소스 검색

Merge branch 'feature/fengkong_thanos' into 'master'

增加风控管理模块

See merge request admin-manager/dc!25
王文博 5 년 전
부모
커밋
895b6975ff

+ 1 - 0
package.json

@@ -29,6 +29,7 @@
     "eslint-plugin-standard": "^4.0.1",
     "less-vars-to-js": "^1.3.0",
     "lint-staged": "^9.3.0",
+    "react-ace": "^8.1.0",
     "react-test-renderer": "^16.9.0",
     "umi": "^2.9.6",
     "umi-plugin-react": "^1.15.2"

+ 40 - 35
src/conf/config.js

@@ -1,45 +1,49 @@
-let dc = 'http://back-apit.weipaitang.com';
-let tc = 'http://localhost:8080';
-let apiCdn = 'http://cdn01t.weipaitang.com/img/';
-let auth = 'https://back-autht.weipaitang.com';
-let hostDev = 'http://back-admint.weipaitang.com';
-let us = 'http://back-apit.weipaitang.com';
-let sTaskJobLog = "http://10.3.7.11:16686"; // 定时任务日志跳转
+let dc = 'http://back-apit.weipaitang.com'
+let tc = 'http://localhost:8080'
+const apiCdn = 'http://cdn01t.weipaitang.com/img/'
+let auth = 'https://back-autht.weipaitang.com'
+let hostDev = 'http://back-admint.weipaitang.com'
+let us = 'http://back-apit.weipaitang.com'
+let sTaskJobLog = 'http://10.3.7.11:16686' // 定时任务日志跳转
+let thanos = 'http://thanos-admint.wpt.la'
 
 if (document.domain === 'localhost') {
-
   // dc = 'http://localhost:8000/api'
   // dc = 'http://backend.wpt.local:8087'
-  dc = 'http://back-apit.weipaitang.com';
-
+  dc = 'http://back-apit.weipaitang.com'
+  thanos = 'http://thanos-admint.wpt.la'
 } else if (document.domain === 'back-admint.wpt.la') {
-  dc = 'http://back-apit.weipaitang.com';
-  us = 'http://back-apit.weipaitang.com';
-  tc = 'http://back-apit.weipaitang.com';
-  auth = 'https://back-autht.weipaitang.com';
-  hostDev = 'http://back-admint.weipaitang.com';
-  sTaskJobLog = "http://10.3.7.11:16686"; // 定时任务日志跳转
+  dc = 'http://back-apit.weipaitang.com'
+  us = 'http://back-apit.weipaitang.com'
+  tc = 'http://back-apit.weipaitang.com'
+  auth = 'https://back-autht.weipaitang.com'
+  hostDev = 'http://back-admint.weipaitang.com'
+  sTaskJobLog = 'http://10.3.7.11:16686' // 定时任务日志跳转
+  thanos = 'http://thanos-admint.wpt.la'
 } else if (document.domain === 'back-admint.weipaitang.com') {
-  dc = 'http://back-apit.weipaitang.com';
-  tc = 'http://back-apit.weipaitang.com';
-  auth = 'https://back-autht.weipaitang.com';
-  us = 'http://back-apit.weipaitang.com';
-  hostDev = 'http://back-admint.weipaitang.com';
-  sTaskJobLog = "http://10.3.7.11:16686"; // 定时任务日志跳转
+  dc = 'http://back-apit.weipaitang.com'
+  tc = 'http://back-apit.weipaitang.com'
+  auth = 'https://back-autht.weipaitang.com'
+  us = 'http://back-apit.weipaitang.com'
+  hostDev = 'http://back-admint.weipaitang.com'
+  sTaskJobLog = 'http://10.3.7.11:16686' // 定时任务日志跳转
+  thanos = 'http://thanos-admint.wpt.la'
 } else if (document.domain === 'back-admin.wpt.la') {
-  dc = 'http://back-admin.wpt.la/api';
-  tc = 'http://back-admin.wpt.la/api';
-  auth = 'https://back-auth.weipaitang.com';
-  us = 'http://back-api.weipaitang.com';
-  hostDev = 'http://back-admin.wpt.la';
-  sTaskJobLog = "http://10.3.7.11:16686"; // 定时任务日志跳转
+  dc = 'http://back-admin.wpt.la/api'
+  tc = 'http://back-admin.wpt.la/api'
+  auth = 'https://back-auth.weipaitang.com'
+  us = 'http://back-api.weipaitang.com'
+  hostDev = 'http://back-admin.wpt.la'
+  sTaskJobLog = 'http://10.3.7.11:16686' // 定时任务日志跳转
+  thanos = 'http://thanos-admin-inside.wptqc.com​'
 } else if (document.domain === 'back-admin.weipaitang.com') {
-  dc = 'http://back-api.weipaitang.com';
-  tc = 'http://back-api.weipaitang.com';
-  auth = 'https://back-auth.weipaitang.com';
-  us = 'http://back-api.weipaitang.com';
-  hostDev = 'http://back-admin.weipaitang.com';
-  sTaskJobLog = "http://ms-trace.weipaitang.com"; // 定时任务日志跳转
+  dc = 'http://back-api.weipaitang.com'
+  tc = 'http://back-api.weipaitang.com'
+  auth = 'https://back-auth.weipaitang.com'
+  us = 'http://back-api.weipaitang.com'
+  hostDev = 'http://back-admin.weipaitang.com'
+  sTaskJobLog = 'http://ms-trace.weipaitang.com' // 定时任务日志跳转
+  thanos = 'http://thanos-admin-inside.wptqc.com​'
 }
 
 export {
@@ -49,5 +53,6 @@ export {
   apiCdn,
   auth,
   hostDev,
-  sTaskJobLog
+  sTaskJobLog,
+  thanos
 }

+ 5 - 3
src/layouts/mainLayout/index.less

@@ -45,10 +45,12 @@
       white-space: nowrap;
       margin: 0;
       color: #fff;
+      font-size: 20px;
     }
     .logo {
-      height: 32px;
-      margin: 0px 5px 0px 24px;
+      height: 40px;
+      margin: 0px 10px 0px 10px;
+      border-radius: 5px;
     }
   }
   .content {
@@ -63,4 +65,4 @@
     text-align: center;
     font-size: 14px;
   }
-}
+}

+ 83 - 0
src/pages/fengkong/features/feature.js

@@ -0,0 +1,83 @@
+import React from 'react'
+import { FilterTable } from 'wptpc-design'
+import { thanos } from '@/conf/config'
+
+const apiUrl = `${thanos}/thanos-admin/api/v1/feature/list`
+
+class FeaturesList extends React.PureComponent {
+  state = {
+    showModal: false,
+    params: {}
+  }
+
+  filterSetting = {
+    isClearSearch: true,
+    formFields: [
+      {
+        label: '描述:',
+        type: 'input',
+        key: 'queryName',
+        placeholder: '特征名称'
+      }
+    ]
+    // 在接口请求前,可以修改给接口的入参
+    // beforeSearchFunc: params => {
+    //   params.pageNum = params.pageNum
+    // }
+  }
+
+  // filtertable的列表配置
+  tableSetting = {
+    // rowKey: 'alias',
+    // isFrontPagination: true,
+    pagination: {
+      pageSize: 10
+    },
+    columnConfig: [
+      {
+        title: 'ID',
+        dataIndex: 'id'
+      },
+      {
+        title: '名称',
+        dataIndex: 'name'
+      },
+      {
+        title: '描述',
+        dataIndex: 'description'
+      },
+      {
+        title: '是否输出',
+        dataIndex: 'overt',
+        render: (text) => text === true ? '是' : '否'
+      },
+      {
+        title: '是否IO型特征',
+        dataIndex: 'io',
+        render: (text) => text === true ? '是' : '否'
+      },
+      {
+        title: '数据类型',
+        dataIndex: 'returnType'
+      },
+      {
+        title: '类目',
+        dataIndex: 'category'
+      }
+    ],
+    getRefresh: refresh => {
+      this.refresh = refresh
+    }
+  }
+
+  render () {
+    return (
+      <div>
+        <FilterTable filterSetting={this.filterSetting} tableSetting={this.tableSetting} apiUrl={apiUrl}
+        />
+      </div>
+    )
+  }
+}
+
+export default FeaturesList

+ 142 - 0
src/pages/fengkong/features/group/add/index.js

@@ -0,0 +1,142 @@
+import React from 'react'
+import { Form, Input, Row, Col, Switch, Button, Modal, message } from 'antd'
+import AceEditor from 'react-ace'
+import { create, test } from '../service'
+
+import 'ace-builds/src-noconflict/mode-java'
+import 'ace-builds/src-noconflict/theme-monokai'
+import { connect } from 'dva'
+
+const formItemLayout = {
+  layout: 'vertical'
+}
+@connect(({ user }) => ({
+  currentUser: user.currentUser
+}))
+@Form.create()
+class Add extends React.PureComponent {
+  state = {
+    content: '',
+    showTest: false, // 是否展示测试内容
+    testContent: '', // 测试数据
+    testResult: '' // 测试结果
+  }
+
+  create = () => {
+    this.props.form.validateFields((err, values) => {
+      if (!err) {
+        create({
+          ...values,
+          createUser: this.props.currentUser.name, // 创建人
+          updateUser: this.props.currentUser.name // 最后修改人
+        }).then(res => {
+          if (res.code === 0) {
+            this.setState({ ...values })
+            Modal.success({
+              title: '提交成功',
+              content: '策略代码编译正常,点击“测试按钮”可以继续测试策略逻辑'
+            })
+          }
+        })
+      }
+    })
+  }
+
+  test =() => {
+    if (!this.state.name) {
+      message.warn('请先提交分组内容!')
+      return false
+    }
+    test({
+      name: this.state.name,
+      input: this.state.testContent
+    }).then(res => {
+      if (res.code === 0) {
+        this.setState({ testResult: res.data })
+      }
+    })
+  }
+
+  render () {
+    const { getFieldDecorator } = this.props.form
+
+    return (
+      <div>
+        <h1>新增分组</h1>
+        <Row>
+          <Col span={12}>
+            <Form {...formItemLayout}>
+              <Form.Item label="分组名称">
+                {getFieldDecorator('name')(<Input placeholder="全英文或英文带下划线" />)}
+              </Form.Item>
+              <Form.Item label="特征列表">
+                {getFieldDecorator('features')(<Input placeholder=",号分割" />)}
+              </Form.Item>
+              <Form.Item label="分组描述">
+                {getFieldDecorator('description')(<Input.TextArea placeholder="多行输入" />)}
+              </Form.Item>
+              <Form.Item label="前置函数">
+                {getFieldDecorator('preScript')(<Input placeholder="预处理分组函数" />)}
+              </Form.Item>
+              <Form.Item label="后置函数">
+                {getFieldDecorator('postScript')(<Input placeholder="后处理分组函数" />)}
+              </Form.Item>
+              <Form.Item>
+                <Button type="primary" onClick={this.create}>提交</Button>&emsp;
+                <Button onClick={() => this.setState({ showTest: true })}>测试</Button>
+              </Form.Item>
+            </Form>
+          </Col>
+          <Col span={12}>
+            <div style={{ paddingLeft: '20px', display: this.state.showTest ? 'block' : 'none' }}>
+              <Form.Item label="输入数据">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  onChange={(value) => this.setState({ testContent: value })}
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testContent}
+                  height="300px"
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+
+              <Button type="primary" onClick={this.test}>执行测试</Button>&emsp;
+              <Form.Item label="输出结果">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testResult}
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+            </div>
+
+          </Col>
+        </Row>
+
+      </div>
+    )
+  }
+}
+
+export default Add

+ 168 - 0
src/pages/fengkong/features/group/edit/$name.js

@@ -0,0 +1,168 @@
+import React from 'react'
+import { Form, Input, Row, Col, Button, Modal, message } from 'antd'
+import { connect } from 'dva'
+import AceEditor from 'react-ace'
+import { isJSON } from '@/utils/utils'
+import { detail, update, test } from '../service'
+
+import 'ace-builds/src-noconflict/mode-java'
+import 'ace-builds/src-noconflict/theme-monokai'
+
+const formItemLayout = {
+  layout: 'vertical'
+}
+@connect(({ user }) => ({
+  currentUser: user.currentUser
+}))
+@Form.create()
+class Add extends React.PureComponent {
+  state = {
+    content: '',
+    showTest: false, // 是否展示测试内容
+    testContent: '', // 测试数据
+    testResult: '' // 测试结果
+  }
+
+  componentDidMount () {
+    detail({
+      name: this.props.match.params.name
+    }).then(res => {
+      if (res.code === 0) {
+        this.setState({ ...res.data })
+      }
+    })
+  }
+
+  create = () => {
+    this.props.form.validateFields((err, values) => {
+      if (!err) {
+        update({
+          ...values,
+          content: this.state.content,
+          createUser: this.state.createUser || this.props.currentUser.name, // 创建人
+          updateUser: this.props.currentUser.name // 最后修改人
+        }).then(res => {
+          if (res.code === 0) {
+            this.setState({ ...values })
+            Modal.success({
+              title: '提交成功',
+              content: '策略代码编译正常,点击“测试按钮”可以继续测试策略逻辑'
+            })
+          }
+        })
+      }
+    })
+  }
+
+  test =() => {
+    if (!this.state.name) {
+      message.warn('请先提交策略内容!')
+      return false
+    }
+    if (!isJSON(this.state.testContent)) {
+      message.warn('输入数据格式错误!')
+      return false
+    }
+    test({
+      group: this.state.name,
+      input: JSON.parse(this.state.testContent)
+    }).then(res => {
+      if (res.code === 0) {
+        this.setState({ testResult: JSON.stringify(res) })
+      }
+    })
+  }
+
+  render () {
+    const { getFieldDecorator } = this.props.form
+    const { name, features, description, preScript, postScript } = this.state
+    return (
+      <div>
+        <h1>编辑分组</h1>
+        <Row>
+          <Col span={12}>
+            <Form {...formItemLayout}>
+              <Form.Item label="分组名称">
+                {getFieldDecorator('name', {
+                  initialValue: name
+                })(<Input placeholder="全英文或英文带下划线" />)}
+              </Form.Item>
+              <Form.Item label="特征列表">
+                {getFieldDecorator('features', {
+                  initialValue: features
+                })(<Input placeholder=",号分割" />)}
+              </Form.Item>
+              <Form.Item label="分组描述">
+                {getFieldDecorator('description', {
+                  initialValue: description
+                })(<Input.TextArea placeholder="多行输入" />)}
+              </Form.Item>
+              <Form.Item label="前置函数">
+                {getFieldDecorator('preScript', {
+                  initialValue: preScript
+                })(<Input placeholder="预处理分组函数" />)}
+              </Form.Item>
+              <Form.Item label="后置函数">
+                {getFieldDecorator('postScript', {
+                  initialValue: postScript
+                })(<Input placeholder="后处理分组函数" />)}
+              </Form.Item>
+              <Form.Item>
+                <Button type="primary" onClick={this.create}>提交</Button>&emsp;
+                <Button onClick={() => this.setState({ showTest: true })}>测试</Button>
+              </Form.Item>
+            </Form>
+          </Col>
+          <Col span={12}>
+            <div style={{ paddingLeft: '20px', display: this.state.showTest ? 'block' : 'none' }}>
+              <Form.Item label="输入数据">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  onChange={(value) => this.setState({ testContent: value })}
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testContent}
+                  height="300px"
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+
+              <Button type="primary" onClick={this.test}>执行测试</Button>&emsp;
+              <Form.Item label="输出结果">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testResult}
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+            </div>
+
+          </Col>
+        </Row>
+
+      </div>
+    )
+  }
+}
+
+export default Add

+ 117 - 0
src/pages/fengkong/features/group/index.js

@@ -0,0 +1,117 @@
+import React from 'react'
+import { FilterTable } from 'wptpc-design'
+import { Link } from 'dva/router'
+import { thanos } from '@/conf/config'
+import { Divider, message, Popconfirm, Button } from 'antd'
+import { delItem } from './service.js'
+
+const apiUrl = `${thanos}/thanos-admin/api/v1/group/list`
+
+class GroupList extends React.PureComponent {
+  state = {
+    showModal: false,
+    params: {}
+  }
+
+  filterSetting = {
+    rfBtnsJsx: <Link
+      to={{
+        pathname: './group/add'
+      }}
+    ><Button>新增分组</Button></Link>,
+    isClearSearch: true,
+    formFields: [
+      {
+        label: '描述:',
+        type: 'input',
+        key: 'queryName',
+        placeholder: '分组名称'
+      }
+    ]
+    // 在接口请求前,可以修改给接口的入参
+    // beforeSearchFunc: params => {
+    //   params.pageNum = params.pageNum
+    // }
+  }
+
+  // filtertable的列表配置
+  tableSetting = {
+    pagination: {
+      pageSize: 10
+    },
+    columnConfig: [
+      {
+        title: 'ID',
+        dataIndex: 'id'
+      },
+      {
+        title: '分组名称',
+        dataIndex: 'name'
+      },
+      {
+        title: '描述',
+        dataIndex: 'description'
+      },
+      {
+        title: '前置函数',
+        dataIndex: 'preScript'
+      },
+      {
+        title: '后置函数',
+        dataIndex: 'postScript'
+      },
+      {
+        title: '创建人',
+        dataIndex: 'createUser'
+      },
+      {
+        title: '修改人',
+        dataIndex: 'updateUser'
+      },
+      {
+        title: '操作',
+        dataIndex: 'actions',
+        // 所有需要弹窗操作的都可以用编辑的逻辑;所有不需要弹窗的操作,比如上架、发布等,都可以用”删除“的逻辑
+        render: (text, record) => (
+          <span>
+            <Link
+              to={{
+                pathname: './group/edit/' + record.name,
+                state: record
+              }}
+            >编辑</Link>
+            <Divider type="vertical"/>
+            <Popconfirm
+              title="确定删除"
+              onConfirm={() => this.delItem(record)}>
+              <a>删除</a>
+            </Popconfirm>
+          </span>)
+      }
+    ],
+    getRefresh: refresh => {
+      this.refresh = refresh
+    }
+  }
+
+    // 点击删除按钮时的事件处理函数
+    delItem = (record) => {
+      delItem({ id: record.id, name: record.name }).then(res => {
+        if (res.code === 0) {
+          message.success('删除成功')
+          this.refresh()
+        }
+      })
+    }
+
+  render () {
+    return (
+      <div>
+        <FilterTable filterSetting={this.filterSetting} tableSetting={this.tableSetting} apiUrl={apiUrl}
+        />
+      </div>
+    )
+  }
+}
+
+export default GroupList

+ 32 - 0
src/pages/fengkong/features/group/service.js

@@ -0,0 +1,32 @@
+import { fetchApi, fetchApi_get as fetchApiGet } from '@/apis/'
+import { thanos } from '@/conf/config'
+
+// 新增策略
+export async function create (params) {
+  const url = `${thanos}/thanos-admin/api/v1/group/create`
+  return fetchApi(url, params)
+}
+
+// 测试策略
+export async function test (params) {
+  const url = `${thanos}/thanos-admin/api/v1/group/test`
+  return fetchApi(url, params)
+}
+
+// 获取分组详情
+export async function detail (params) {
+  const url = `${thanos}/thanos-admin/api/v1/group/query`
+  return fetchApiGet(url, params)
+}
+
+// 更新
+export async function update (params) {
+  const url = `${thanos}/thanos-admin/api/v1/group/update`
+  return fetchApi(url, params)
+}
+
+//删除
+export async function delItem (params) {
+  const url = `${thanos}/thanos-admin/api/v1/group/delete`
+  return fetchApi(url, params)
+}

+ 164 - 0
src/pages/fengkong/strategies/add/index.js

@@ -0,0 +1,164 @@
+import React from 'react'
+import { Form, Input, Row, Col, Switch, Button, Modal, message } from 'antd'
+import AceEditor from 'react-ace'
+import { create, test } from '../service'
+
+import 'ace-builds/src-noconflict/mode-java'
+import 'ace-builds/src-noconflict/theme-monokai'
+import { connect } from 'dva'
+
+const formItemLayout = {
+  layout: 'vertical'
+}
+
+@connect(({ user }) => ({
+  currentUser: user.currentUser
+}))
+
+@Form.create()
+class Add extends React.PureComponent {
+  state = {
+    content: '',
+    enabled: false,
+    showTest: false, // 是否展示测试内容
+    testContent: '', // 测试数据
+    testResult: '' // 测试结果
+  }
+
+  create = () => {
+    this.props.form.validateFields((err, values) => {
+      if (!err) {
+        create({
+          ...values,
+          createUser: this.props.currentUser.name, // 创建人
+          updateUser: this.props.currentUser.name // 最后修改人
+        }).then(res => {
+          if (res.code === 0) {
+            this.setState({ ...values })
+            Modal.success({
+              title: '提交成功',
+              content: '策略代码编译正常,点击“测试按钮”可以继续测试策略逻辑'
+            })
+          }
+        })
+      }
+    })
+  }
+
+  test =() => {
+    if (!this.state.name) {
+      message.warn('请先提交策略内容!')
+      return false
+    }
+    test({
+      name: this.state.name,
+      input: JSON.parse(this.state.testContent)
+    }).then(res => {
+      if (res.code === 0) {
+        this.setState({ testResult: JSON.stringify(res) })
+      }
+    })
+  }
+
+  render () {
+    const { getFieldDecorator } = this.props.form
+
+    return (
+      <div>
+        <h1>新增策略</h1>
+        <Row>
+          <Col span={12}>
+            <Form {...formItemLayout}>
+              <Form.Item label="策略名称">
+                {getFieldDecorator('name')(<Input placeholder="全英文或英文带下划线" />)}
+              </Form.Item>
+              <Form.Item label="策略描述">
+                {getFieldDecorator('description')(<Input.TextArea placeholder="多行输入" />)}
+              </Form.Item>
+              <Form.Item label="是否启用">
+                {getFieldDecorator('enabled', {
+                  initialValue: this.state.enabled
+                })(<Switch checked={this.state.enabled} onChange={checked => this.setState({ enabled: checked })} />)}
+              </Form.Item>
+              <Form.Item label="策略逻辑开发">
+                {getFieldDecorator('content')(
+                  <AceEditor
+                    style={{ width: this.state.showTest ? '100%' : '200%' }}
+                    mode="java"
+                    theme="monokai"
+                    name="content"
+                    onChange={(value) => this.setState({ content: value })}
+                    fontSize={14}
+                    showPrintMargin={true}
+                    showGutter={true}
+                    highlightActiveLine={true}
+                    value={''}
+                    setOptions={{
+                      enableBasicAutocompletion: true,
+                      enableLiveAutocompletion: true,
+                      enableSnippets: true,
+                      showLineNumbers: true,
+                      tabSize: 2
+                    }}
+                  />
+                )}
+              </Form.Item>
+              <Form.Item>
+                <Button type="primary" onClick={this.create}>提交</Button>&emsp;
+                <Button onClick={() => this.setState({ showTest: true })}>测试</Button>
+              </Form.Item>
+            </Form>
+          </Col>
+          <Col span={12}>
+            <div style={{ paddingLeft: '20px', display: this.state.showTest ? 'block' : 'none' }}>
+              <Form.Item label="输入数据">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  onChange={(value) => this.setState({ testContent: value })}
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testContent}
+                  height="300px"
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+
+              <Button type="primary" onClick={this.test}>执行测试</Button>&emsp;
+              <Form.Item label="输出结果">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testResult}
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+            </div>
+
+          </Col>
+        </Row>
+
+      </div>
+    )
+  }
+}
+
+export default Add

+ 182 - 0
src/pages/fengkong/strategies/edit/$name.js

@@ -0,0 +1,182 @@
+import React from 'react'
+import { Form, Input, Row, Col, Switch, Button, Modal, message } from 'antd'
+import { connect } from 'dva'
+import AceEditor from 'react-ace'
+import { detail, test, update } from '../service'
+import { isJSON } from '@/utils/utils'
+
+import 'ace-builds/src-noconflict/mode-java'
+import 'ace-builds/src-noconflict/theme-monokai'
+
+const formItemLayout = {
+  layout: 'vertical'
+}
+
+@connect(({ user }) => ({
+  currentUser: user.currentUser
+}))
+@Form.create()
+class Add extends React.PureComponent {
+  state = {
+    content: '',
+    showTest: false, // 是否展示测试内容
+    testContent: '', // 测试数据
+    testResult: '' // 测试结果
+  }
+
+  componentDidMount () {
+    detail({
+      name: this.props.match.params.name
+    }).then(res => {
+      if (res.code === 0) {
+        this.setState({ ...res.data })
+      }
+    })
+  }
+
+  create = () => {
+    this.props.form.validateFields((err, values) => {
+      if (!err) {
+        update({
+          ...values,
+          content: this.state.content,
+          createUser: this.state.createUser || this.props.currentUser.name, // 创建人
+          updateUser: this.props.currentUser.name // 最后修改人
+        }).then(res => {
+          if (res.code === 0) {
+            this.setState({ ...values })
+            Modal.success({
+              title: '提交成功',
+              content: '策略代码编译正常,点击“测试按钮”可以继续测试策略逻辑'
+            })
+          }
+        })
+      }
+    })
+  }
+
+  test =(id) => {
+    if (!this.state.name) {
+      message.warn('请先提交策略内容!')
+      return false
+    }
+    if (!isJSON(this.state.testContent)) {
+      message.warn('输入数据格式错误!')
+      return false
+    }
+    test({
+      name: this.state.name,
+      input: JSON.parse(this.state.testContent)
+    }).then(res => {
+      if (res.code === 0) {
+        console.log(res)
+        this.setState({ testResult: JSON.stringify(res) })
+      }
+    })
+  }
+
+  render () {
+    const { getFieldDecorator } = this.props.form
+    const { name, description, enabled, content } = this.state
+    return (
+      <div>
+        <h1>编辑策略</h1>
+        <Row>
+          <Col span={12}>
+            <Form {...formItemLayout}>
+              <Form.Item label="策略名称">
+                {getFieldDecorator('name', {
+                  initialValue: name
+                })(<Input placeholder="全英文或英文带下划线" />)}
+              </Form.Item>
+              <Form.Item label="策略描述">
+                {getFieldDecorator('description', {
+                  initialValue: description
+                })(<Input.TextArea placeholder="多行输入" />)}
+              </Form.Item>
+              <Form.Item label="是否启用">
+                {getFieldDecorator('enabled', {
+                  initialValue: enabled
+                })(<Switch checked={enabled} onChange={checked => this.setState({ enabled: checked })} />)}
+              </Form.Item>
+              <Form.Item label="策略逻辑开发">
+
+                <AceEditor
+                  style={{ width: this.state.showTest ? '100%' : '200%' }}
+                  mode="java"
+                  theme="monokai"
+                  name="content"
+                  onChange={(value) => this.setState({ content: value })}
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={content}
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+              <Form.Item>
+                <Button type="primary" onClick={this.create}>提交</Button>&emsp;
+                <Button onClick={() => this.setState({ showTest: true })}>测试</Button>
+              </Form.Item>
+            </Form>
+          </Col>
+          <Col span={12}>
+            <div style={{ paddingLeft: '20px', display: this.state.showTest ? 'block' : 'none' }}>
+              <Form.Item label="输入数据">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  onChange={(value) => this.setState({ testContent: value })}
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testContent}
+                  height="300px"
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+
+              <Button type="primary" onClick={this.test}>执行测试</Button>&emsp;
+              <Form.Item label="输出结果">
+                <AceEditor
+                  mode="json"
+                  theme="monokai"
+                  fontSize={14}
+                  showPrintMargin={true}
+                  showGutter={true}
+                  highlightActiveLine={true}
+                  value={this.state.testResult}
+                  setOptions={{
+                    enableBasicAutocompletion: true,
+                    enableLiveAutocompletion: true,
+                    enableSnippets: true,
+                    showLineNumbers: true,
+                    tabSize: 2
+                  }}
+                />
+              </Form.Item>
+            </div>
+
+          </Col>
+        </Row>
+
+      </div>
+    )
+  }
+}
+
+export default Add

+ 31 - 0
src/pages/fengkong/strategies/service.js

@@ -0,0 +1,31 @@
+import { fetchApi, fetchApi_get as fetchApiGet } from '@/apis/'
+import { thanos } from '@/conf/config'
+
+// 新增策略
+export async function create (params) {
+  const url = `${thanos}/thanos-admin/api/v1/dsl/create`
+  return fetchApi(url, params)
+}
+
+// 测试策略
+export async function test (params) {
+  const url = `${thanos}/thanos-admin//api/v1/dsl/test`
+  return fetchApi(url, params)
+}
+
+// 获取策略详情
+export async function detail (params) {
+  const url = `${thanos}/thanos-admin/api/v1/dsl/query`
+  return fetchApiGet(url, params)
+}
+
+// 更新
+export async function update (params) {
+  const url = `${thanos}/thanos-admin/api/v1/dsl/update`
+  return fetchApi(url, params)
+}
+
+export async function delItem (params) {
+  const url = `${thanos}/thanos-admin/api/v1/dsl/delete`
+  return fetchApi(url, params)
+}

+ 136 - 0
src/pages/fengkong/strategies/strategies.js

@@ -0,0 +1,136 @@
+import React from 'react'
+import { FilterTable } from 'wptpc-design'
+import { Link } from 'dva/router'
+import { thanos } from '@/conf/config'
+import { Divider, message, Popconfirm, Button } from 'antd'
+import { delItem } from './service.js'
+
+const apiUrl = `${thanos}/thanos-admin/api/v1/dsl/list`
+
+class GroupList extends React.PureComponent {
+  state = {
+    showModal: false,
+    params: {}
+  }
+
+  filterSetting = {
+    rfBtnsJsx: <Link
+      to={{
+        pathname: './add'
+      }}
+    ><Button>新增策略</Button></Link>,
+    isClearSearch: true,
+    formFields: [
+      {
+        label: '描述:',
+        type: 'input',
+        key: 'queryName',
+        placeholder: '分组名称'
+      }
+    ]
+    // 在接口请求前,可以修改给接口的入参
+    // beforeSearchFunc: params => {
+    //   params.pageNum = params.pageNum
+    // }
+  }
+
+  // filtertable的列表配置
+  tableSetting = {
+    rowKey: 'id',
+    // isFrontPagination: true,
+    pagination: {
+      pageSize: 10
+    },
+    columnConfig: [
+      {
+        title: 'ID',
+        dataIndex: 'id'
+      },
+      {
+        title: '分组名称',
+        dataIndex: 'name'
+      },
+      {
+        title: '描述',
+        dataIndex: 'description'
+      },
+      {
+        title: '策略是否启用',
+        dataIndex: 'enabled',
+        render: (text) => text === true ? '是' : '否'
+      },
+      {
+        title: '创建人',
+        dataIndex: 'createUser'
+      },
+      {
+        title: '修改人',
+        dataIndex: 'updateUser'
+      },
+      {
+        title: '操作',
+        dataIndex: 'actions',
+        // 所有需要弹窗操作的都可以用编辑的逻辑;所有不需要弹窗的操作,比如上架、发布等,都可以用”删除“的逻辑
+        render: (text, record) => (
+          <span>
+            <Link
+              to={{
+                pathname: './edit/' + record.name,
+                state: record
+              }}
+            >编辑</Link>
+            <Divider type="vertical"/>
+            <Popconfirm
+              title="确定删除"
+              onConfirm={() => this.delItem(record)}>
+              <a>删除</a>
+            </Popconfirm>
+          </span>)
+      }
+    ],
+    getRefresh: refresh => {
+      this.refresh = refresh
+    }
+  }
+
+  // 点击编辑按钮时的事件处理函数
+  editItem (record) {
+    console.log('11111111=')
+    // const fields = JSON.parse(record.fieldsJson)
+    // console.log('=====', fields)
+    const { fields } = record
+    const fieldsJson = Object.keys(fields).map(f => ({
+      key: f,
+      desc: fields[f].desc,
+      column: fields[f].column
+    }))
+    console.log(fieldsJson)
+    this.setState({
+      showModal: true,
+      params: {
+        ...record,
+        fieldsJson
+      }
+    })
+  }
+  // 点击删除按钮时的事件处理函数
+  delItem = (record) => {
+    delItem({ id: record.id, name: record.name }).then(res => {
+      if (res.code === 0) {
+        message.success('删除成功')
+        this.refresh()
+      }
+    })
+  }
+
+  render () {
+    return (
+      <div>
+        <FilterTable filterSetting={this.filterSetting} tableSetting={this.tableSetting} apiUrl={apiUrl}
+        />
+      </div>
+    )
+  }
+}
+
+export default GroupList

+ 17 - 5
src/utils/utils.js

@@ -1,6 +1,18 @@
-export function arrayToObj(arr) {
+export function arrayToObj (arr) {
   return arr.reduce((t, c) => {
-    t[c.value] = c.label;
-    return t;
-  }, {});
-}
+    t[c.value] = c.label
+    return t
+  }, {})
+}
+
+export function isJSON (str) {
+  if (typeof str === 'string') {
+    try {
+      JSON.parse(str)
+      return true
+    } catch (e) {
+      console.log(e)
+      return false
+    }
+  }
+}