/* eslint-disable spaced-comment */ /* eslint-disable eqeqeq */ import React, { useEffect, useRef, useState } from 'react'; import { Card, Form, Input, Button, Select, Table, Space, notification, Modal, Row, Col, Popconfirm, Spin, Tabs, Radio, } from 'antd'; import PageContainer from '@/components/BasePageContainer'; import RadioBox from '@/components/RadioGroup'; import { connect } from 'react-redux'; import { setTableSQLDirName, deleteConnNew, initDBv4new, getInitDBLogNew, getConnRecordNew, getDataBaseConfigNew, saveConnectionNew, getDataBaseList, updateConnDescNew, deleteInitDBLogNew, connectionTest, GetProductList, // 获取产品列表 GetDbProduct, // 获取产品方案配置 InitAddDataBase, // 数据库初始化 InitEditDataBase, // 二次初始化 } from '@/services/database/api'; import CryptoJS from 'crypto-js'; import styles from './InitDataBase.less'; import InitModal from './initModal'; const { TabPane } = Tabs; const { Option } = Select; const formLables = { ip: '服务器名或IP地址', userName: '数据库用户名称', password: '数据库用户密码', dbName: '数据库名称', }; let time = null; const InitDataBase = props => { const [form] = Form.useForm(); const [tableLoading, setTableLoading] = useState(false); // 连接记录 const [dbForm, setDbForm] = useState({ ip: '', dbName: '', password: '', userName: '', inUse: '', }); const [data, setData] = useState([]); // 数据库链接记录 const [upData, setUpData] = useState(1); // 列表刷新标记 const [option, setOption] = useState([]); // 下拉列表数据 const [desc, setDesc] = useState(''); // 修改描述 const [allSqlDir, setAllSqulDir] = useState([]); // 修改产品方案 const [defaultSqlDir, setDefaultSqlDir] = useState(''); // 修改产品方案默认值 const [modalVisible, setModalVisible] = useState({ describeVisible: false, // 描述弹窗 versionVisible: false, // 检查版本弹窗 initVisible: false, // 初始化选择产品弹窗 }); // 修改弹窗 const [initVisible, setInitVisible] = useState(false); // 数据库初始化弹窗 const [initContent, setInitContent] = useState(''); // 数据库初始化内容 const [cardLoading, setCardLoading] = useState(false); // 初始化card Loading const [finish, setFinish] = useState(false); const [initLoading, setInitLoading] = useState(false); const [initList, setInitList] = useState([]); // 数据库初始化产品数据 const [dbExists, setDbExists] = useState(false); // 数据库是否存在 const [visibleModel, setVisibleModel] = useState(false); const [keepDb, setKeepDb] = useState([]); const [keepProduct, setKeepProduct] = useState([]); const scroll = useRef(null); const [keep, setKeep] = useState([]); const [flag, setFlag] = useState(0); const [keepData, setKeepData] = useState({}); const key = CryptoJS.enc.Utf8.parse('1p2a3n4d5a6o7m8s9a10n1e2t3c4o5re'); //十六位十六进制数作为密钥 const iv = CryptoJS.enc.Utf8.parse('1234567890000000'); // 获取数据库配置信息 useEffect(() => { setCardLoading(true); // 数据库连接记录初始化 getConnRecordData(); getDataBaseConfigNew().then(resnew => { setCardLoading(false); let res = resnew.data; if (resnew.code === 0) { const { inUse } = res; let obj = {}; Object.keys(dbForm).forEach(k => { obj[k] = res[k]; }); console.log(obj, 'objohjfaosdjf'); console.log(Decrypt(obj.password)); let aa = Decrypt(obj.password); console.log(Encrypt(aa)); form.setFieldsValue({ ...obj, password: Decrypt(obj.password) }); setDbForm(val => ({ ...val, ...obj, password: Decrypt(obj.password) })); setAllSqulDir(res.allSqlDir); if (res.allSqlDir.some(item => item === inUse)) { setDefaultSqlDir(res.tableSQLDirName); } else { // 默认切换到第一个产品方案 handeleChangeSQLDirName(res.allSqlDir[0]); setDefaultSqlDir(res.allSqlDir[0]); } } }); return () => { if (time) { clearTimeout(time); time = null; } }; }, []); // 解密 const Decrypt = word => { let encryptedHexStr = CryptoJS.enc.Hex.parse(word); let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr); let decrypt = CryptoJS.AES.decrypt(srcs, key, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, }); let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8); return decryptedStr.toString(); }; //加密 const Encrypt = word => { let srcs = CryptoJS.enc.Utf8.parse(word); let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, }); return encrypted.ciphertext.toString().toUpperCase(); }; // 弹出模态框 const handleShowModal = (key, value) => { setModalVisible({ ...modalVisible, [key]: value }); }; // 获取数据库连接记录 const getConnRecordData = () => { setTableLoading(true); getConnRecordNew() .then(resnew => { setTableLoading(false); if (resnew.code === 0) { let res = resnew.data; let arr = res.map((item, index) => { item.key = index; return item; }); setData(arr); } }) .catch(err => { setTableLoading(false); console.error(err); }); }; // 获取日志 const doInitLog = () => { setInitLoading(true); getInitDBLogNew() .then(res => { if (res.code === 0) { if (res.data.content) { setInitLoading(false); let arr = []; arr.push( res.data.content.split(/(\r\n)|(\n)/).map((item, index) => ( // eslint-disable-next-line react/no-danger <p key={index} dangerouslySetInnerHTML={{ __html: item }} /> )), ); console.log(arr); setInitContent(arr); scroll.current.scrollTop = scroll.current.scrollHeight; } if (!res.data.finish) { time = setTimeout(() => { doInitLog(); }, 600); } else { setInitLoading(false); if (time) { clearTimeout(time); time = null; } } } }) .catch(err => { setFinish(true); }); }; // 数据库初始化 const initClick = () => { setInitContent(''); setCardLoading(true); setInitVisible(true); let obj = form.getFieldsValue(); doInitLog(); initDBv4new({ ...obj, }) .then(res => { setCardLoading(false); if (res.code == 0) { console.log(res); } else { notification.error({ message: '提示', duration: 15, description: res.msg || '初始化失败', }); } }) .catch(err => { setCardLoading(false); console.log(err); }); }; const onValuesChange = (value, b) => { form.setFieldsValue(value); }; const onChange = value => { const { length } = value; form.setFieldsValue({ dbName: value[length - 1], }); }; // 保存连接 const onFinish = values => { setCardLoading(true); const obj = values; saveConnectionNew({ ip: obj.ip, dbName: obj.dbName, userName: obj.userName, password: Encrypt(obj.password), }) .then(resnew => { setCardLoading(false); if (resnew.code === 0) { setFlag(flag + 1); setKeepData({ ip: obj.ip, dbName: obj.dbName, userName: obj.userName, password: Encrypt(obj.password), }); // setUpData(upData + 1); getConnRecordData(); notification.success({ message: '提示', duration: 3, description: '保存成功', }); } else { notification.error({ message: '提示', duration: 15, description: resnew.msg, }); } }) .catch(err => { setCardLoading(false); console.log(err); }); }; // 测试连接 const onCheck = e => { console.log(dbForm); setCardLoading(true); const obj = form.getFieldsValue(); connectionTest({ // _version: 9999, // _dc: new Date().getTime(), ip: obj.ip, dbName: obj.dbName, userName: obj.userName, password: Encrypt(obj.password), // Type:"SQLServer", // name:obj.dbName, }) .then(res => { setCardLoading(false); if (res.code == 0 && res.data == true) { notification.success({ message: '提示', duration: 3, description: '连接成功', }); } else { notification.error({ message: '提示', duration: 15, description: res.msg, }); } }) .catch(err => { setCardLoading(false); console.log(err); }); }; // 获取数据库列表 const selectFocus = e => { //setOption([]); let params = form.getFieldsValue(); getDataBaseList({ // _version: 9999, // _dc: Date.now(), userName: params.userName || '', password: Encrypt(params.password) || '', ip: params.ip || '', }) .then(res => { if (res.code == 0) { console.log(res.data.root); setOption(res.data.root); } else { notification.error({ message: '提示', duration: 15, description: res.msg, }); setOption([]); } }) .catch(err => { console.error(err); }); }; // 点击表格回显到表单 const tableClick = item => { let obj = { ...dbForm }; Object.keys(obj).forEach(k => { obj[k] = item[k]; }); form.setFieldsValue({ ...obj, password: Decrypt(obj.password) }); }; // 产品方案选择框回调 const handleSelect = value => { handeleChangeSQLDirName(value); }; const handeleChangeSQLDirName = val => { setTableSQLDirName({ dirName: val, }) .then(res => { if (res.code === 0) { notification.success({ message: '提示', duration: 3, description: `已切换初始化脚本为:${val}`, }); } else { notification.error({ message: '提示', duration: 15, description: res.message, }); } }) .catch(err => { console.error(err); }); }; // 展示修改描述 const changeDesc = val => { setDesc(val); handleShowModal('describeVisible', true); }; const descChange = e => { const { value } = e.target; setDesc(value); }; // 关闭弹窗 const handleClick = () => { setInitVisible(false); setInitContent(''); setFinish(false); // deleteInitDBLog({ // _version: 9999, // _dc: Date.now(), // }); deleteInitDBLogNew(); }; // 弹窗确认回调 const modalOkCallback = () => { const obj = form.getFieldsValue(); // 更新描述 updateConnDescNew({ ip: obj.ip, dbName: obj.dbName, userName: obj.userName, password: Encrypt(obj.password), desc, }) .then(res => { handleShowModal('describeVisible', false); // setUpData(upData + 1); getConnRecordData(); }) .catch(err => { console.error(err); handleShowModal('describeVisible', false); }); }; // 删除数据库连接记录 const delConfirm = value => { const { key = '' } = value; setTableLoading(true); deleteConnNew({ rowIndex: key, }) .then(res => { setTableLoading(false); if (res.code === 0) { // setUpData(upData + 1); getConnRecordData(); notification.success({ message: '提示', duration: 3, description: '操作成功', }); } else { notification.error({ message: '提示', duration: 15, description: res.msg, }); } }) .catch(err => { setTableLoading(false); console.error(err); }); }; const GetDb = () => { let obj = form.getFieldsValue(); GetDbProduct({ ...obj, password: Encrypt(obj.password) }).then(res => { if (res.code === 0) { console.log(res.data); if (res.data.Product) { console.log(res.data.Product); let aa = []; res.data.Product.map(i => { aa.push(i.name); }); console.log(aa); setKeep(res.data.IsAuthorize); setKeepProduct(aa); } setDbExists(res.data.DBExists); setKeepDb(res.data); if (!res.data.DBExists) { setVisibleModel(true); } else if (res.data.DBExists && res.data.Product.length > 0) { setVisibleModel(true); } else { notification.warning({ message: '提示', duration: 15, description: '当前数据库不可初始化', }); } } else { notification.warning({ message: '提示', duration: 15, description: res.msg, }); } }); }; // 获取数据库初始化回显列表 const getInitList = () => { setInitList([]); handleShowModal('initVisible', true); setInitLoading(true); let obj = form.getFieldsValue(); let req1 = GetProductList(); let req2 = GetDbProduct({ ...obj, password: Encrypt(obj.password) }); Promise.all([req1, req2]) .then(res => { if (res[1].code !== 0 || res[0].code !== 0) { setInitLoading(false); notification.error({ message: '提示', duration: 3, description: '连接失败', }); return; } setDbExists(res[1].data.DBExists); let fileList = res[0].data ? res[0].data : []; let dataList = res[1].data.Product ? res[1].data.Product : []; // 没有库或者dataList为[]直接用fileList作为回显 if (!res[1].data.DBExists || dataList.length === 0) { setInitList(fileList); setInitLoading(false); return; } let mapList = new Map(); // 通过map给数据库中中的节点中的key的值当作key,checkVersion当作value进行存储 dataList.forEach(element => { // 存入一级目录是否有选中项的key mapList.set(element.key, element.check); element.modularSolutions.forEach(item => { // 存入二级目录对应的选中的checkVersion跟check mapList.set(item.key, { checkVersion: item.checkVersion, check: item.check, }); item.functionrSolutions.forEach(val => { // 存入三级目录对应的选中的checkVersion跟check mapList.set(val.key, val.isCheck); }); }); }); console.log(mapList, 'mapList'); fileList.forEach(element => { // 根据key来获取第一级目录tab的check let tabKey = mapList.get(element.key); element.check = tabKey === undefined ? null : tabKey; element.modularSolutions.forEach(item => { let mapCheckVersion = mapList.get(item.key); if (mapCheckVersion === undefined) { mapCheckVersion = { checkVersion: null, check: null }; } // 根据key值去匹配对应的checkVersion item.checkVersion = mapCheckVersion.checkVersion === undefined ? null : mapCheckVersion.checkVersion; // 根据key值去匹配对应的二级目录的check item.check = mapCheckVersion.check === undefined ? null : mapCheckVersion.check; if (item.check) { item.hasCheck = true; } item.functionrSolutions.forEach(val => { // 根据三级目录对应的选中key匹配isCheck let isCheck = mapList.get(val.key); val.isCheck = isCheck === undefined ? null : isCheck; // 版本号低于当前版本号禁止选用 if (item.checkVersion && val.version < item.checkVersion) { val.disabled = true; } else { val.disabled = false; } }); }); }); setInitList(fileList); setInitLoading(false); }) .catch(err => { console.log(err, 'err'); notification.error({ message: '提示', duration: 3, description: '连接失败', }); setInitLoading(false); }); }; // 初始化产品列表渲染 const renderInitListItem = (tabItem, index) => ( <TabPane tab={tabItem.productName} key={index}> <div className={styles.tabContainer}> {tabItem.modularSolutions.map((item, num) => ( <React.Fragment key={item.key}> {item.functionrSolutions.length > 0 ? ( <RadioBox radioTitle={item.modularName} radioOptions={item.functionrSolutions} currentVal={item.checkVersion} currentIndex={{ tabIndex: index, radioIndex: num }} callBack={radioChange} /> ) : null} </React.Fragment> ))} </div> </TabPane> ); // 单选选后的回调,改变数据 const radioChange = (index, value) => { setInitList(val => { const list = JSON.parse(JSON.stringify(val)); const secondList = list[index.tabIndex].modularSolutions[index.radioIndex]; // 取消功能 一开始未选中的才能取消 if (value === secondList.checkVersion && !secondList.hasCheck) { secondList.checkVersion = null; value = null; secondList.check = false; } else { // 修改选中的checkVersion值 secondList.checkVersion = value; // 修改二级菜单的check字段 secondList.check = true; } // 修改一级菜单的check字段 list[index.tabIndex].check = !list[index.tabIndex].modularSolutions.every( version => version.checkVersion === null, ); // 修改单选isCheck字段 secondList.functionrSolutions.forEach(item => { if (item.version === value) { item.isCheck = true; } else { item.isCheck = false; } }); return list; }); }; const onOK = (arr, code) => { initDatabasePro(arr, code); }; // 数据库初始化 const initDatabasePro = (e, j) => { let productSetting = e; let obj = form.getFieldsValue(); // 数据库存在调用编辑接口否则调用新增接口 setInitLoading(true); setVisibleModel(false); handleShowModal('initVisible', false); setInitVisible(true); doInitLog(); if (dbExists) { InitEditDataBase({ ...obj, productSetting, license: j, password: Encrypt(obj.password), }).then(res => { setInitLoading(false); if (res.code === 0) { notification.success({ message: '提示', duration: 3, description: '数据库初始化成功', }); } else { notification.error({ message: '提示', duration: 5, description: res.msg, }); } }); return; } InitAddDataBase({ ...obj, productSetting, license: j }).then(res => { setInitLoading(false); if (res.code === 0) { notification.success({ message: '提示', duration: 3, description: '数据库初始化成功', }); } else { notification.error({ message: '提示', duration: 5, description: res.msg, }); } }); }; const columns = [ { title: '服务器名或IP地址', dataIndex: 'ip', key: 'ip', width: 180, ellipsis: true, }, { title: '数据库名称', dataIndex: 'dbName', key: 'dbName', width: 180, ellipsis: true, }, { title: '数据库用户名称', dataIndex: 'userName', key: 'userName', width: 180, ellipsis: true, }, { title: '保存时间', dataIndex: 'saveTime', key: 'saveTime', width: 180, ellipsis: true, }, { title: '描述', dataIndex: 'desc', key: 'desc', ellipsis: true, }, { title: '操作', dataIndex: 'action', key: 'action', width: 250, ellipsis: true, render: (text, record) => ( <Space> <Button type="primary" size="small" onClick={() => { changeDesc(record.desc); }} > 修改描述 </Button> {/* <div onClick={e => e.stopPropagation()}> <Popconfirm title="是否删除该连接的历史记录?" okText="确认" cancelText="取消" onConfirm={() => { delConfirm(record); }} > <Button size="small" danger> 删除 </Button> </Popconfirm> </div> */} </Space> ), }, ]; const flagChange = () => { const obj = form.getFieldsValue(); console.log(keepData); console.log(obj); if ( keepData.ip == obj.ip && keepData.dbName == obj.dbName && keepData.userName == obj.userName && keepData.password == obj.password ) { GetDb(); deleteInitDBLogNew(); } else { notification.warning({ message: '提示', duration: 15, description: '请先保存连接', }); } }; return ( <> <PageContainer className={styles.InitDataBaseContainer}> <Card> <Spin tip="loading..." spinning={cardLoading}> {/* <div className={styles.tableTitle}>数据库初始化</div> */} <Form className={styles.mgTop20} layout="horizontal" labelAlign="left" labelCol={{ span: 3 }} form={form} onFinish={onFinish} onValuesChange={onValuesChange} > <Form.Item label={`${formLables.ip}:`} name="ip" rules={[ { validator: (rule, value) => { if (form.getFieldValue().ip == '') { return Promise.reject('ip必填'); } return Promise.resolve(); }, }, ]} > <Input placeholder="请输入服务器名或IP地址" /> </Form.Item> <Form.Item label={`${formLables.userName}:`} name="userName" rules={[ { validator: (rule, value) => { if (form.getFieldValue().userName == '') { return Promise.reject('用户名称必填'); } return Promise.resolve(); }, }, ]} > <Input placeholder="请输入用户名称" /> </Form.Item> <Form.Item label={`${formLables.password}:`} name="password" rules={[ { validator: (rule, value) => { console.log(form.getFieldValue().password); if (form.getFieldValue().password == '') { return Promise.reject('用户密码必填'); } return Promise.resolve(); }, }, ]} > <Input placeholder="请输入用户密码" type="password" /> </Form.Item> <Form.Item label={`${formLables.dbName}:`} name="dbName" rules={[ { validator: (rule, value) => { console.log(form.getFieldValue().dbName); if ( form.getFieldValue().dbName == '' || form.getFieldValue().dbName == undefined ) { return Promise.reject('数据库名称必填'); } return Promise.resolve(); }, }, ]} > <Select showSearch mode="tags" placeholder="请选择数据库" optionFilterProp="children" onFocus={() => { selectFocus(); }} onChange={e => { onChange(e); }} // eslint-disable-next-line no-shadow filterOption={(input, option) => { console.log(option); return ( option.children && option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ); }} > {option && option.length > 0 && option.map((item, index) => ( <Option value={item.value} key={item.value + index}> {item.value} </Option> ))} </Select> </Form.Item> <Form.Item wrapperCol={{ offset: 3 }}> <div className={styles.tCenter}> <Space size="large" className={styles.btnBox}> <Space> <Button onClick={onCheck}>测试连接</Button> <Button type="primary" htmlType="submit" loading={tableLoading}> 保存连接 </Button> </Space> <Space> {/* <Button type="primary" // onClick={() => { // getInitList(); // deleteInitDBLogNew(); // }} onClick={() => { flagChange(); }} > 数据库初始化 </Button> */} </Space> </Space> </div> </Form.Item> </Form> </Spin> </Card> <Card className={styles.mgTop20}> <div className={styles.recordBox}> <div className={styles.tableTitle}>近期保存的数据库连接</div> <Table style={{ marginTop: '20px', marginBottom: '20px' }} scroll={{ x: 'max-content', y: 'calc(100vh - 550px)' }} columns={columns} dataSource={data} pagination={false} bordered loading={tableLoading} size="small" onRow={record => ({ onClick: () => { tableClick(record); setFlag(0); }, // 点击行 })} /> </div> </Card> <Modal title="初始化数据库" visible={initVisible} onCancel={() => { setInitVisible(false); setInitContent(''); // deleteInitDBLog({ // _version: 9999, // _dc: Date.now(), // }); deleteInitDBLogNew(); }} width={800} maskClosable={false} bodyStyle={{ height: '500px', // overflowY: 'auto', }} footer={[ <Button onClick={() => { handleClick(); }} key="back" type="primary" > 关闭窗口 </Button>, ]} > <div ref={scroll} style={{ maxHeight: '470px', overflowY: 'auto', marginRight: ' -24px', }} > {initContent || ( <Spin spinning={initLoading} tip="loading..." style={{ width: '100%', marginTop: '40px' }} /> )} </div> </Modal> <Modal title="修改链接描述" visible={modalVisible.describeVisible} onOk={() => modalOkCallback()} onCancel={() => handleShowModal('describeVisible', false)} width="800px" bodyStyle={{ minHeight: '100px', }} cancelText="取消" okText="确认" destroyOnClose > <Row> <Col span={2} className={styles.decsBox}> 描述: </Col> <Col span={22}> <Input placeholder="请输入描述" allowClear defaultValue={desc} onChange={value => { descChange(value); }} /> </Col> </Row> </Modal> <InitModal visible={visibleModel} onCancel={() => setVisibleModel(false)} keepDb={keepDb} callBackSubmit={onOK} keepProduct={keepProduct} keep={keep} /> {/* 初始化选择产品弹窗 */} <Modal title="初始化" maskClosable={false} visible={modalVisible.initVisible} onCancel={() => handleShowModal('initVisible', false)} footer={[ <Button key="back" onClick={() => handleShowModal('initVisible', false)}> 取消 </Button>, <Popconfirm placement="topLeft" title="是否确认初始化" onConfirm={initDatabasePro} okText="确认" key="submit" cancelText="取消" > <Button type="primary" loading={initLoading}> 确认 </Button> </Popconfirm>, ]} width={900} > <Spin spinning={initLoading}> <div className={styles.cardContainer}> <Tabs defaultActiveKey="1" type="card" tabBarGutter={-1}> {initList.map((item, index) => renderInitListItem(item, index))} </Tabs> </div> </Spin> </Modal> </PageContainer> </> ); }; export default connect()(InitDataBase);