diff --git a/web/config/router.config.js b/web/config/router.config.js
index d745e14a..49056d30 100644
--- a/web/config/router.config.js
+++ b/web/config/router.config.js
@@ -26,13 +26,13 @@ export default [
component: './Dashboard/Analysis',
routes: [
{
- path: '/list/table-list',
+ path: '/platform/gateway',
name: 'gateway',
- component: './List/TableList',
+ component: './Dashboard/Analysis',
}, {
- path: '/list/table-list',
+ path: '/platform/cluster',
name: 'cluster',
- component: './List/TableList',
+ component: './Dashboard/Monitor',
}, {
path: '/list/table-list',
name: 'tasks',
@@ -95,28 +95,27 @@ export default [
path: '/search',
name: 'search',
icon: 'search',
- component: './Logs/Overview',
routes: [
{
- path: '/list/table-list',
+ path: '/search/template',
name: 'template',
- component: './List/TableList',
+ component: './SearchManage/SearchTemplate',
}, {
- path: '/list/table-list',
+ path: '/search/alias',
name: 'alias',
- component: './List/TableList',
+ component: './SearchManage/AliasManage',
}, {
- path: '/list/table-list',
+ path: '/search/dict',
name: 'dict',
- component: './List/TableList',
+ component: './SearchManage/DictManage',
}, {
- path: '/list/table-list',
+ path: '/search/analyzer',
name: 'analyzer',
- component: './List/TableList',
+ component: './SearchManage/AnalyzerManage',
}, {
- path: '/list/table-list',
+ path: '/search/nlp',
name: 'nlp',
- component: './List/TableList',
+ component: './SearchManage/NLPManage',
},
]
},
diff --git a/web/docker/entrypoint-build.sh b/web/docker/entrypoint-build.sh
old mode 100644
new mode 100755
diff --git a/web/docker/entrypoint-dev.sh b/web/docker/entrypoint-dev.sh
old mode 100644
new mode 100755
diff --git a/web/docker/entrypoint.sh b/web/docker/entrypoint.sh
old mode 100644
new mode 100755
diff --git a/web/src/pages/SearchManage/AliasManage.js b/web/src/pages/SearchManage/AliasManage.js
new file mode 100644
index 00000000..3367d590
--- /dev/null
+++ b/web/src/pages/SearchManage/AliasManage.js
@@ -0,0 +1,624 @@
+import React, { PureComponent, Fragment } from 'react';
+import { connect } from 'dva';
+import moment from 'moment';
+import {
+ Row,
+ Col,
+ Card,
+ Form,
+ Input,
+ Select,
+ Icon,
+ Button,
+ Dropdown,
+ Menu,
+ InputNumber,
+ DatePicker,
+ Modal,
+ message,
+ Badge,
+ Divider,
+ Steps,
+ Radio,
+} from 'antd';
+import StandardTable from '@/components/StandardTable';
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+
+import styles from './AliasManage.less';
+
+const FormItem = Form.Item;
+const { Step } = Steps;
+const { TextArea } = Input;
+const { Option } = Select;
+const RadioGroup = Radio.Group;
+const getValue = obj =>
+ Object.keys(obj)
+ .map(key => obj[key])
+ .join(',');
+const statusMap = ['default', 'processing', 'success', 'error'];
+const status = ['关闭', '运行中', '已上线', '异常'];
+
+class UpdateForm extends PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ formVals: {
+ name: props.values.name,
+ desc: props.values.desc,
+ key: props.values.key,
+ target: '0',
+ template: '0',
+ type: '1',
+ time: '',
+ frequency: 'month',
+ },
+ currentStep: 0,
+ };
+
+ this.formLayout = {
+ labelCol: { span: 7 },
+ wrapperCol: { span: 13 },
+ };
+ }
+
+ handleNext = currentStep => {
+ const { form, handleUpdate } = this.props;
+ const { formVals: oldValue } = this.state;
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ const formVals = { ...oldValue, ...fieldsValue };
+ this.setState(
+ {
+ formVals,
+ },
+ () => {
+ if (currentStep < 2) {
+ this.forward();
+ } else {
+ handleUpdate(formVals);
+ }
+ }
+ );
+ });
+ };
+
+ backward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep - 1,
+ });
+ };
+
+ forward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep + 1,
+ });
+ };
+
+ renderContent = (currentStep, formVals) => {
+ const { form } = this.props;
+ if (currentStep === 1) {
+ return [
+
+ {form.getFieldDecorator('target', {
+ initialValue: formVals.target,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('template', {
+ initialValue: formVals.template,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('type', {
+ initialValue: formVals.type,
+ })(
+
+ 强
+ 弱
+
+ )}
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+
+ {form.getFieldDecorator('time', {
+ rules: [{ required: true, message: '请选择开始时间!' }],
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('frequency', {
+ initialValue: formVals.frequency,
+ })(
+
+ )}
+ ,
+ ];
+ }
+ return [
+
+ {form.getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入索引名称!' }],
+ initialValue: formVals.name,
+ })()}
+ ,
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的索引描述!', min: 5 }],
+ initialValue: formVals.desc,
+ })()}
+ ,
+ ];
+ };
+
+ renderFooter = currentStep => {
+ const { handleUpdateModalVisible } = this.props;
+ if (currentStep === 1) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ return [
+ ,
+ ,
+ ];
+ };
+
+ render() {
+ const { updateModalVisible, handleUpdateModalVisible } = this.props;
+ const { currentStep, formVals } = this.state;
+
+ return (
+ handleUpdateModalVisible()}
+ >
+
+
+
+
+
+ {this.renderContent(currentStep, formVals)}
+
+ );
+ }
+}
+
+/* eslint react/no-multi-comp:0 */
+@connect(({ rule, loading }) => ({
+ rule,
+ loading: loading.models.rule,
+}))
+@Form.create()
+class AliasManage extends PureComponent {
+ state = {
+ modalVisible: false,
+ updateModalVisible: false,
+ expandForm: false,
+ selectedRows: [],
+ formValues: {},
+ stepFormValues: {},
+ };
+
+ columns = [
+ {
+ title: '索引名称',
+ dataIndex: 'name',
+ },
+ {
+ title: '别名',
+ dataIndex: 'desc',
+ },
+ {
+ title: '索引调用次数',
+ dataIndex: 'callNo',
+ sorter: true,
+ align: 'right',
+ render: val => `${val} 万`,
+ // mark to display a total number
+ needTotal: true,
+ },
+ {
+ title: '索引状态',
+ dataIndex: 'status',
+ filters: [
+ {
+ text: status[0],
+ value: 0,
+ },
+ {
+ text: status[1],
+ value: 1,
+ },
+ {
+ text: status[2],
+ value: 2,
+ },
+ {
+ text: status[3],
+ value: 3,
+ },
+ ],
+ render(val) {
+ return ;
+ },
+ },
+ {
+ title: '最后更新时间',
+ dataIndex: 'updatedAt',
+ sorter: true,
+ render: val => {moment(val).format('YYYY-MM-DD HH:mm:ss')},
+ },
+ {
+ title: '操作',
+ render: (text, record) => (
+
+ this.handleUpdateModalVisible(true, record)}>配置别名
+
+ 订阅警报
+
+ ),
+ },
+ ];
+
+ componentDidMount() {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/fetch',
+ });
+ }
+
+ handleStandardTableChange = (pagination, filtersArg, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const filters = Object.keys(filtersArg).reduce((obj, key) => {
+ const newObj = { ...obj };
+ newObj[key] = getValue(filtersArg[key]);
+ return newObj;
+ }, {});
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues,
+ ...filters,
+ };
+ if (sorter.field) {
+ params.sorter = `${sorter.field}_${sorter.order}`;
+ }
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: params,
+ });
+ };
+
+ handleFormReset = () => {
+ const { form, dispatch } = this.props;
+ form.resetFields();
+ this.setState({
+ formValues: {},
+ });
+ dispatch({
+ type: 'rule/fetch',
+ payload: {},
+ });
+ };
+
+ toggleForm = () => {
+ const { expandForm } = this.state;
+ this.setState({
+ expandForm: !expandForm,
+ });
+ };
+
+ handleMenuClick = e => {
+ const { dispatch } = this.props;
+ const { selectedRows } = this.state;
+
+ if (!selectedRows) return;
+ switch (e.key) {
+ case 'remove':
+ dispatch({
+ type: 'rule/remove',
+ payload: {
+ key: selectedRows.map(row => row.key),
+ },
+ callback: () => {
+ this.setState({
+ selectedRows: [],
+ });
+ },
+ });
+ break;
+ default:
+ break;
+ }
+ };
+
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows,
+ });
+ };
+
+ handleSearch = e => {
+ e.preventDefault();
+
+ const { dispatch, form } = this.props;
+
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+
+ const values = {
+ ...fieldsValue,
+ updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
+ };
+
+ this.setState({
+ formValues: values,
+ });
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: values,
+ });
+ });
+ };
+
+ handleModalVisible = flag => {
+ this.setState({
+ modalVisible: !!flag,
+ });
+ };
+
+ handleUpdateModalVisible = (flag, record) => {
+ this.setState({
+ updateModalVisible: !!flag,
+ stepFormValues: record || {},
+ });
+ };
+
+ handleAdd = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/add',
+ payload: {
+ desc: fields.desc,
+ },
+ });
+
+ message.success('添加成功');
+ this.handleModalVisible();
+ };
+
+ handleUpdate = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/update',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ key: fields.key,
+ },
+ });
+
+ message.success('配置成功');
+ this.handleUpdateModalVisible();
+ };
+
+ renderSimpleForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderAdvancedForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderForm() {
+ const { expandForm } = this.state;
+ return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
+ }
+
+ render() {
+ const {
+ rule: { data },
+ loading,
+ } = this.props;
+ const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
+ const menu = (
+
+ );
+
+ const parentMethods = {
+ handleAdd: this.handleAdd,
+ handleModalVisible: this.handleModalVisible,
+ };
+ const updateMethods = {
+ handleUpdateModalVisible: this.handleUpdateModalVisible,
+ handleUpdate: this.handleUpdate,
+ };
+ return (
+
+
+
+
{this.renderForm()}
+
+ {selectedRows.length > 0 && (
+
+
+
+
+
+
+ )}
+
+
+
+
+ {stepFormValues && Object.keys(stepFormValues).length ? (
+
+ ) : null}
+
+ );
+ }
+}
+
+export default AliasManage;
diff --git a/web/src/pages/SearchManage/AliasManage.less b/web/src/pages/SearchManage/AliasManage.less
new file mode 100644
index 00000000..792757df
--- /dev/null
+++ b/web/src/pages/SearchManage/AliasManage.less
@@ -0,0 +1,49 @@
+@import '~antd/lib/style/themes/default.less';
+@import '~@/utils/utils.less';
+
+.tableList {
+ .tableListOperator {
+ margin-bottom: 16px;
+ button {
+ margin-right: 8px;
+ }
+ }
+}
+
+.tableListForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 24px;
+ margin-right: 0;
+ display: flex;
+ > .ant-form-item-label {
+ width: auto;
+ line-height: 32px;
+ padding-right: 8px;
+ }
+ .ant-form-item-control {
+ line-height: 32px;
+ }
+ }
+ .ant-form-item-control-wrapper {
+ flex: 1;
+ }
+ }
+ .submitButtons {
+ display: block;
+ white-space: nowrap;
+ margin-bottom: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-lg) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 8px;
+ }
+}
diff --git a/web/src/pages/SearchManage/AnalyzerManage.js b/web/src/pages/SearchManage/AnalyzerManage.js
new file mode 100644
index 00000000..166a0e90
--- /dev/null
+++ b/web/src/pages/SearchManage/AnalyzerManage.js
@@ -0,0 +1,675 @@
+import React, { PureComponent, Fragment } from 'react';
+import { connect } from 'dva';
+import moment from 'moment';
+import {
+ Row,
+ Col,
+ Card,
+ Form,
+ Input,
+ Select,
+ Icon,
+ Button,
+ Dropdown,
+ Menu,
+ InputNumber,
+ DatePicker,
+ Modal,
+ message,
+ Badge,
+ Divider,
+ Steps,
+ Radio,
+} from 'antd';
+import StandardTable from '@/components/StandardTable';
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+
+import styles from './AnalyzerManage.less';
+
+const FormItem = Form.Item;
+const { Step } = Steps;
+const { TextArea } = Input;
+const { Option } = Select;
+const RadioGroup = Radio.Group;
+const getValue = obj =>
+ Object.keys(obj)
+ .map(key => obj[key])
+ .join(',');
+const statusMap = ['default', 'processing', 'success', 'error'];
+const status = ['关闭', '运行中', '已上线', '异常'];
+
+const CreateForm = Form.create()(props => {
+ const { modalVisible, form, handleAdd, handleModalVisible } = props;
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleAdd(fieldsValue);
+ });
+ };
+ return (
+ handleModalVisible()}
+ >
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ })()}
+
+
+ );
+});
+
+@Form.create()
+class UpdateForm extends PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ formVals: {
+ name: props.values.name,
+ desc: props.values.desc,
+ key: props.values.key,
+ target: '0',
+ template: '0',
+ type: '1',
+ time: '',
+ frequency: 'month',
+ },
+ currentStep: 0,
+ };
+
+ this.formLayout = {
+ labelCol: { span: 7 },
+ wrapperCol: { span: 13 },
+ };
+ }
+
+ handleNext = currentStep => {
+ const { form, handleUpdate } = this.props;
+ const { formVals: oldValue } = this.state;
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ const formVals = { ...oldValue, ...fieldsValue };
+ this.setState(
+ {
+ formVals,
+ },
+ () => {
+ if (currentStep < 2) {
+ this.forward();
+ } else {
+ handleUpdate(formVals);
+ }
+ }
+ );
+ });
+ };
+
+ backward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep - 1,
+ });
+ };
+
+ forward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep + 1,
+ });
+ };
+
+ renderContent = (currentStep, formVals) => {
+ const { form } = this.props;
+ if (currentStep === 1) {
+ return [
+
+ {form.getFieldDecorator('target', {
+ initialValue: formVals.target,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('template', {
+ initialValue: formVals.template,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('type', {
+ initialValue: formVals.type,
+ })(
+
+ 强
+ 弱
+
+ )}
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+
+ {form.getFieldDecorator('time', {
+ rules: [{ required: true, message: '请选择开始时间!' }],
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('frequency', {
+ initialValue: formVals.frequency,
+ })(
+
+ )}
+ ,
+ ];
+ }
+ return [
+
+ {form.getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入规则名称!' }],
+ initialValue: formVals.name,
+ })()}
+ ,
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ initialValue: formVals.desc,
+ })()}
+ ,
+ ];
+ };
+
+ renderFooter = currentStep => {
+ const { handleUpdateModalVisible } = this.props;
+ if (currentStep === 1) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ return [
+ ,
+ ,
+ ];
+ };
+
+ render() {
+ const { updateModalVisible, handleUpdateModalVisible } = this.props;
+ const { currentStep, formVals } = this.state;
+
+ return (
+ handleUpdateModalVisible()}
+ >
+
+
+
+
+
+ {this.renderContent(currentStep, formVals)}
+
+ );
+ }
+}
+
+/* eslint react/no-multi-comp:0 */
+@connect(({ rule, loading }) => ({
+ rule,
+ loading: loading.models.rule,
+}))
+@Form.create()
+class AnalyzerManage extends PureComponent {
+ state = {
+ modalVisible: false,
+ updateModalVisible: false,
+ expandForm: false,
+ selectedRows: [],
+ formValues: {},
+ stepFormValues: {},
+ };
+
+ columns = [
+ {
+ title: '规则名称',
+ dataIndex: 'name',
+ },
+ {
+ title: '描述',
+ dataIndex: 'desc',
+ },
+ {
+ title: '服务调用次数',
+ dataIndex: 'callNo',
+ sorter: true,
+ align: 'right',
+ render: val => `${val} 万`,
+ // mark to display a total number
+ needTotal: true,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ filters: [
+ {
+ text: status[0],
+ value: 0,
+ },
+ {
+ text: status[1],
+ value: 1,
+ },
+ {
+ text: status[2],
+ value: 2,
+ },
+ {
+ text: status[3],
+ value: 3,
+ },
+ ],
+ render(val) {
+ return ;
+ },
+ },
+ {
+ title: '上次调度时间',
+ dataIndex: 'updatedAt',
+ sorter: true,
+ render: val => {moment(val).format('YYYY-MM-DD HH:mm:ss')},
+ },
+ {
+ title: '操作',
+ render: (text, record) => (
+
+ this.handleUpdateModalVisible(true, record)}>配置
+
+ 订阅警报
+
+ ),
+ },
+ ];
+
+ componentDidMount() {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/fetch',
+ });
+ }
+
+ handleStandardTableChange = (pagination, filtersArg, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const filters = Object.keys(filtersArg).reduce((obj, key) => {
+ const newObj = { ...obj };
+ newObj[key] = getValue(filtersArg[key]);
+ return newObj;
+ }, {});
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues,
+ ...filters,
+ };
+ if (sorter.field) {
+ params.sorter = `${sorter.field}_${sorter.order}`;
+ }
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: params,
+ });
+ };
+
+ handleFormReset = () => {
+ const { form, dispatch } = this.props;
+ form.resetFields();
+ this.setState({
+ formValues: {},
+ });
+ dispatch({
+ type: 'rule/fetch',
+ payload: {},
+ });
+ };
+
+ toggleForm = () => {
+ const { expandForm } = this.state;
+ this.setState({
+ expandForm: !expandForm,
+ });
+ };
+
+ handleMenuClick = e => {
+ const { dispatch } = this.props;
+ const { selectedRows } = this.state;
+
+ if (!selectedRows) return;
+ switch (e.key) {
+ case 'remove':
+ dispatch({
+ type: 'rule/remove',
+ payload: {
+ key: selectedRows.map(row => row.key),
+ },
+ callback: () => {
+ this.setState({
+ selectedRows: [],
+ });
+ },
+ });
+ break;
+ default:
+ break;
+ }
+ };
+
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows,
+ });
+ };
+
+ handleSearch = e => {
+ e.preventDefault();
+
+ const { dispatch, form } = this.props;
+
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+
+ const values = {
+ ...fieldsValue,
+ updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
+ };
+
+ this.setState({
+ formValues: values,
+ });
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: values,
+ });
+ });
+ };
+
+ handleModalVisible = flag => {
+ this.setState({
+ modalVisible: !!flag,
+ });
+ };
+
+ handleUpdateModalVisible = (flag, record) => {
+ this.setState({
+ updateModalVisible: !!flag,
+ stepFormValues: record || {},
+ });
+ };
+
+ handleAdd = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/add',
+ payload: {
+ desc: fields.desc,
+ },
+ });
+
+ message.success('添加成功');
+ this.handleModalVisible();
+ };
+
+ handleUpdate = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/update',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ key: fields.key,
+ },
+ });
+
+ message.success('配置成功');
+ this.handleUpdateModalVisible();
+ };
+
+ renderSimpleForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderAdvancedForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderForm() {
+ const { expandForm } = this.state;
+ return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
+ }
+
+ render() {
+ const {
+ rule: { data },
+ loading,
+ } = this.props;
+ const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
+ const menu = (
+
+ );
+
+ const parentMethods = {
+ handleAdd: this.handleAdd,
+ handleModalVisible: this.handleModalVisible,
+ };
+ const updateMethods = {
+ handleUpdateModalVisible: this.handleUpdateModalVisible,
+ handleUpdate: this.handleUpdate,
+ };
+ return (
+
+
+
+
{this.renderForm()}
+
+
+ {selectedRows.length > 0 && (
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ {stepFormValues && Object.keys(stepFormValues).length ? (
+
+ ) : null}
+
+ );
+ }
+}
+
+export default AnalyzerManage;
diff --git a/web/src/pages/SearchManage/AnalyzerManage.less b/web/src/pages/SearchManage/AnalyzerManage.less
new file mode 100644
index 00000000..792757df
--- /dev/null
+++ b/web/src/pages/SearchManage/AnalyzerManage.less
@@ -0,0 +1,49 @@
+@import '~antd/lib/style/themes/default.less';
+@import '~@/utils/utils.less';
+
+.tableList {
+ .tableListOperator {
+ margin-bottom: 16px;
+ button {
+ margin-right: 8px;
+ }
+ }
+}
+
+.tableListForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 24px;
+ margin-right: 0;
+ display: flex;
+ > .ant-form-item-label {
+ width: auto;
+ line-height: 32px;
+ padding-right: 8px;
+ }
+ .ant-form-item-control {
+ line-height: 32px;
+ }
+ }
+ .ant-form-item-control-wrapper {
+ flex: 1;
+ }
+ }
+ .submitButtons {
+ display: block;
+ white-space: nowrap;
+ margin-bottom: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-lg) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 8px;
+ }
+}
diff --git a/web/src/pages/SearchManage/DictManage.js b/web/src/pages/SearchManage/DictManage.js
new file mode 100644
index 00000000..1f0fe0d8
--- /dev/null
+++ b/web/src/pages/SearchManage/DictManage.js
@@ -0,0 +1,675 @@
+import React, { PureComponent, Fragment } from 'react';
+import { connect } from 'dva';
+import moment from 'moment';
+import {
+ Row,
+ Col,
+ Card,
+ Form,
+ Input,
+ Select,
+ Icon,
+ Button,
+ Dropdown,
+ Menu,
+ InputNumber,
+ DatePicker,
+ Modal,
+ message,
+ Badge,
+ Divider,
+ Steps,
+ Radio,
+} from 'antd';
+import StandardTable from '@/components/StandardTable';
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+
+import styles from './DictManage.less';
+
+const FormItem = Form.Item;
+const { Step } = Steps;
+const { TextArea } = Input;
+const { Option } = Select;
+const RadioGroup = Radio.Group;
+const getValue = obj =>
+ Object.keys(obj)
+ .map(key => obj[key])
+ .join(',');
+const statusMap = ['default', 'processing', 'success', 'error'];
+const status = ['关闭', '运行中', '已上线', '异常'];
+
+const CreateForm = Form.create()(props => {
+ const { modalVisible, form, handleAdd, handleModalVisible } = props;
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleAdd(fieldsValue);
+ });
+ };
+ return (
+ handleModalVisible()}
+ >
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ })()}
+
+
+ );
+});
+
+@Form.create()
+class UpdateForm extends PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ formVals: {
+ name: props.values.name,
+ desc: props.values.desc,
+ key: props.values.key,
+ target: '0',
+ template: '0',
+ type: '1',
+ time: '',
+ frequency: 'month',
+ },
+ currentStep: 0,
+ };
+
+ this.formLayout = {
+ labelCol: { span: 7 },
+ wrapperCol: { span: 13 },
+ };
+ }
+
+ handleNext = currentStep => {
+ const { form, handleUpdate } = this.props;
+ const { formVals: oldValue } = this.state;
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ const formVals = { ...oldValue, ...fieldsValue };
+ this.setState(
+ {
+ formVals,
+ },
+ () => {
+ if (currentStep < 2) {
+ this.forward();
+ } else {
+ handleUpdate(formVals);
+ }
+ }
+ );
+ });
+ };
+
+ backward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep - 1,
+ });
+ };
+
+ forward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep + 1,
+ });
+ };
+
+ renderContent = (currentStep, formVals) => {
+ const { form } = this.props;
+ if (currentStep === 1) {
+ return [
+
+ {form.getFieldDecorator('target', {
+ initialValue: formVals.target,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('template', {
+ initialValue: formVals.template,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('type', {
+ initialValue: formVals.type,
+ })(
+
+ 强
+ 弱
+
+ )}
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+
+ {form.getFieldDecorator('time', {
+ rules: [{ required: true, message: '请选择开始时间!' }],
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('frequency', {
+ initialValue: formVals.frequency,
+ })(
+
+ )}
+ ,
+ ];
+ }
+ return [
+
+ {form.getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入规则名称!' }],
+ initialValue: formVals.name,
+ })()}
+ ,
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ initialValue: formVals.desc,
+ })()}
+ ,
+ ];
+ };
+
+ renderFooter = currentStep => {
+ const { handleUpdateModalVisible } = this.props;
+ if (currentStep === 1) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ return [
+ ,
+ ,
+ ];
+ };
+
+ render() {
+ const { updateModalVisible, handleUpdateModalVisible } = this.props;
+ const { currentStep, formVals } = this.state;
+
+ return (
+ handleUpdateModalVisible()}
+ >
+
+
+
+
+
+ {this.renderContent(currentStep, formVals)}
+
+ );
+ }
+}
+
+/* eslint react/no-multi-comp:0 */
+@connect(({ rule, loading }) => ({
+ rule,
+ loading: loading.models.rule,
+}))
+@Form.create()
+class DictManage extends PureComponent {
+ state = {
+ modalVisible: false,
+ updateModalVisible: false,
+ expandForm: false,
+ selectedRows: [],
+ formValues: {},
+ stepFormValues: {},
+ };
+
+ columns = [
+ {
+ title: '规则名称',
+ dataIndex: 'name',
+ },
+ {
+ title: '描述',
+ dataIndex: 'desc',
+ },
+ {
+ title: '服务调用次数',
+ dataIndex: 'callNo',
+ sorter: true,
+ align: 'right',
+ render: val => `${val} 万`,
+ // mark to display a total number
+ needTotal: true,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ filters: [
+ {
+ text: status[0],
+ value: 0,
+ },
+ {
+ text: status[1],
+ value: 1,
+ },
+ {
+ text: status[2],
+ value: 2,
+ },
+ {
+ text: status[3],
+ value: 3,
+ },
+ ],
+ render(val) {
+ return ;
+ },
+ },
+ {
+ title: '上次调度时间',
+ dataIndex: 'updatedAt',
+ sorter: true,
+ render: val => {moment(val).format('YYYY-MM-DD HH:mm:ss')},
+ },
+ {
+ title: '操作',
+ render: (text, record) => (
+
+ this.handleUpdateModalVisible(true, record)}>配置
+
+ 订阅警报
+
+ ),
+ },
+ ];
+
+ componentDidMount() {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/fetch',
+ });
+ }
+
+ handleStandardTableChange = (pagination, filtersArg, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const filters = Object.keys(filtersArg).reduce((obj, key) => {
+ const newObj = { ...obj };
+ newObj[key] = getValue(filtersArg[key]);
+ return newObj;
+ }, {});
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues,
+ ...filters,
+ };
+ if (sorter.field) {
+ params.sorter = `${sorter.field}_${sorter.order}`;
+ }
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: params,
+ });
+ };
+
+ handleFormReset = () => {
+ const { form, dispatch } = this.props;
+ form.resetFields();
+ this.setState({
+ formValues: {},
+ });
+ dispatch({
+ type: 'rule/fetch',
+ payload: {},
+ });
+ };
+
+ toggleForm = () => {
+ const { expandForm } = this.state;
+ this.setState({
+ expandForm: !expandForm,
+ });
+ };
+
+ handleMenuClick = e => {
+ const { dispatch } = this.props;
+ const { selectedRows } = this.state;
+
+ if (!selectedRows) return;
+ switch (e.key) {
+ case 'remove':
+ dispatch({
+ type: 'rule/remove',
+ payload: {
+ key: selectedRows.map(row => row.key),
+ },
+ callback: () => {
+ this.setState({
+ selectedRows: [],
+ });
+ },
+ });
+ break;
+ default:
+ break;
+ }
+ };
+
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows,
+ });
+ };
+
+ handleSearch = e => {
+ e.preventDefault();
+
+ const { dispatch, form } = this.props;
+
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+
+ const values = {
+ ...fieldsValue,
+ updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
+ };
+
+ this.setState({
+ formValues: values,
+ });
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: values,
+ });
+ });
+ };
+
+ handleModalVisible = flag => {
+ this.setState({
+ modalVisible: !!flag,
+ });
+ };
+
+ handleUpdateModalVisible = (flag, record) => {
+ this.setState({
+ updateModalVisible: !!flag,
+ stepFormValues: record || {},
+ });
+ };
+
+ handleAdd = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/add',
+ payload: {
+ desc: fields.desc,
+ },
+ });
+
+ message.success('添加成功');
+ this.handleModalVisible();
+ };
+
+ handleUpdate = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/update',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ key: fields.key,
+ },
+ });
+
+ message.success('配置成功');
+ this.handleUpdateModalVisible();
+ };
+
+ renderSimpleForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderAdvancedForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderForm() {
+ const { expandForm } = this.state;
+ return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
+ }
+
+ render() {
+ const {
+ rule: { data },
+ loading,
+ } = this.props;
+ const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
+ const menu = (
+
+ );
+
+ const parentMethods = {
+ handleAdd: this.handleAdd,
+ handleModalVisible: this.handleModalVisible,
+ };
+ const updateMethods = {
+ handleUpdateModalVisible: this.handleUpdateModalVisible,
+ handleUpdate: this.handleUpdate,
+ };
+ return (
+
+
+
+
{this.renderForm()}
+
+
+ {selectedRows.length > 0 && (
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ {stepFormValues && Object.keys(stepFormValues).length ? (
+
+ ) : null}
+
+ );
+ }
+}
+
+export default DictManage;
diff --git a/web/src/pages/SearchManage/DictManage.less b/web/src/pages/SearchManage/DictManage.less
new file mode 100644
index 00000000..792757df
--- /dev/null
+++ b/web/src/pages/SearchManage/DictManage.less
@@ -0,0 +1,49 @@
+@import '~antd/lib/style/themes/default.less';
+@import '~@/utils/utils.less';
+
+.tableList {
+ .tableListOperator {
+ margin-bottom: 16px;
+ button {
+ margin-right: 8px;
+ }
+ }
+}
+
+.tableListForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 24px;
+ margin-right: 0;
+ display: flex;
+ > .ant-form-item-label {
+ width: auto;
+ line-height: 32px;
+ padding-right: 8px;
+ }
+ .ant-form-item-control {
+ line-height: 32px;
+ }
+ }
+ .ant-form-item-control-wrapper {
+ flex: 1;
+ }
+ }
+ .submitButtons {
+ display: block;
+ white-space: nowrap;
+ margin-bottom: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-lg) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 8px;
+ }
+}
diff --git a/web/src/pages/SearchManage/NLPManage.js b/web/src/pages/SearchManage/NLPManage.js
new file mode 100644
index 00000000..84dfd1c8
--- /dev/null
+++ b/web/src/pages/SearchManage/NLPManage.js
@@ -0,0 +1,675 @@
+import React, { PureComponent, Fragment } from 'react';
+import { connect } from 'dva';
+import moment from 'moment';
+import {
+ Row,
+ Col,
+ Card,
+ Form,
+ Input,
+ Select,
+ Icon,
+ Button,
+ Dropdown,
+ Menu,
+ InputNumber,
+ DatePicker,
+ Modal,
+ message,
+ Badge,
+ Divider,
+ Steps,
+ Radio,
+} from 'antd';
+import StandardTable from '@/components/StandardTable';
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+
+import styles from './NLPManage.less';
+
+const FormItem = Form.Item;
+const { Step } = Steps;
+const { TextArea } = Input;
+const { Option } = Select;
+const RadioGroup = Radio.Group;
+const getValue = obj =>
+ Object.keys(obj)
+ .map(key => obj[key])
+ .join(',');
+const statusMap = ['default', 'processing', 'success', 'error'];
+const status = ['关闭', '运行中', '已上线', '异常'];
+
+const CreateForm = Form.create()(props => {
+ const { modalVisible, form, handleAdd, handleModalVisible } = props;
+ const okHandle = () => {
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ form.resetFields();
+ handleAdd(fieldsValue);
+ });
+ };
+ return (
+ handleModalVisible()}
+ >
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ })()}
+
+
+ );
+});
+
+@Form.create()
+class UpdateForm extends PureComponent {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ formVals: {
+ name: props.values.name,
+ desc: props.values.desc,
+ key: props.values.key,
+ target: '0',
+ template: '0',
+ type: '1',
+ time: '',
+ frequency: 'month',
+ },
+ currentStep: 0,
+ };
+
+ this.formLayout = {
+ labelCol: { span: 7 },
+ wrapperCol: { span: 13 },
+ };
+ }
+
+ handleNext = currentStep => {
+ const { form, handleUpdate } = this.props;
+ const { formVals: oldValue } = this.state;
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ const formVals = { ...oldValue, ...fieldsValue };
+ this.setState(
+ {
+ formVals,
+ },
+ () => {
+ if (currentStep < 2) {
+ this.forward();
+ } else {
+ handleUpdate(formVals);
+ }
+ }
+ );
+ });
+ };
+
+ backward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep - 1,
+ });
+ };
+
+ forward = () => {
+ const { currentStep } = this.state;
+ this.setState({
+ currentStep: currentStep + 1,
+ });
+ };
+
+ renderContent = (currentStep, formVals) => {
+ const { form } = this.props;
+ if (currentStep === 1) {
+ return [
+
+ {form.getFieldDecorator('target', {
+ initialValue: formVals.target,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('template', {
+ initialValue: formVals.template,
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('type', {
+ initialValue: formVals.type,
+ })(
+
+ 强
+ 弱
+
+ )}
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+
+ {form.getFieldDecorator('time', {
+ rules: [{ required: true, message: '请选择开始时间!' }],
+ })(
+
+ )}
+ ,
+
+ {form.getFieldDecorator('frequency', {
+ initialValue: formVals.frequency,
+ })(
+
+ )}
+ ,
+ ];
+ }
+ return [
+
+ {form.getFieldDecorator('name', {
+ rules: [{ required: true, message: '请输入规则名称!' }],
+ initialValue: formVals.name,
+ })()}
+ ,
+
+ {form.getFieldDecorator('desc', {
+ rules: [{ required: true, message: '请输入至少五个字符的规则描述!', min: 5 }],
+ initialValue: formVals.desc,
+ })()}
+ ,
+ ];
+ };
+
+ renderFooter = currentStep => {
+ const { handleUpdateModalVisible } = this.props;
+ if (currentStep === 1) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ if (currentStep === 2) {
+ return [
+ ,
+ ,
+ ,
+ ];
+ }
+ return [
+ ,
+ ,
+ ];
+ };
+
+ render() {
+ const { updateModalVisible, handleUpdateModalVisible } = this.props;
+ const { currentStep, formVals } = this.state;
+
+ return (
+ handleUpdateModalVisible()}
+ >
+
+
+
+
+
+ {this.renderContent(currentStep, formVals)}
+
+ );
+ }
+}
+
+/* eslint react/no-multi-comp:0 */
+@connect(({ rule, loading }) => ({
+ rule,
+ loading: loading.models.rule,
+}))
+@Form.create()
+class NLPManage extends PureComponent {
+ state = {
+ modalVisible: false,
+ updateModalVisible: false,
+ expandForm: false,
+ selectedRows: [],
+ formValues: {},
+ stepFormValues: {},
+ };
+
+ columns = [
+ {
+ title: '规则名称',
+ dataIndex: 'name',
+ },
+ {
+ title: '描述',
+ dataIndex: 'desc',
+ },
+ {
+ title: '服务调用次数',
+ dataIndex: 'callNo',
+ sorter: true,
+ align: 'right',
+ render: val => `${val} 万`,
+ // mark to display a total number
+ needTotal: true,
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ filters: [
+ {
+ text: status[0],
+ value: 0,
+ },
+ {
+ text: status[1],
+ value: 1,
+ },
+ {
+ text: status[2],
+ value: 2,
+ },
+ {
+ text: status[3],
+ value: 3,
+ },
+ ],
+ render(val) {
+ return ;
+ },
+ },
+ {
+ title: '上次调度时间',
+ dataIndex: 'updatedAt',
+ sorter: true,
+ render: val => {moment(val).format('YYYY-MM-DD HH:mm:ss')},
+ },
+ {
+ title: '操作',
+ render: (text, record) => (
+
+ this.handleUpdateModalVisible(true, record)}>配置
+
+ 订阅警报
+
+ ),
+ },
+ ];
+
+ componentDidMount() {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/fetch',
+ });
+ }
+
+ handleStandardTableChange = (pagination, filtersArg, sorter) => {
+ const { dispatch } = this.props;
+ const { formValues } = this.state;
+
+ const filters = Object.keys(filtersArg).reduce((obj, key) => {
+ const newObj = { ...obj };
+ newObj[key] = getValue(filtersArg[key]);
+ return newObj;
+ }, {});
+
+ const params = {
+ currentPage: pagination.current,
+ pageSize: pagination.pageSize,
+ ...formValues,
+ ...filters,
+ };
+ if (sorter.field) {
+ params.sorter = `${sorter.field}_${sorter.order}`;
+ }
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: params,
+ });
+ };
+
+ handleFormReset = () => {
+ const { form, dispatch } = this.props;
+ form.resetFields();
+ this.setState({
+ formValues: {},
+ });
+ dispatch({
+ type: 'rule/fetch',
+ payload: {},
+ });
+ };
+
+ toggleForm = () => {
+ const { expandForm } = this.state;
+ this.setState({
+ expandForm: !expandForm,
+ });
+ };
+
+ handleMenuClick = e => {
+ const { dispatch } = this.props;
+ const { selectedRows } = this.state;
+
+ if (!selectedRows) return;
+ switch (e.key) {
+ case 'remove':
+ dispatch({
+ type: 'rule/remove',
+ payload: {
+ key: selectedRows.map(row => row.key),
+ },
+ callback: () => {
+ this.setState({
+ selectedRows: [],
+ });
+ },
+ });
+ break;
+ default:
+ break;
+ }
+ };
+
+ handleSelectRows = rows => {
+ this.setState({
+ selectedRows: rows,
+ });
+ };
+
+ handleSearch = e => {
+ e.preventDefault();
+
+ const { dispatch, form } = this.props;
+
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+
+ const values = {
+ ...fieldsValue,
+ updatedAt: fieldsValue.updatedAt && fieldsValue.updatedAt.valueOf(),
+ };
+
+ this.setState({
+ formValues: values,
+ });
+
+ dispatch({
+ type: 'rule/fetch',
+ payload: values,
+ });
+ });
+ };
+
+ handleModalVisible = flag => {
+ this.setState({
+ modalVisible: !!flag,
+ });
+ };
+
+ handleUpdateModalVisible = (flag, record) => {
+ this.setState({
+ updateModalVisible: !!flag,
+ stepFormValues: record || {},
+ });
+ };
+
+ handleAdd = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/add',
+ payload: {
+ desc: fields.desc,
+ },
+ });
+
+ message.success('添加成功');
+ this.handleModalVisible();
+ };
+
+ handleUpdate = fields => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'rule/update',
+ payload: {
+ name: fields.name,
+ desc: fields.desc,
+ key: fields.key,
+ },
+ });
+
+ message.success('配置成功');
+ this.handleUpdateModalVisible();
+ };
+
+ renderSimpleForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderAdvancedForm() {
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ return (
+
+ );
+ }
+
+ renderForm() {
+ const { expandForm } = this.state;
+ return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm();
+ }
+
+ render() {
+ const {
+ rule: { data },
+ loading,
+ } = this.props;
+ const { selectedRows, modalVisible, updateModalVisible, stepFormValues } = this.state;
+ const menu = (
+
+ );
+
+ const parentMethods = {
+ handleAdd: this.handleAdd,
+ handleModalVisible: this.handleModalVisible,
+ };
+ const updateMethods = {
+ handleUpdateModalVisible: this.handleUpdateModalVisible,
+ handleUpdate: this.handleUpdate,
+ };
+ return (
+
+
+
+
{this.renderForm()}
+
+
+ {selectedRows.length > 0 && (
+
+
+
+
+
+
+ )}
+
+
+
+
+
+ {stepFormValues && Object.keys(stepFormValues).length ? (
+
+ ) : null}
+
+ );
+ }
+}
+
+export default NLPManage;
diff --git a/web/src/pages/SearchManage/NLPManage.less b/web/src/pages/SearchManage/NLPManage.less
new file mode 100644
index 00000000..792757df
--- /dev/null
+++ b/web/src/pages/SearchManage/NLPManage.less
@@ -0,0 +1,49 @@
+@import '~antd/lib/style/themes/default.less';
+@import '~@/utils/utils.less';
+
+.tableList {
+ .tableListOperator {
+ margin-bottom: 16px;
+ button {
+ margin-right: 8px;
+ }
+ }
+}
+
+.tableListForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 24px;
+ margin-right: 0;
+ display: flex;
+ > .ant-form-item-label {
+ width: auto;
+ line-height: 32px;
+ padding-right: 8px;
+ }
+ .ant-form-item-control {
+ line-height: 32px;
+ }
+ }
+ .ant-form-item-control-wrapper {
+ flex: 1;
+ }
+ }
+ .submitButtons {
+ display: block;
+ white-space: nowrap;
+ margin-bottom: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-lg) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 24px;
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .tableListForm :global(.ant-form-item) {
+ margin-right: 8px;
+ }
+}
diff --git a/web/src/pages/SearchManage/SearchTemplate.js b/web/src/pages/SearchManage/SearchTemplate.js
new file mode 100644
index 00000000..4a6ab304
--- /dev/null
+++ b/web/src/pages/SearchManage/SearchTemplate.js
@@ -0,0 +1,311 @@
+import React, { PureComponent } from 'react';
+import { findDOMNode } from 'react-dom';
+import moment from 'moment';
+import { connect } from 'dva';
+import {
+ List,
+ Card,
+ Row,
+ Col,
+ Radio,
+ Input,
+ Progress,
+ Button,
+ Icon,
+ Dropdown,
+ Menu,
+ Avatar,
+ Modal,
+ Form,
+ DatePicker,
+ Select,
+} from 'antd';
+
+import PageHeaderWrapper from '@/components/PageHeaderWrapper';
+import Result from '@/components/Result';
+
+import styles from './SearchTemplate.less';
+
+const FormItem = Form.Item;
+const RadioButton = Radio.Button;
+const RadioGroup = Radio.Group;
+const SelectOption = Select.Option;
+const { Search, TextArea } = Input;
+
+@connect(({ list, loading }) => ({
+ list,
+ loading: loading.models.list,
+}))
+@Form.create()
+class SearchTemplate extends PureComponent {
+ state = { visible: false, done: false };
+
+ formLayout = {
+ labelCol: { span: 7 },
+ wrapperCol: { span: 13 },
+ };
+
+ componentDidMount() {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'list/fetch',
+ payload: {
+ count: 5,
+ },
+ });
+ }
+
+ showModal = () => {
+ this.setState({
+ visible: true,
+ current: undefined,
+ });
+ };
+
+ showEditModal = item => {
+ this.setState({
+ visible: true,
+ current: item,
+ });
+ };
+
+ handleDone = () => {
+ setTimeout(() => this.addBtn.blur(), 0);
+ this.setState({
+ done: false,
+ visible: false,
+ });
+ };
+
+ handleCancel = () => {
+ setTimeout(() => this.addBtn.blur(), 0);
+ this.setState({
+ visible: false,
+ });
+ };
+
+ handleSubmit = e => {
+ e.preventDefault();
+ const { dispatch, form } = this.props;
+ const { current } = this.state;
+ const id = current ? current.id : '';
+
+ setTimeout(() => this.addBtn.blur(), 0);
+ form.validateFields((err, fieldsValue) => {
+ if (err) return;
+ this.setState({
+ done: true,
+ });
+ dispatch({
+ type: 'list/submit',
+ payload: { id, ...fieldsValue },
+ });
+ });
+ };
+
+ deleteItem = id => {
+ const { dispatch } = this.props;
+ dispatch({
+ type: 'list/submit',
+ payload: { id },
+ });
+ };
+
+ render() {
+ const {
+ list: { list },
+ loading,
+ } = this.props;
+ const {
+ form: { getFieldDecorator },
+ } = this.props;
+ const { visible, done, current = {} } = this.state;
+
+ const editAndDelete = (key, currentItem) => {
+ if (key === 'edit') this.showEditModal(currentItem);
+ else if (key === 'delete') {
+ Modal.confirm({
+ title: '删除模板',
+ content: '确定删除该模板吗?',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => this.deleteItem(currentItem.id),
+ });
+ }
+ };
+
+ const modalFooter = done
+ ? { footer: null, onCancel: this.handleDone }
+ : { okText: '保存', onOk: this.handleSubmit, onCancel: this.handleCancel };
+
+ const Info = ({ title, value, bordered }) => (
+
+
{title}
+
{value}
+ {bordered &&
}
+
+ );
+
+ const extraContent = (
+
+ ({})} />
+
+ );
+
+ const paginationProps = {
+ showSizeChanger: true,
+ showQuickJumper: true,
+ pageSize: 5,
+ total: 50,
+ };
+
+ const ListContent = ({ data: { owner, createdAt, percent, status } }) => (
+
+
+
+
创建时间
+
{moment(createdAt).format('YYYY-MM-DD HH:mm')}
+
+
+
+ );
+
+ const MoreBtn = props => (
+ editAndDelete(key, props.current)}>
+ 编辑
+ 删除
+
+ }
+ >
+
+ 更多
+
+
+ );
+
+ const getModalContent = () => {
+ if (done) {
+ return (
+
+ 知道了
+
+ }
+ className={styles.formResult}
+ />
+ );
+ }
+ return (
+
+ );
+ };
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (
+ {
+ e.preventDefault();
+ this.showEditModal(item);
+ }}
+ >
+ 编辑
+ ,
+ ,
+ ]}
+ >
+ }
+ title={{item.title}}
+ description={item.subDescription}
+ />
+
+
+ )}
+ />
+
+
+
+ {getModalContent()}
+
+
+ );
+ }
+}
+
+export default SearchTemplate;
diff --git a/web/src/pages/SearchManage/SearchTemplate.less b/web/src/pages/SearchManage/SearchTemplate.less
new file mode 100644
index 00000000..f086c501
--- /dev/null
+++ b/web/src/pages/SearchManage/SearchTemplate.less
@@ -0,0 +1,195 @@
+@import '~antd/lib/style/themes/default.less';
+@import '~@/utils/utils.less';
+
+.standardList {
+ :global {
+ .ant-card-head {
+ border-bottom: none;
+ }
+ .ant-card-head-title {
+ line-height: 32px;
+ padding: 24px 0;
+ }
+ .ant-card-extra {
+ padding: 24px 0;
+ }
+ .ant-list-pagination {
+ text-align: right;
+ margin-top: 24px;
+ }
+ .ant-avatar-lg {
+ width: 48px;
+ height: 48px;
+ line-height: 48px;
+ }
+ }
+ .headerInfo {
+ position: relative;
+ text-align: center;
+ & > span {
+ color: @text-color-secondary;
+ display: inline-block;
+ font-size: @font-size-base;
+ line-height: 22px;
+ margin-bottom: 4px;
+ }
+ & > p {
+ color: @heading-color;
+ font-size: 24px;
+ line-height: 32px;
+ margin: 0;
+ }
+ & > em {
+ background-color: @border-color-split;
+ position: absolute;
+ height: 56px;
+ width: 1px;
+ top: 0;
+ right: 0;
+ }
+ }
+ .listContent {
+ font-size: 0;
+ .listContentItem {
+ color: @text-color-secondary;
+ display: inline-block;
+ vertical-align: middle;
+ font-size: @font-size-base;
+ margin-left: 40px;
+ > span {
+ line-height: 20px;
+ }
+ > p {
+ margin-top: 4px;
+ margin-bottom: 0;
+ line-height: 22px;
+ }
+ }
+ }
+ .extraContentSearch {
+ margin-left: 16px;
+ width: 272px;
+ }
+}
+
+@media screen and (max-width: @screen-xs) {
+ .standardList {
+ :global {
+ .ant-list-item-content {
+ display: block;
+ flex: none;
+ width: 100%;
+ }
+ .ant-list-item-action {
+ margin-left: 0;
+ }
+ }
+ .listContent {
+ margin-left: 0;
+ & > div {
+ margin-left: 0;
+ }
+ }
+ .listCard {
+ :global {
+ .ant-card-head-title {
+ overflow: visible;
+ }
+ }
+ }
+ }
+}
+
+@media screen and (max-width: @screen-sm) {
+ .standardList {
+ .extraContentSearch {
+ margin-left: 0;
+ width: 100%;
+ }
+ .headerInfo {
+ margin-bottom: 16px;
+ & > em {
+ display: none;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: @screen-md) {
+ .standardList {
+ .listContent {
+ & > div {
+ display: block;
+ }
+ & > div:last-child {
+ top: 0;
+ width: 100%;
+ }
+ }
+ }
+ .listCard {
+ :global {
+ .ant-radio-group {
+ display: block;
+ margin-bottom: 8px;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: @screen-lg) and (min-width: @screen-md) {
+ .standardList {
+ .listContent {
+ & > div {
+ display: block;
+ }
+ & > div:last-child {
+ top: 0;
+ width: 100%;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: @screen-xl) {
+ .standardList {
+ .listContent {
+ & > div {
+ margin-left: 24px;
+ }
+ & > div:last-child {
+ top: 0;
+ }
+ }
+ }
+}
+
+@media screen and (max-width: 1400px) {
+ .standardList {
+ .listContent {
+ text-align: right;
+ & > div:last-child {
+ top: 0;
+ }
+ }
+ }
+}
+
+.standardListForm {
+ :global {
+ .ant-form-item {
+ margin-bottom: 12px;
+ &:last-child {
+ padding-top: 4px;
+ margin-bottom: 32px;
+ }
+ }
+ }
+}
+
+.formResult {
+ width: 100%;
+ [class^='title'] {
+ margin-bottom: 8px;
+ }
+}
diff --git a/web/src/pages/SearchManage/models/rule.js b/web/src/pages/SearchManage/models/rule.js
new file mode 100644
index 00000000..b318dbe3
--- /dev/null
+++ b/web/src/pages/SearchManage/models/rule.js
@@ -0,0 +1,55 @@
+import { queryRule, removeRule, addRule, updateRule } from '@/services/api';
+
+export default {
+ namespace: 'rule',
+
+ state: {
+ data: {
+ list: [],
+ pagination: {},
+ },
+ },
+
+ effects: {
+ *fetch({ payload }, { call, put }) {
+ const response = yield call(queryRule, payload);
+ yield put({
+ type: 'save',
+ payload: response,
+ });
+ },
+ *add({ payload, callback }, { call, put }) {
+ const response = yield call(addRule, payload);
+ yield put({
+ type: 'save',
+ payload: response,
+ });
+ if (callback) callback();
+ },
+ *remove({ payload, callback }, { call, put }) {
+ const response = yield call(removeRule, payload);
+ yield put({
+ type: 'save',
+ payload: response,
+ });
+ if (callback) callback();
+ },
+ *update({ payload, callback }, { call, put }) {
+ const response = yield call(updateRule, payload);
+ yield put({
+ type: 'save',
+ payload: response,
+ });
+ if (callback) callback();
+ },
+ },
+
+ reducers: {
+ save(state, action) {
+ return {
+ ...state,
+ data: action.payload,
+ };
+ },
+ },
+};