mirror of
https://gitee.com/freshday/radar.git
synced 2026-03-22 04:37:16 +08:00
15
webapp/component/App.jsx
Normal file
15
webapp/component/App.jsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
export default class App extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
48
webapp/component/Index.jsx
Normal file
48
webapp/component/Index.jsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import {Menu,Breadcrumb,Icon,Tooltip} from 'antd';
|
||||
const SubMenu = Menu.SubMenu;
|
||||
import './Index.less';
|
||||
import {FetchUtil} from './utils/fetchUtil';
|
||||
|
||||
export default class Index extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
}
|
||||
|
||||
handleLogout=()=>{
|
||||
FetchUtil('/merchant/logout','GET','',
|
||||
(data) => {
|
||||
window.location.href="#/login";
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return (
|
||||
|
||||
|
||||
<div className="ant-layout-ceiling-demo">
|
||||
<div className="ant-layout-header">
|
||||
<div className="ant-layout-wrapper">
|
||||
<div className="ant-layout-logo">
|
||||
<Tooltip title="回到首页"><Link to="/modelList"><Icon type="home" /></Link></Tooltip>
|
||||
</div>
|
||||
<div className="ant-layout-logo">
|
||||
<Tooltip title="统计报表"><Link to="/report"><Icon type="line-chart" /></Link></Tooltip>
|
||||
</div>
|
||||
<div className="ant-layout-logo" style={{float:"right",marginRight:0}}>
|
||||
<Tooltip title="退出登录"><a onClick={this.handleLogout}><Icon type="logout" /></a></Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ant-layout-main">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
69
webapp/component/Index.less
Normal file
69
webapp/component/Index.less
Normal file
@@ -0,0 +1,69 @@
|
||||
.ant-layout-ceiling-demo {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling {
|
||||
font-size: 12px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background-color: #242736;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling .right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling ul li {
|
||||
display: inline-block;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling-demo .ant-layout-wrapper {
|
||||
padding: 0 50px;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling-demo .ant-layout-header {
|
||||
background: #fff;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.ant-layout-ceiling-demo .ant-layout-logo {
|
||||
width:36px;
|
||||
height: 32px;
|
||||
border-radius: 6px;
|
||||
margin: 16px 28px 16px 0;
|
||||
float: left;
|
||||
font-size: 26px;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.ant-layout-wrapper {
|
||||
padding: 0 50px;
|
||||
}
|
||||
|
||||
.ant-layout-breadcrumb {
|
||||
margin: 7px 0 -17px 24px;
|
||||
}
|
||||
|
||||
.ant-layout-container {
|
||||
background: #fff;
|
||||
margin: 24px 0;
|
||||
position: relative;
|
||||
padding-top: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ant-layout-content {
|
||||
background: #fff;
|
||||
padding:0 24px 24px;
|
||||
}
|
||||
|
||||
.ant-divider {
|
||||
margin: 0 4px;
|
||||
color: #999;
|
||||
display: inline-block;
|
||||
height: 8px;
|
||||
width: 1px;
|
||||
background: #ccc;
|
||||
}
|
||||
138
webapp/component/Login.jsx
Normal file
138
webapp/component/Login.jsx
Normal file
@@ -0,0 +1,138 @@
|
||||
import React from 'react';
|
||||
import {Card,Form,Input,Button,Icon,Alert,Col,message} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
import './Login.less';
|
||||
import {fetchVersion} from './utils/fetchUtil';
|
||||
import {trim} from './utils/validateUtil';
|
||||
|
||||
export default class Login extends React.Component{
|
||||
|
||||
state={
|
||||
username:'',
|
||||
password:'',
|
||||
captcha:'',
|
||||
rd:Math.random(),
|
||||
|
||||
showMsg:false,
|
||||
msg:''
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleLogin=()=>{
|
||||
if(!this.state.username){
|
||||
this.setState({
|
||||
showMsg:true,
|
||||
msg:'请输入用户名'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if(!this.state.password){
|
||||
this.setState({
|
||||
showMsg:true,
|
||||
msg:'请输入密码'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if(!this.state.captcha){
|
||||
this.setState({
|
||||
showMsg:true,
|
||||
msg:'请输入验证码'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
let formData = new FormData();
|
||||
formData.append("loginName",this.state.username);
|
||||
formData.append("passwd",this.state.password);
|
||||
formData.append("captcha",this.state.captcha);
|
||||
const hide = message.loading('正在执行中...', 0);
|
||||
fetch(fetchVersion+'/merchant/login',{credentials: 'include',method: 'POST',
|
||||
body:formData})
|
||||
.then((res) => {
|
||||
hide();
|
||||
if(res.ok){
|
||||
return res.json();
|
||||
}
|
||||
else{
|
||||
Modal.error({
|
||||
title: '系统错误',
|
||||
content: '请检查是否有参数配置错误',
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((data)=>{
|
||||
if(data.success){
|
||||
window.location.href="#/modelList";
|
||||
}
|
||||
else{
|
||||
this.refs.captcha.click();
|
||||
this.setState({
|
||||
msg:data.msg,
|
||||
showMsg:true
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e.message);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
handleClick=(event)=>{
|
||||
this.setState({
|
||||
rd:Math.random()
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown=(event)=>{
|
||||
if(event.keyCode==13){
|
||||
this.handleLogin();
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 7 },
|
||||
wrapperCol: { span: 13 },
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="middleBox" onKeyDown={this.handleKeyDown}>
|
||||
<Card>
|
||||
<h2 style={{textAlign:"center",paddingBottom:10,borderBottom:"1px dashed #ececec"}}><Icon type="lock" /> 反欺诈系统管理平台</h2>
|
||||
<Form horizontal style={{marginTop:30}}>
|
||||
<FormItem {...formItemLayout} label="用户名">
|
||||
<Input size="large" type="text" name="username" value={this.state.username} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="密码">
|
||||
<Input type="password" name="password" value={this.state.password} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="验证码" style={{marginBottom:12}}>
|
||||
<Col span="8">
|
||||
<Input style={{width:60}} size="large" type="text" name="captcha" value={this.state.captcha} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<span><img id="captcha" ref="captcha" src={fetchVersion+"/common/getCaptcha?"+this.state.rd} onClick={this.handleClick}/> </span>
|
||||
</Col>
|
||||
</FormItem>
|
||||
|
||||
<FormItem wrapperCol={{ span: 13, offset: 7 }}>
|
||||
<div style={this.state.showMsg?{display:"block"}:{display:"none"}}><Alert message={this.state.msg} type="error" /></div>
|
||||
<Button type="primary" onClick={this.handleLogin}>登录</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
10
webapp/component/Login.less
Normal file
10
webapp/component/Login.less
Normal file
@@ -0,0 +1,10 @@
|
||||
.middleBox{
|
||||
width:440px;
|
||||
margin:0 auto;
|
||||
padding-top:200px;
|
||||
}
|
||||
|
||||
#captcha{
|
||||
cursor:pointer;
|
||||
|
||||
}
|
||||
405
webapp/component/abstraction/Abstraction.jsx
Normal file
405
webapp/component/abstraction/Abstraction.jsx
Normal file
@@ -0,0 +1,405 @@
|
||||
import React from 'react';
|
||||
|
||||
import {Form,Input,Breadcrumb,Row,Col,Icon,Card,Select,Button,Cascader,Tooltip,message,Modal} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const OptGroup = Select.OptGroup;
|
||||
|
||||
import './Abstraction.less';
|
||||
|
||||
import ComplexCondition from './ComplexCondition';
|
||||
|
||||
import {generateScript,validateRules} from '../utils/groovyUtil';
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class Abstraction extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
if(props.abstraction!=undefined){
|
||||
const abstraction=props.abstraction;
|
||||
|
||||
this.state={
|
||||
name:abstraction.name,
|
||||
label:abstraction.label,
|
||||
aggregateType:abstraction.aggregateType+'',
|
||||
searchField:abstraction.searchField,
|
||||
searchIntervalType:abstraction.searchIntervalType+'',
|
||||
searchIntervalValue:abstraction.searchIntervalValue,
|
||||
functionField:abstraction.functionField,
|
||||
comment:abstraction.comment,
|
||||
ruleDefinition:abstraction.ruleDefinition==undefined?null:JSON.parse(abstraction.ruleDefinition),
|
||||
ruleScript:abstraction.ruleScript
|
||||
}
|
||||
}
|
||||
else{
|
||||
this.state={
|
||||
name:'',
|
||||
label:'',
|
||||
aggregateType:'',
|
||||
searchField:'',
|
||||
searchIntervalType:'',
|
||||
searchIntervalValue:'',
|
||||
functionField:'',
|
||||
comment:'',
|
||||
ruleDefinition:null,
|
||||
ruleScript:''
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
if(this.props.abstraction.id!=0){
|
||||
param.id=this.props.abstraction.id;
|
||||
}
|
||||
if(!this.state.ruleDefinition){
|
||||
let fieldList=this.props.fieldList;
|
||||
let fieldArr=this.state.searchField.split('.');
|
||||
let fieldType='STRING';
|
||||
for(let i=0;i<fieldList.length;i++){
|
||||
if(fieldList[i].value==fieldArr[0]){
|
||||
for(let j=0;j<fieldList[i].children.length;j++){
|
||||
if(fieldList[i].children[j].value==fieldArr[1]){
|
||||
if(fieldArr.length==2){
|
||||
fieldType=fieldList[i].children[j].type;
|
||||
}
|
||||
else{
|
||||
for(let k=0;k<fieldList[i].children[j].children.length;k++){
|
||||
if(fieldList[i].children[j].children[k].value==fieldArr[2]){
|
||||
fieldType=fieldList[i].children[j].children[k].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.state.ruleDefinition={
|
||||
"linking":"All",
|
||||
"conditions":[
|
||||
{
|
||||
"class":"SMPL",
|
||||
"expressions":[
|
||||
{
|
||||
"column":this.state.searchField,
|
||||
"type":fieldType,
|
||||
"class":"ENTATTR"
|
||||
}],
|
||||
"enabled":true,
|
||||
"operator":"IsNotNull"
|
||||
}],
|
||||
"class":"PDCT",
|
||||
"enabled":true
|
||||
}
|
||||
}
|
||||
if(!validateRules(this.state.ruleDefinition)){
|
||||
Modal.error({
|
||||
title:'请检查过滤条件是否配置完整'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
param.modelId=this.props.modelId;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
param.aggregateType=this.state.aggregateType;
|
||||
param.searchField=this.state.searchField;
|
||||
param.searchIntervalType=this.state.searchIntervalType;
|
||||
param.searchIntervalValue=this.state.searchIntervalValue;
|
||||
param.functionField=this.state.functionField;
|
||||
param.comment=this.state.comment;
|
||||
param.ruleDefinition=this.state.ruleDefinition;
|
||||
param.ruleScript=generateScript(this.state.ruleDefinition,"Abstraction");
|
||||
param.status=1;
|
||||
|
||||
FetchUtil('/abstraction/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success==true){
|
||||
message.success('保存成功!');
|
||||
}
|
||||
else{
|
||||
message.error('保存失败!');
|
||||
}
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
displayRender = (labels, selectedOptions) => labels.map((label, i) => {
|
||||
const option = selectedOptions[i];
|
||||
if (i === labels.length - 1) {
|
||||
return (
|
||||
<span key={option.value+i}>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return <span key={option.value+i}>{label} / </span>;
|
||||
});
|
||||
|
||||
handleCascader=(name,value,selectedOptions)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value.join('.'));
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleChangeCondition=(condition,index)=>{
|
||||
let ruleDefinition=this.state.ruleDefinition;
|
||||
|
||||
if(condition==null){
|
||||
ruleDefinition=null;
|
||||
}
|
||||
else{
|
||||
ruleDefinition=condition;
|
||||
}
|
||||
this.setState({
|
||||
ruleDefinition:ruleDefinition
|
||||
})
|
||||
}
|
||||
|
||||
handleAddCondition=()=>{
|
||||
let ruleDefinition=this.state.ruleDefinition;
|
||||
|
||||
if(ruleDefinition==null){
|
||||
ruleDefinition={
|
||||
"class": "PDCT",
|
||||
"enabled": true,
|
||||
"linking": "All",
|
||||
"conditions": [
|
||||
{
|
||||
"class": "SMPL",
|
||||
"enabled": true,
|
||||
"operator": "",
|
||||
"expressions": [
|
||||
{
|
||||
"class": "ENTATTR",
|
||||
"type": "",
|
||||
"column": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
else{
|
||||
ruleDefinition.conditions.push(
|
||||
{
|
||||
"class": "SMPL",
|
||||
"enabled": true,
|
||||
"operator": "",
|
||||
"expressions": [
|
||||
{
|
||||
"class": "ENTATTR",
|
||||
"type": "",
|
||||
"column": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
ruleDefinition:ruleDefinition
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
|
||||
let ruleDefinition=this.state.ruleDefinition;
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
aggregateType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
searchField:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
searchInterval:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入指标名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的指标名';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.aggregateType){
|
||||
validate.aggregateType.help='请选择聚合条件';
|
||||
validate.aggregateType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.searchField){
|
||||
validate.searchField.help='请输入搜索字段';
|
||||
validate.searchField.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.searchIntervalValue){
|
||||
validate.searchInterval.help='请输入时间片';
|
||||
validate.searchInterval.status='warning';
|
||||
isValidated=false;
|
||||
}else if(!/^[0-9]+$/.test(this.state.searchIntervalValue)){
|
||||
validate.searchInterval.help='时间片必须为数字';
|
||||
validate.searchInterval.status='error';
|
||||
isValidated=false;
|
||||
}else if(!this.state.searchIntervalType){
|
||||
validate.searchInterval.help='请选择时间单位';
|
||||
validate.searchInterval.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{width:750}}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="指标名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'指标显示名称,一般为中文,如"100秒内设备注册数"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="聚合条件:" help={validate.aggregateType.help} validateStatus={validate.aggregateType.status}>
|
||||
<Select value={this.state.aggregateType} onChange={this.handleSelect.bind(this,'aggregateType')}>
|
||||
<Option value="">请选择</Option>
|
||||
<Option value="1">求总数</Option>
|
||||
<Option value="2">求不同项总数</Option>
|
||||
<Option value="3">求和</Option>
|
||||
<Option value="4">求平均值</Option>
|
||||
<Option value="5">求最大值</Option>
|
||||
<Option value="6">求最小值</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="搜索字段:" help={validate.searchField.help} validateStatus={validate.searchField.status}>
|
||||
<Cascader
|
||||
title={this.state.searchField.split(".")}
|
||||
options={this.props.fieldList}
|
||||
allowClear={false}
|
||||
value={this.state.searchField.split(".")}
|
||||
displayRender={this.displayRender}
|
||||
onChange={this.handleCascader.bind(this,'searchField')}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="统计字段:">
|
||||
<Cascader
|
||||
title={this.state.functionField.split(".")}
|
||||
options={this.props.fieldList}
|
||||
allowClear={false}
|
||||
value={this.state.functionField.split(".")}
|
||||
displayRender={this.displayRender}
|
||||
onChange={this.handleCascader.bind(this,'functionField')}
|
||||
/>
|
||||
|
||||
<Button style={{marginTop:10}} onClick={()=>{this.setState({functionField:''})}}>清空统计字段</Button>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="时间片:" help={validate.searchInterval.help} validateStatus={validate.searchInterval.status}>
|
||||
<Row>
|
||||
<Col span={4} style={{marginTop:1}}>
|
||||
<Input type="text" name="searchIntervalValue" value={this.state.searchIntervalValue} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={4} offset={1}>
|
||||
<Select value={this.state.searchIntervalType} onChange={this.handleSelect.bind(this,'searchIntervalType')}>
|
||||
<Option value="">请选择</Option>
|
||||
<Option value="1">年</Option>
|
||||
<Option value="2">月</Option>
|
||||
<Option value="5">日</Option>
|
||||
<Option value="11">时</Option>
|
||||
<Option value="12">分</Option>
|
||||
<Option value="13">秒</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'搜索某段时间的数据,数值为正数,代表范围区间,如 3 ,再配合后面的时间单位,如 月,就表示3个月内的数据'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="备注:">
|
||||
<Input type="textarea" name="comment" value={this.state.comment} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<Row>
|
||||
<Col span={4} offset={4}>
|
||||
<Tooltip title="添加过滤条件" onClick={this.handleAddCondition}><span className="addRule"><Icon type="plus" /> 添加过滤条件</span></Tooltip>
|
||||
<br/>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<ComplexCondition fieldList={this.props.fieldList} dataList={this.props.dataList} condition={this.state.ruleDefinition} changeParentCondition={this.handleChangeCondition} index={0}/>
|
||||
|
||||
<div className="separate"></div>
|
||||
<Row>
|
||||
<Col span={4} offset={4}>
|
||||
<Button type="primary" onClick={this.handleSubmit.bind(this,isValidated)}>保存</Button>{' '}
|
||||
<Button type="primary" onClick={this.props.delete}>删除</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
22
webapp/component/abstraction/Abstraction.less
Normal file
22
webapp/component/abstraction/Abstraction.less
Normal file
@@ -0,0 +1,22 @@
|
||||
.addRule{
|
||||
color:rgb(102, 102, 102);
|
||||
cursor:pointer;
|
||||
font-size:16px;
|
||||
}
|
||||
|
||||
.addRule:hover{
|
||||
color:black;
|
||||
}
|
||||
|
||||
.separate{
|
||||
width:100%;
|
||||
height:0;
|
||||
border-bottom:rgb(102, 102, 102) 1px dashed;
|
||||
margin-top:5px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.condition-row{
|
||||
height:26px;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
191
webapp/component/abstraction/AbstractionList.jsx
Normal file
191
webapp/component/abstraction/AbstractionList.jsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import React,{Component} from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Spin} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import CollapseGroup from '../common/CollapseGroup';
|
||||
import Collapse from '../common/Collapse';
|
||||
|
||||
import Abstraction from './Abstraction';
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
|
||||
export default class AbstractionList extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
name:'',
|
||||
label:'',
|
||||
status:"1",
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null,
|
||||
fieldList:[],
|
||||
dataList:[],
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.params.id;
|
||||
param.aggregateType=this.state.aggregateType;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/abstraction','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = value;
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleAdd=()=>{
|
||||
let tData=this.state.tData;
|
||||
|
||||
tData.push({
|
||||
id:0,
|
||||
name:'',
|
||||
label:'',
|
||||
aggregateType:'',
|
||||
searchField:'',
|
||||
searchIntervalType:'',
|
||||
searchIntervalValue:'',
|
||||
functionField:'',
|
||||
comment:'',
|
||||
ruleDefinition:null,
|
||||
ruleScript:''
|
||||
});
|
||||
|
||||
this.setState({
|
||||
tData:tData
|
||||
})
|
||||
}
|
||||
|
||||
handleDelete=(index)=>{
|
||||
let tData=this.state.tData;
|
||||
let id=tData[index].id;
|
||||
if(id!=0){
|
||||
FetchUtil('/abstraction/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
if(data.success==true){
|
||||
message.success('删除成功!');
|
||||
}
|
||||
else{
|
||||
message.error('删除失败!');
|
||||
}
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
else{
|
||||
tData.splice(index,1);
|
||||
this.setState({
|
||||
tData:tData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
|
||||
FetchUtil('/abstraction/datacolumns/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldList:data.data.list
|
||||
});
|
||||
});
|
||||
FetchUtil('/datalist/list/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
dataList:data.data.list
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="指标名:">
|
||||
<Input value={this.state.name} name="name" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<Button type="primary" onClick={this.handleAdd}>新增</Button>
|
||||
</Form>
|
||||
</div>
|
||||
<Spin size="large" spinning={this.state.loading}>
|
||||
<CollapseGroup>
|
||||
{this.state.tData.filter((info,index)=>{
|
||||
if(this.state.name){
|
||||
var reg = new RegExp('('+ this.state.name+')','gi');
|
||||
return reg.test(info.label);
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}).map((info,index)=>{
|
||||
return (<Collapse key={info.id+""+index} title={info.label?info.label:'新增(请保存)'}>
|
||||
<Abstraction abstraction={info} modelId={this.props.params.id} fieldList={this.state.fieldList} dataList={this.state.dataList} reload={this.fetchTableData} delete={this.handleDelete.bind(this,index)}/>
|
||||
</Collapse>);
|
||||
})
|
||||
}
|
||||
|
||||
</CollapseGroup>
|
||||
</Spin>
|
||||
|
||||
<div>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
126
webapp/component/abstraction/ComplexCondition.jsx
Normal file
126
webapp/component/abstraction/ComplexCondition.jsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import React from 'react';
|
||||
|
||||
import {Form,Input,Row,Col,Card,Select,Button,Cascader,Tooltip,Icon} from 'antd';
|
||||
|
||||
const Option = Select.Option;
|
||||
|
||||
import SimpleCondition from './SimpleCondition';
|
||||
|
||||
export default class ComplexCondition extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
condition.linking=value;
|
||||
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleChangeCondition=(childCondition,childIndex)=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
|
||||
if(childCondition==null){
|
||||
condition.conditions.splice(childIndex,1);
|
||||
}
|
||||
else{
|
||||
condition.conditions[childIndex]=childCondition;
|
||||
}
|
||||
|
||||
if(condition.conditions.length==0){
|
||||
this.props.changeParentCondition(null,index);
|
||||
}
|
||||
else{
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
}
|
||||
|
||||
handleSimpleCondition=()=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
|
||||
condition.conditions.push(
|
||||
{
|
||||
"class": "SMPL",
|
||||
"enabled": true,
|
||||
"operator": "",
|
||||
"expressions": [
|
||||
{
|
||||
"class": "ENTATTR",
|
||||
"type": "STRING",
|
||||
"column": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleComplexCondition=()=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
|
||||
condition.conditions.push(
|
||||
{
|
||||
"class": "PDCT",
|
||||
"enabled": true,
|
||||
"linking": "All",
|
||||
"conditions": [
|
||||
{
|
||||
"class": "SMPL",
|
||||
"enabled": true,
|
||||
"operator": "",
|
||||
"expressions": [
|
||||
{
|
||||
"class": "ENTATTR",
|
||||
"type": "STRING",
|
||||
"column": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
render(){
|
||||
if(this.props.condition==null){
|
||||
return (<div/>);
|
||||
}
|
||||
else{
|
||||
return (
|
||||
<div style={{marginLeft:20}}>
|
||||
<div className="condition-row">
|
||||
<Select style={{width:100}} readOnly={this.props.readOnly} value={this.props.condition.linking} defaultValue={'All'} onChange={this.handleSelect.bind(this,'linking')}>
|
||||
<Option value="All">All</Option>
|
||||
<Option value="Any">Any</Option>
|
||||
<Option value="NotAll">NotAll</Option>
|
||||
<Option value="None">None</Option>
|
||||
</Select>条件成立
|
||||
{this.props.readOnly!=true?<Tooltip title="添加简单条件" onClick={this.handleSimpleCondition}><span style={{cursor:"pointer",marginRight:"10px"}}><Icon type="plus" />简单</span></Tooltip>:''}
|
||||
{this.props.readOnly!=true?<Tooltip title="添加复杂条件" onClick={this.handleComplexCondition}><span style={{cursor:"pointer"}}><Icon type="plus" />复杂</span></Tooltip>:''}
|
||||
</div>
|
||||
{this.props.condition.conditions.map((info,index)=>{
|
||||
if(info.class=='SMPL'){
|
||||
return (
|
||||
<SimpleCondition key={index} readOnly={this.props.readOnly} fieldList={this.props.fieldList} dataList={this.props.dataList} condition={info} changeParentCondition={this.handleChangeCondition} index={index} />
|
||||
);
|
||||
}
|
||||
else{
|
||||
return (
|
||||
<ComplexCondition key={index} readOnly={this.props.readOnly} fieldList={this.props.fieldList} dataList={this.props.dataList} condition={info} changeParentCondition={this.handleChangeCondition} index={index}/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
166
webapp/component/abstraction/SimpleCondition.jsx
Normal file
166
webapp/component/abstraction/SimpleCondition.jsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import React from 'react';
|
||||
|
||||
import {Form,Input,Row,Col,Card,Select,Button,Cascader,Tooltip,Icon} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const OptGroup = Select.OptGroup;
|
||||
|
||||
import {Operator,operatorMap} from '../utils/operatorUtil';
|
||||
|
||||
export default class SimpleCondition extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
handleConditionColumn=(name,value,selectedOptions)=>{
|
||||
let type=selectedOptions[selectedOptions.length-1].type;
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
if(name=='expression'){
|
||||
condition.operator='';
|
||||
condition.expressions=condition.expressions.slice(0,1);
|
||||
condition.expressions[0]={
|
||||
class: "ENTATTR",
|
||||
type: type,
|
||||
column: value.join('.')
|
||||
}
|
||||
}
|
||||
else if(name=='expressionOption'){
|
||||
if(condition.expressions.length<=1){
|
||||
condition.expressions.push({
|
||||
class: "ENTATTR",
|
||||
type: type,
|
||||
column: value.join('.')
|
||||
})
|
||||
}
|
||||
else{
|
||||
condition.expressions[1]={
|
||||
class: "ENTATTR",
|
||||
type: type,
|
||||
column: value.join('.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleOperator=(value)=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
|
||||
condition.operator=value;
|
||||
condition.expressions=condition.expressions.slice(0,1);
|
||||
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleDataList=(value)=>{
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
|
||||
if(condition.expressions.length<=1){
|
||||
condition.expressions.push({
|
||||
class: "CONST",
|
||||
type: "LIST",
|
||||
value: value
|
||||
})
|
||||
}
|
||||
else{
|
||||
condition.expressions[1]={
|
||||
class: "CONST",
|
||||
type: "LIST",
|
||||
value: value
|
||||
}
|
||||
}
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleInput=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
|
||||
let condition=this.props.condition;
|
||||
let index=this.props.index;
|
||||
const type=condition.expressions[0].type;
|
||||
if(condition.expressions.length<=1){
|
||||
condition.expressions.push({
|
||||
class: "CONST",
|
||||
type: type,
|
||||
value: value
|
||||
})
|
||||
}
|
||||
else{
|
||||
condition.expressions[1]={
|
||||
class: "CONST",
|
||||
type: type,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
this.props.changeParentCondition(condition,index);
|
||||
}
|
||||
|
||||
handleDelete=()=>{
|
||||
this.props.changeParentCondition(null,this.props.index);
|
||||
}
|
||||
|
||||
displayRender = (labels, selectedOptions) => labels.map((label, i) => {
|
||||
const option = selectedOptions[i];
|
||||
if (i === labels.length - 1) {
|
||||
return (
|
||||
<span key={option.value+i}>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return <span key={option.value+i}>{label} / </span>;
|
||||
})
|
||||
|
||||
render(){
|
||||
let condition=this.props.condition;
|
||||
let expression=condition.expressions[0];
|
||||
let expressionOption=condition.expressions[1];
|
||||
return (
|
||||
<div className="condition-row" style={{marginLeft:20}}>
|
||||
<Cascader
|
||||
options={this.props.fieldList}
|
||||
allowClear={false}
|
||||
value={expression.column.split('.')}
|
||||
displayRender={this.displayRender}
|
||||
onChange={this.handleConditionColumn.bind(this,'expression')}
|
||||
readOnly={this.props.readOnly}
|
||||
|
||||
/>
|
||||
<Select dropdownMatchSelectWidth={false} readOnly={this.props.readOnly} value={condition.operator} onChange={this.handleOperator}>
|
||||
{operatorMap[expression.type].map(op=>
|
||||
<Option key={op.value} value={op.value}>{op.label}</Option>
|
||||
)}
|
||||
</Select>
|
||||
{condition.operator==''?'':
|
||||
Operator[condition.operator].nextType=='input'?(
|
||||
<Input style={{width:200}} type="text" readOnly={this.props.readOnly} value={expressionOption==undefined?'':expressionOption.value} onChange={this.handleInput}/>):
|
||||
Operator[condition.operator].nextType=='list'?(
|
||||
<Select dropdownMatchSelectWidth={false} readOnly={this.props.readOnly} value={expressionOption==undefined?'':expressionOption.value} onChange={this.handleDataList}>
|
||||
{this.props.dataList.map(op=>
|
||||
<Option key={op.id} value={op.name}>{op.label}</Option>
|
||||
)}
|
||||
</Select>
|
||||
):
|
||||
Operator[condition.operator].nextType=='field'?(
|
||||
<Cascader
|
||||
options={this.props.fieldList}
|
||||
allowClear={false}
|
||||
value={expressionOption==undefined?'':expressionOption.column.split('.')}
|
||||
displayRender={this.displayRender}
|
||||
onChange={this.handleConditionColumn.bind(this,'expressionOption')}
|
||||
readOnly={this.props.readOnly}
|
||||
/>
|
||||
):''
|
||||
}
|
||||
{this.props.readOnly!=true?<Tooltip title="删除" onClick={this.handleDelete}><Icon type="delete" style={{fontSize:16,lineHeight:"22px"}}/></Tooltip>:''}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
171
webapp/component/activation/Activation.jsx
Normal file
171
webapp/component/activation/Activation.jsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
import AddActivation from './modal/AddActivation';
|
||||
import EditActivation from './modal/EditActivation';
|
||||
|
||||
export default class Activation extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
name:'',
|
||||
label:'',
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.params.id;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
|
||||
FetchUtil('/activation','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deleteActivation=(id)=>{
|
||||
FetchUtil('/activation/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
message.info('删除成功!');
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '策略名',
|
||||
dataIndex: 'label'
|
||||
},{
|
||||
title: '备注',
|
||||
dataIndex: 'comment'
|
||||
},{
|
||||
title: '警戒值',
|
||||
dataIndex: 'median'
|
||||
},{
|
||||
title: '拒绝值',
|
||||
dataIndex: 'high'
|
||||
},{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
<EditActivation modelId={this.props.params.id} row={r} reload={this.fetchTableData}/>
|
||||
<span className="ant-divider"></span>
|
||||
<Tooltip title="管理规则"><Link to={"/ruleList/"+r.modelId+"/"+r.id}>管理规则</Link></Tooltip>
|
||||
<span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该字段吗?'} onConfirm={this.deleteActivation.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="策略名:">
|
||||
<Input value={this.state.name} name="name" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<AddActivation modelId={this.props.params.id} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData.filter((item,index,array)=>{
|
||||
var reg = new RegExp('('+ this.state.name+')','gi');
|
||||
if(this.state.name){
|
||||
return (reg.test(item.label));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
144
webapp/component/activation/HistoryRecord.jsx
Normal file
144
webapp/component/activation/HistoryRecord.jsx
Normal file
@@ -0,0 +1,144 @@
|
||||
import React from 'react';
|
||||
|
||||
import {Form,Input,InputNumber,Breadcrumb,Row,Col,Icon,Card,Select,Button,Cascader,Tooltip,message,Modal} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import ComplexCondition from '../abstraction/ComplexCondition';
|
||||
|
||||
export default class HistoryRecord extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
height:40
|
||||
}
|
||||
}
|
||||
|
||||
slideDown=()=>{
|
||||
if(this.state.height=="auto"){
|
||||
return;
|
||||
}
|
||||
let height = this.refs.content1.offsetHeight+this.refs.content2.offsetHeight+40;
|
||||
if(this.state.height<height){
|
||||
this.setState({
|
||||
height:this.state.height+15
|
||||
},()=>{
|
||||
setTimeout(this.slideDown,1);
|
||||
})
|
||||
}else{
|
||||
this.setState({
|
||||
height:"auto"
|
||||
})
|
||||
this.refs.content.className = 'up'
|
||||
}
|
||||
}
|
||||
|
||||
slideUp=()=>{
|
||||
let height = this.refs.content1.offsetHeight+this.refs.content2.offsetHeight+40;
|
||||
if(this.state.height=="auto"){
|
||||
this.state.height=height;
|
||||
}
|
||||
if(this.state.height>55){
|
||||
this.setState({
|
||||
height:this.state.height-15
|
||||
},()=>{
|
||||
setTimeout(this.slideUp,1);
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:40
|
||||
})
|
||||
this.refs.content.className = 'down'
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=()=>{
|
||||
if(this.refs.content.className === 'down'){
|
||||
this.slideDown();
|
||||
}
|
||||
if(this.refs.content.className === 'up'){
|
||||
this.slideUp();
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
|
||||
let abstractionList=[];
|
||||
if(this.props.fieldList.length>0){
|
||||
abstractionList=this.props.fieldList.filter(x=>x.value=='abstractions')[0].children;
|
||||
}
|
||||
|
||||
const ruleHistory=this.props.ruleHistory;
|
||||
|
||||
return (
|
||||
<div ref="content" className="down" style={{border:'1px solid #d9d9d9',borderRadius:'5px',padding:'10px',height:this.state.height,overflow:'hidden'}}>
|
||||
<div style={{padding:'0 0 20px 20px',cursor:'pointer'}} onClick={this.handleClick}>用户{ruleHistory.merchantCode}修改</div>
|
||||
<div ref="content1" style={{width:750}}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="显示名称:">
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={ruleHistory.label} readOnly/>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="命中初始得分:">
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="initScore" value={ruleHistory.initScore} readOnly/>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="命中基数:">
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="baseNum" value={ruleHistory.baseNum} readOnly/>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="操作符:">
|
||||
<Select value={ruleHistory.operator} readOnly>
|
||||
<Option value="NONE">无</Option>
|
||||
<Option value="ADD">加</Option>
|
||||
<Option value="DEC">减</Option>
|
||||
<Option value="MUL">乘</Option>
|
||||
<Option value="DIV">除</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="指标字段:">
|
||||
<Select value={ruleHistory.abstractionName} readOnly>
|
||||
{abstractionList==undefined?null:abstractionList.map((x,index)=><Option key={x.value+index} value={x.value}>{x.label}</Option>)}
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="比率:">
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="rate" value={ruleHistory.rate} readOnly/>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div ref="content2">
|
||||
<div>
|
||||
<Tooltip title="添加过滤条件" onClick={this.handleAddCondition}><span className="addRule"><Icon type="plus" /> 添加过滤条件</span></Tooltip>
|
||||
</div>
|
||||
<ComplexCondition readOnly fieldList={this.props.fieldList} dataList={this.props.dataList} condition={ruleHistory.ruleDefinition==undefined?null:JSON.parse(ruleHistory.ruleDefinition)} changeParentCondition={()=>{}} index={0}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
121
webapp/component/activation/HistoryRecordList.jsx
Normal file
121
webapp/component/activation/HistoryRecordList.jsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React,{Component} from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Timeline,Icon} from 'antd';
|
||||
import CollapseGroup from '../common/CollapseGroup';
|
||||
import Collapse from '../common/Collapse';
|
||||
import { Link } from 'react-router';
|
||||
import moment from 'moment';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import HistoryRecord from './HistoryRecord';
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class HistoryRecordList extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
label:'',
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null,
|
||||
fieldList:[],
|
||||
dataList:[]
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.ruleId=this.props.params.ruleId;
|
||||
|
||||
//此处为单条策略历史记录接口的获取,参数中应该有本条策略的id,否则无法区分
|
||||
FetchUtil('/ruleHistory','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
label:data.data.page.list[0].label,
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
componentWillMount() {
|
||||
this.fetchTableData();
|
||||
FetchUtil('/activation/datacolumns/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldList:data.data.list
|
||||
});
|
||||
});
|
||||
FetchUtil('/datalist/list/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
dataList:data.data.list
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header" style={{fontSize:'16px',marginBottom:'20px'}}>
|
||||
<Link to={"/ruleList/"+this.props.params.id+"/"+this.props.params.activationId}><Icon type="left-circle" style={{marginRight:'10px'}} />{this.state.label}</Link><span style={{marginLeft:'20px'}}>历史记录</span>
|
||||
</div>
|
||||
|
||||
<Timeline style={{marginLeft:'150px'}}>
|
||||
{this.state.tData.map((info,index)=>{
|
||||
return (
|
||||
<Timeline.Item key={index}>
|
||||
<span style={{position:'absolute',left:'-120px'}}>{moment(info.updateTime).format('YYYY-MM-DD HH:mm:ss')}</span>
|
||||
<HistoryRecord ruleHistory={info} modelId={this.props.params.id} activationId={this.props.params.activationId} fieldList={this.state.fieldList} dataList={this.state.dataList} reload={this.fetchTableData}/>
|
||||
</Timeline.Item>
|
||||
);
|
||||
})
|
||||
}
|
||||
</Timeline>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
341
webapp/component/activation/Rule.jsx
Normal file
341
webapp/component/activation/Rule.jsx
Normal file
@@ -0,0 +1,341 @@
|
||||
import React from 'react';
|
||||
|
||||
import {Form,Input,InputNumber,Breadcrumb,Row,Col,Icon,Card,Select,Button,Cascader,Tooltip,message,Modal} from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import ComplexCondition from '../abstraction/ComplexCondition';
|
||||
|
||||
import {generateScript,validateRules} from '../utils/groovyUtil';
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class Rule extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
if(props.rule!=undefined){
|
||||
const rule=props.rule;
|
||||
|
||||
this.state={
|
||||
label:rule.label,
|
||||
initScore:rule.initScore,
|
||||
baseNum:rule.baseNum,
|
||||
operator:rule.operator,
|
||||
abstractionName:rule.abstractionName,
|
||||
rate:rule.rate,
|
||||
ruleDefinition:rule.ruleDefinition==undefined?null:JSON.parse(rule.ruleDefinition),
|
||||
scripts:rule.scripts
|
||||
}
|
||||
}
|
||||
else{
|
||||
this.state={
|
||||
label:'',
|
||||
initScore:'0',
|
||||
baseNum:'0',
|
||||
operator:'NONE',
|
||||
abstractionName:'',
|
||||
rate:'100',
|
||||
ruleDefinition:null,
|
||||
scripts:''
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
//state[name] = trim(value);
|
||||
state[name] = value;
|
||||
|
||||
if(name=='operator'&&value=='NONE'){
|
||||
state['abstractionName']='';
|
||||
}
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleChangeCondition=(condition,index)=>{
|
||||
let ruleDefinition=this.state.ruleDefinition;
|
||||
|
||||
if(condition==null){
|
||||
ruleDefinition=null;
|
||||
}
|
||||
else{
|
||||
ruleDefinition=condition;
|
||||
}
|
||||
this.setState({
|
||||
ruleDefinition:ruleDefinition
|
||||
})
|
||||
}
|
||||
|
||||
handleAddCondition=()=>{
|
||||
let ruleDefinition=this.state.ruleDefinition;
|
||||
|
||||
if(ruleDefinition==null){
|
||||
ruleDefinition={
|
||||
"class": "PDCT",
|
||||
"enabled": true,
|
||||
"linking": "All",
|
||||
"conditions": [
|
||||
{
|
||||
"class": "SMPL",
|
||||
"enabled": true,
|
||||
"operator": "",
|
||||
"expressions": [
|
||||
{
|
||||
"class": "ENTATTR",
|
||||
"type": "",
|
||||
"column": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
ruleDefinition:ruleDefinition
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
if(!this.state.ruleDefinition){
|
||||
Modal.error({
|
||||
title:'请至少配置一条过滤规则'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if(!validateRules(this.state.ruleDefinition)){
|
||||
Modal.error({
|
||||
title:'请检查过滤条件是否配置完整'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
var param={};
|
||||
if(this.props.rule.id!=0){
|
||||
param.id=this.props.rule.id;
|
||||
}
|
||||
param.modelId=this.props.modelId;
|
||||
param.activationId=this.props.activationId;
|
||||
param.label=this.state.label;
|
||||
param.initScore=this.state.initScore,
|
||||
param.baseNum=this.state.baseNum,
|
||||
param.operator=this.state.operator,
|
||||
param.abstractionName=this.state.abstractionName,
|
||||
param.rate=this.state.rate,
|
||||
param.ruleDefinition=this.state.ruleDefinition;
|
||||
param.scripts=generateScript(this.state.ruleDefinition,"Activation");
|
||||
param.status=1;
|
||||
|
||||
FetchUtil('/rule/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success==true){
|
||||
if(this.props.rule.id==0){
|
||||
message.success('添加成功!');
|
||||
}
|
||||
else{
|
||||
message.success('修改成功!');
|
||||
}
|
||||
}
|
||||
else{
|
||||
message.error('修改失败!');
|
||||
}
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
|
||||
let abstractionList=[];
|
||||
if(this.props.fieldList.length>0){
|
||||
abstractionList=this.props.fieldList.filter(x=>x.value=='abstractions')[0].children;
|
||||
}
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
initScore:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
baseNum:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
abstractionName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
rate:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入显示名称';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.initScore){
|
||||
validate.initScore.help='请输入初始得分';
|
||||
validate.initScore.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(this.state.baseNum < 0){
|
||||
validate.baseNum.help='请输入基数';
|
||||
validate.baseNum.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(this.state.operator!='NONE'&&!this.state.abstractionName){
|
||||
validate.abstractionName.help='请选择抽象字段';
|
||||
validate.abstractionName.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(this.state.rate < 0 ){
|
||||
validate.rate.help='请输入rate';
|
||||
validate.rate.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
// if(!/^[0-9]+$/.test(this.state.initScore)){
|
||||
// validate.initScore.help='initScore必须为数字';
|
||||
// validate.initScore.status='error';
|
||||
// isValidated=false;
|
||||
// }
|
||||
// if(!/^[0-9]+$/.test(this.state.baseNum)){
|
||||
// validate.baseNum.help='baseNum必须为数字';
|
||||
// validate.baseNum.status='error';
|
||||
// isValidated=false;
|
||||
// }
|
||||
// if(!/^[0-9]+$/.test(this.state.rate)){
|
||||
// validate.rate.help='rate必须为数字';
|
||||
// validate.rate.status='error';
|
||||
// isValidated=false;
|
||||
// }
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{width:750}}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="显示名称:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'规则名称,一般为中文,如"1天内设备注册次数过多或注册时间间隔过短"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="命中初始得分:" help={validate.initScore.help} validateStatus={validate.initScore.status}>
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="initScore" value={this.state.initScore} onChange={this.handleSelect.bind(this,'initScore')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'初始得分,在此基础上进行累加计算'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="命中基数:" help={validate.baseNum.help} validateStatus={validate.baseNum.status}>
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="baseNum" value={this.state.baseNum} onChange={this.handleSelect.bind(this,'baseNum')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'配合操作符,与指标字段进行运算'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="操作符:">
|
||||
<Select value={this.state.operator} onChange={this.handleSelect.bind(this,'operator')}>
|
||||
<Option value="NONE">无</Option>
|
||||
<Option value="ADD">加</Option>
|
||||
<Option value="DEC">减</Option>
|
||||
<Option value="MUL">乘</Option>
|
||||
<Option value="DIV">除</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="指标字段:" help={validate.abstractionName.help} validateStatus={validate.abstractionName.status}>
|
||||
<Select disabled={this.state.operator=='NONE'} value={this.state.abstractionName} onChange={this.handleSelect.bind(this,'abstractionName')}>
|
||||
{abstractionList==undefined?null:abstractionList.map((x,index)=><Option key={x.value+index} value={x.value}>{x.label}</Option>)}
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
<FormItem required={true} {...formItemLayout} label="比率:" help={validate.rate.help} validateStatus={validate.rate.status}>
|
||||
<Row>
|
||||
<Col span={4}>
|
||||
<InputNumber name="rate" value={this.state.rate} onChange={this.handleSelect.bind(this,'rate')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'当指标字段值过大或者过小时,对指标字段进行放大或者缩小,使命中分数更加合理'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<Tooltip title="添加过滤条件" onClick={this.handleAddCondition}><span className="addRule"><Icon type="plus" /> 添加过滤条件</span></Tooltip>
|
||||
</div>
|
||||
<ComplexCondition fieldList={this.props.fieldList} dataList={this.props.dataList} condition={this.state.ruleDefinition} changeParentCondition={this.handleChangeCondition} index={0}/>
|
||||
|
||||
<div className="separate"></div>
|
||||
<Row>
|
||||
<Col span={4} offset={4}>
|
||||
<Button type="primary" onClick={this.handleSubmit.bind(this,isValidated)}>保存</Button>{' '}
|
||||
<Button type="primary" onClick={this.props.delete}>删除</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
304
webapp/component/activation/RuleList.jsx
Normal file
304
webapp/component/activation/RuleList.jsx
Normal file
@@ -0,0 +1,304 @@
|
||||
import React,{Component} from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Icon,Spin} from 'antd';
|
||||
import CollapseGroup from '../common/CollapseGroup';
|
||||
import Collapse from '../common/Collapse';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import Rule from './Rule';
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
import {fetchVersion} from '../utils/fetchUtil';
|
||||
|
||||
export default class RuleList extends Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
label:'',
|
||||
status:"1",
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null,
|
||||
fieldList:[],
|
||||
dataList:[],
|
||||
|
||||
activation:null,
|
||||
ruleOrder:[]
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.activationId=this.props.params.activationId;
|
||||
param.label=this.state.label;
|
||||
|
||||
FetchUtil('/rule','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
let ruleOrder=data.data.ruleOrder?data.data.ruleOrder.split(','):[];
|
||||
let ruleList=this.getOrderedRules(ruleOrder,data.data.page.list);
|
||||
if(data.data.page.list.length>0||ruleOrder.length>ruleList.length){
|
||||
let unOrderedList=data.data.page.list;
|
||||
ruleList=ruleList.concat(unOrderedList);
|
||||
ruleOrder=ruleList.map(x=>x.id+'');
|
||||
this.handleReOrder(ruleOrder);
|
||||
}
|
||||
this.setState({
|
||||
tData:ruleList,
|
||||
ruleOrder:ruleOrder
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleAdd=()=>{
|
||||
let tData=this.state.tData;
|
||||
|
||||
tData.push({
|
||||
id:0,
|
||||
label:'',
|
||||
initScore:'0',
|
||||
baseNum:'0',
|
||||
operator:'NONE',
|
||||
abstractionName:'',
|
||||
rate:'100',
|
||||
ruleDefinition:null,
|
||||
scripts:''
|
||||
});
|
||||
|
||||
this.setState({
|
||||
tData:tData
|
||||
})
|
||||
}
|
||||
|
||||
handleDelete=(index)=>{
|
||||
let tData=this.state.tData;
|
||||
let id=tData[index].id;
|
||||
if(id!=0){
|
||||
FetchUtil('/rule/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
if(data.success==true){
|
||||
message.success('删除成功!');
|
||||
}
|
||||
else{
|
||||
message.error('删除失败!');
|
||||
}
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
else{
|
||||
tData.splice(index,1);
|
||||
this.setState({
|
||||
tData:tData
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleSwitch=(rule)=>{
|
||||
rule.status=(rule.status==0?1:0);
|
||||
|
||||
FetchUtil('/rule/','PUT',JSON.stringify(rule),
|
||||
(data) => {
|
||||
if(data.success==true){
|
||||
if(rule.status==1){
|
||||
message.success('启用成功!');
|
||||
}
|
||||
else{
|
||||
message.success('禁用成功!');
|
||||
}
|
||||
}
|
||||
else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({});
|
||||
});
|
||||
}
|
||||
|
||||
handleReOrder=(ruleOrder=this.state.ruleOrder,showMessage=false)=>{
|
||||
let formData = new FormData();
|
||||
formData.append("activationId",this.props.params.activationId);
|
||||
formData.append("ruleOrder",ruleOrder.join(','));
|
||||
fetch(fetchVersion+'/activation/updateOrder',{credentials: 'include',method: 'POST',
|
||||
body:formData})
|
||||
.then((res) => {
|
||||
if(res.ok){
|
||||
return res.json();
|
||||
}
|
||||
else{
|
||||
Modal.error({
|
||||
title: '系统错误',
|
||||
content: '请检查是否有参数配置错误',
|
||||
});
|
||||
}
|
||||
})
|
||||
.then((data)=>{
|
||||
if(showMessage){
|
||||
message.success('排序成功!');
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e.message);
|
||||
});
|
||||
}
|
||||
|
||||
getOrderedRules=(ruleOrder,ruleData)=>{
|
||||
let resultList=[];
|
||||
for(let i=0;i<ruleOrder.length;i++){
|
||||
for(let j=0;j<ruleData.length;j++){
|
||||
if(ruleOrder[i]==ruleData[j].id){
|
||||
resultList.push(ruleData.splice(j,1)[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
handleDrag=(ruleId,pos)=>{
|
||||
let ruleOrder=this.state.ruleOrder;
|
||||
let ruleList=this.state.tData;
|
||||
|
||||
let index=ruleOrder.indexOf(ruleId+'');
|
||||
if(index==pos){
|
||||
return;
|
||||
}
|
||||
let order=ruleOrder.splice(index,1);
|
||||
let rule=ruleList.splice(index,1);
|
||||
ruleOrder.splice(pos,0,order[0]);
|
||||
ruleList.splice(pos,0,rule[0]);
|
||||
this.state.ruleOrder=ruleOrder;
|
||||
this.state.tData=ruleList;
|
||||
|
||||
this.setState({
|
||||
});
|
||||
|
||||
// let moveY=0;
|
||||
// if(distance>=0){
|
||||
// moveY=Math.floor(distance/48);
|
||||
// }
|
||||
// else{
|
||||
// moveY=Math.ceil(distance/48);
|
||||
// }
|
||||
// if(moveY==0){return;}
|
||||
// if(moveY<0){
|
||||
// let order=ruleOrder.splice(index,1);
|
||||
// let rule=ruleList.splice(index,1);
|
||||
// ruleOrder.splice(index+moveY,0,order[0]);
|
||||
// ruleList.splice(index+moveY,0,rule[0]);
|
||||
// this.setState({
|
||||
// ruleOrder:ruleOrder,
|
||||
// tData:ruleList
|
||||
// });
|
||||
// }
|
||||
// else{
|
||||
// let order=ruleOrder.splice(index,1);
|
||||
// let rule=ruleList.splice(index,1);
|
||||
// ruleOrder.splice(index+moveY,0,order[0]);
|
||||
// ruleList.splice(index+moveY,0,rule[0]);
|
||||
// this.setState({
|
||||
// ruleOrder:ruleOrder,
|
||||
// tData:ruleList
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
FetchUtil('/activation/datacolumns/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldList:data.data.list
|
||||
});
|
||||
});
|
||||
FetchUtil('/datalist/list/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
dataList:data.data.list
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="显示名称:">
|
||||
<Input value={this.state.label} name="label" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<Button type="primary" onClick={this.handleAdd}>新增</Button>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<Spin size="large" spinning={this.state.loading}>
|
||||
<CollapseGroup handleDrag={this.handleDrag} handleReOrder={this.handleReOrder} draggable={!this.state.label}>
|
||||
{this.state.tData.filter((info,index)=>{
|
||||
if(this.state.label){
|
||||
var reg = new RegExp('('+ this.state.label+')','gi');
|
||||
return reg.test(info.label);
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}).map((info,index)=>{
|
||||
return (<Collapse ruleId={info.id} ruleOrder={this.state.ruleOrder} switcher={info.status=='1'} modelId={this.props.params.id} activationId={this.props.params.activationId} type="calendar" onSwitch={this.handleSwitch.bind(this,info)} key={info.id?info.id:index} title={info.label?info.label:'新增(请保存)'}>
|
||||
<Rule rule={info} modelId={this.props.params.id} activationId={this.props.params.activationId} fieldList={this.state.fieldList} dataList={this.state.dataList} reload={this.fetchTableData} delete={this.handleDelete.bind(this,index)}/>
|
||||
</Collapse>);
|
||||
})
|
||||
}
|
||||
|
||||
</CollapseGroup>
|
||||
</Spin>
|
||||
|
||||
{/*
|
||||
<div>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
200
webapp/component/activation/modal/AddActivation.jsx
Normal file
200
webapp/component/activation/modal/AddActivation.jsx
Normal file
@@ -0,0 +1,200 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddActivation extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
activationName:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
bottom:'',
|
||||
median:'',
|
||||
high:'',
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = value;
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
activationName:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
bottom:'',
|
||||
median:'',
|
||||
high:'',
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.modelId=this.props.modelId;
|
||||
param.activationName=this.state.activationName;
|
||||
param.label=this.state.label;
|
||||
param.comment=this.state.comment;
|
||||
param.bottom=this.state.bottom;
|
||||
param.median=this.state.median;
|
||||
param.high=this.state.high;
|
||||
param.status=1;
|
||||
|
||||
FetchUtil('/activation/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('添加成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
median:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
high:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入策略名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的策略名';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.median){
|
||||
validate.median.help='请输入警戒值';
|
||||
validate.median.status='warning';
|
||||
isValidated=false;
|
||||
}else if(!/^\d{1,3}/.test(this.state.median)){
|
||||
validate.median.help='警戒值必须为数字';
|
||||
validate.median.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.high){
|
||||
validate.high.help='请输入拒绝值';
|
||||
validate.high.status='warning';
|
||||
isValidated=false;
|
||||
}else if(!/^\d{1,3}/.test(this.state.high)){
|
||||
validate.high.help='拒绝值必须为数字';
|
||||
validate.high.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="新增字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="策略名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'显示名称,一般为中文,如"异常注册"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="备注:">
|
||||
<Input type="text" name="comment" value={this.state.comment} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="警戒值:" help={validate.median.help} validateStatus={validate.median.status}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<InputNumber min={1} max={100} name="median" value={this.state.median} onChange={this.handleSelect.bind(this,'median')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果实际风险分数大于此数字,此交易则需要人工审核'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="拒绝值:" help={validate.high.help} validateStatus={validate.high.status}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<InputNumber min={1} max={100} name="high" value={this.state.high} onChange={this.handleSelect.bind(this,'high')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果实际风险分数大于此数字,此交易则直接拒绝'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
228
webapp/component/activation/modal/EditActivation.jsx
Normal file
228
webapp/component/activation/modal/EditActivation.jsx
Normal file
@@ -0,0 +1,228 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditActivation extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
activationName:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
bottom:'0',
|
||||
median:'',
|
||||
high:'',
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/activation/'+this.props.row.id,'GET','',
|
||||
(data) => {
|
||||
const activation=data.data.activation;
|
||||
this.setState({
|
||||
activationName:activation.activationName,
|
||||
label:activation.label,
|
||||
comment:activation.comment,
|
||||
bottom:activation.bottom,
|
||||
median:activation.median,
|
||||
high:activation.high,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = value;
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.modelId=this.props.modelId;
|
||||
param.activationName=this.state.activationName;
|
||||
param.label=this.state.label;
|
||||
param.comment=this.state.comment;
|
||||
param.bottom='0';
|
||||
param.median=this.state.median;
|
||||
param.high=this.state.high;
|
||||
param.status=1;
|
||||
|
||||
FetchUtil('/activation/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('修改成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
activationName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
median:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
high:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.activationName){
|
||||
validate.activationName.help='请输入策略名';
|
||||
validate.activationName.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let activationName = this.state.activationName;
|
||||
if(!reg.test(activationName)){
|
||||
validate.activationName.help='按照提示输入正确的策略名';
|
||||
validate.activationName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入显示名称';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.median){
|
||||
validate.median.help='请输入警戒值';
|
||||
validate.median.status='warning';
|
||||
isValidated=false;
|
||||
}else if(!/^\d{1,3}/.test(this.state.median)){
|
||||
validate.median.help='警戒值必须为数字';
|
||||
validate.median.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.high){
|
||||
validate.high.help='请输入拒绝值';
|
||||
validate.high.status='warning';
|
||||
isValidated=false;
|
||||
}else if(!/^\d{1,3}/.test(this.state.high)){
|
||||
validate.high.help='拒绝值必须为数字';
|
||||
validate.high.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="策略名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'显示名称,一般为中文,如"异常注册"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="备注:">
|
||||
<Input type="text" name="comment" value={this.state.comment} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="警戒值:" help={validate.median.help} validateStatus={validate.median.status}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<InputNumber min={1} max={100} name="median" value={this.state.median} onChange={this.handleSelect.bind(this,'median')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果实际风险分数大于此数字,此交易则需要人工审核'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="拒绝值:" help={validate.high.help} validateStatus={validate.high.status}>
|
||||
<Row>
|
||||
<Col span={6}>
|
||||
<InputNumber min={1} max={100} name="high" value={this.state.high} onChange={this.handleSelect.bind(this,'high')}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果实际风险分数大于此数字,此交易则直接拒绝'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
121
webapp/component/common/Collapse.jsx
Normal file
121
webapp/component/common/Collapse.jsx
Normal file
@@ -0,0 +1,121 @@
|
||||
import React from 'react';
|
||||
import {Switch,Icon} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
|
||||
import './Collapse.less';
|
||||
|
||||
export default class Collapse extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
height:0,
|
||||
|
||||
index:-1,
|
||||
pos:-1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slideDown=()=>{
|
||||
if(this.state.height=="auto"){
|
||||
return;
|
||||
}
|
||||
if(this.state.height<this.refs.pChild.offsetHeight){
|
||||
this.setState({
|
||||
height:this.state.height+15
|
||||
},()=>{
|
||||
setTimeout(this.slideDown,1);
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:"auto"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
slideUp=()=>{
|
||||
if(this.state.height=="auto"){
|
||||
this.state.height=this.refs.pChild.offsetHeight;
|
||||
}
|
||||
if(this.state.height>0){
|
||||
this.setState({
|
||||
height:this.state.height-15
|
||||
},()=>{
|
||||
setTimeout(this.slideUp,1);
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=()=>{
|
||||
this.props.handleClick();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(nextProps.slide){
|
||||
this.slideDown();
|
||||
}
|
||||
else{
|
||||
this.slideUp();
|
||||
}
|
||||
}
|
||||
|
||||
handleDragEnd=(e)=>{
|
||||
this.setState({
|
||||
index:-1,
|
||||
pos:-1
|
||||
})
|
||||
this.props.handleReOrder();
|
||||
}
|
||||
|
||||
handleDrag=(e)=>{
|
||||
if(!this.props.draggable){return;}
|
||||
if(e.pageY==0){return;}
|
||||
let pos=Math.floor((e.pageY-300)/48);
|
||||
let index=this.props.ruleOrder.indexOf(this.props.ruleId+'');
|
||||
if(index==pos){
|
||||
return;
|
||||
}
|
||||
if(index==this.state.index&&pos==this.state.pos){
|
||||
return;
|
||||
}
|
||||
this.state.index=index;
|
||||
this.state.pos=pos;
|
||||
this.props.handleDrag(this.props.ruleId,pos);
|
||||
}
|
||||
|
||||
switchClick=(e)=>{
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={this.state.index!=-1?{"visibility":"hidden"}:{}} className="p-block" draggable={this.props.draggable} onDragEnd={this.handleDragEnd} onDrag={this.handleDrag}>
|
||||
<div className={'p-block-titles'+(this.props.slide?' p-block-title-select':'')} onClick={this.handleClick}>
|
||||
<div className='p-block-title-left'>{this.props.title}</div>
|
||||
{this.props.switcher!=undefined?
|
||||
<div className='p-block-title-right' onClick={this.switchClick}><Switch checked={this.props.switcher} onChange={this.props.onSwitch}/></div>
|
||||
:''}
|
||||
{
|
||||
this.props.type!=undefined?
|
||||
<div className='p-block-title-right'><Link to={"/historyRecordList/"+this.props.modelId+"/" + this.props.activationId+"/"+this.props.ruleId}><Icon type="calendar" style={{fontSize:'24px',lineHeight:1.5}}/></Link></div>
|
||||
:''
|
||||
}
|
||||
|
||||
</div>
|
||||
<div className={'p-block-contents'+(this.props.slide?' p-block-content-select':'')} style={{height:this.state.height}} ref="pContent">
|
||||
<div ref="pChild" className="p-block-main">
|
||||
{this.props?this.props.children:''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
48
webapp/component/common/Collapse.less
Normal file
48
webapp/component/common/Collapse.less
Normal file
@@ -0,0 +1,48 @@
|
||||
.p-block{
|
||||
margin-bottom:8px;
|
||||
}
|
||||
|
||||
.p-block-titles{
|
||||
height: 40px;
|
||||
border:1px solid #d9d9d9;
|
||||
padding-left: 30px;
|
||||
cursor:pointer;
|
||||
border-radius: 7px;
|
||||
|
||||
&:hover{
|
||||
background-color:#FAFAFA;
|
||||
}
|
||||
}
|
||||
|
||||
.p-block-title-left{
|
||||
float:left;
|
||||
line-height:38px;
|
||||
}
|
||||
|
||||
.p-block-title-right{
|
||||
float:right;
|
||||
line-height:34px;
|
||||
margin-right:20px;
|
||||
}
|
||||
|
||||
.p-block-title-select{
|
||||
background-color:#f7f7f7;
|
||||
border-bottom-right-radius:0;
|
||||
border-bottom-left-radius:0;
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
.p-block-contents{
|
||||
clear:both;
|
||||
background-color:white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.p-block-content-select{
|
||||
border:1px solid #d9d9d9;
|
||||
border-top:none;
|
||||
}
|
||||
|
||||
.p-block-main{
|
||||
padding:20px
|
||||
}
|
||||
63
webapp/component/common/CollapseGroup.jsx
Normal file
63
webapp/component/common/CollapseGroup.jsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
|
||||
export default class CollapseGroup extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
activeKey:'',
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
getItems=()=>{
|
||||
if(!this.props){
|
||||
return '';
|
||||
}
|
||||
|
||||
return this.props.children.map((child,index)=>{
|
||||
const key=child.key;
|
||||
const props={
|
||||
slide:child.key==this.state.activeKey?true:false,
|
||||
index:index,
|
||||
draggable:this.props.draggable&&this.state.activeKey=='',
|
||||
|
||||
handleDrag:(ruleId,pos)=>{
|
||||
this.props.handleDrag(ruleId,pos);
|
||||
},
|
||||
handleReOrder:()=>{
|
||||
this.props.handleReOrder();
|
||||
},
|
||||
handleClick:()=>{
|
||||
if(this.state.activeKey==key){
|
||||
this.setState({
|
||||
activeKey:''
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
activeKey:key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return React.cloneElement(child,props);
|
||||
})
|
||||
}
|
||||
|
||||
allowDrop=(e)=>{
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div style={{position:"relative"}} onDragOver={(this.props.draggable&&this.state.activeKey=='')?this.allowDrop:null}>
|
||||
{this.getItems()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
166
webapp/component/datalist/Datalist.jsx
Normal file
166
webapp/component/datalist/Datalist.jsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
import AddDataList from './modal/AddDataList';
|
||||
import EditDataList from './modal/EditDataList';
|
||||
import EditDataListMeta from './modal/EditDataListMeta';
|
||||
|
||||
export default class Datalist extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
name:'',
|
||||
label:'',
|
||||
listType:'',
|
||||
status:1,
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.params.id;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
param.listType=this.state.listType;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/datalist','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deleteModel=(id)=>{
|
||||
FetchUtil('/datalist/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
message.info('删除成功!');
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '列表名',
|
||||
dataIndex: 'label'
|
||||
}, {
|
||||
title: '备注',
|
||||
dataIndex: 'comment'
|
||||
},{
|
||||
title: '名单类型',
|
||||
dataIndex: 'listType'
|
||||
},{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
<EditDataList modelId={this.props.params.id} row={r} reload={this.fetchTableData}/>
|
||||
<span className="ant-divider"></span>
|
||||
<EditDataListMeta modelId={this.props.params.id} row={r}/>
|
||||
<span className="ant-divider"></span>
|
||||
<Tooltip title="管理黑/白名单内容"><Link to={"/datalistRecord/"+this.props.params.id+"/"+r.id}>管理内容</Link></Tooltip>
|
||||
<span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该模型吗?'} onConfirm={this.deleteModel.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="列表名:">
|
||||
<Input value={this.state.name} name="name" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<AddDataList modelId={this.props.params.id} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData.filter((item,index,array)=>{
|
||||
var reg = new RegExp('('+ this.state.name+')','gi');
|
||||
if(this.state.name){
|
||||
return (reg.test(item.label));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
151
webapp/component/datalist/DatalistRecord.jsx
Normal file
151
webapp/component/datalist/DatalistRecord.jsx
Normal file
@@ -0,0 +1,151 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Modal} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
|
||||
import AddDataListRecord from './modal/AddDataListRecord';
|
||||
import EditDataListRecord from './modal/EditDataListRecord';
|
||||
|
||||
export default class DatalistRecord extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
pageSize:30,
|
||||
|
||||
metaList:[],
|
||||
|
||||
loading:true,
|
||||
|
||||
}
|
||||
|
||||
FetchUtil('/datalistmeta/list/'+this.props.params.datalistId,'GET','',
|
||||
(data) => {
|
||||
if(data.data.list.length==0){
|
||||
Modal.warning({
|
||||
title: '警告',
|
||||
content: '黑/白名单字段未定义,请前往上级菜单点击管理字段按钮进行管理。点击按钮返回',
|
||||
maskClosable:false,
|
||||
onOk:this.handleRedirect
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
metaList:data.data.list
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=20;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.dataListId=this.props.params.datalistId;
|
||||
|
||||
FetchUtil('/datalistrecord','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({
|
||||
loading:false,
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum
|
||||
});
|
||||
if(data.data.page.rowCount > 9990){
|
||||
this.setState({
|
||||
rowCount:9990
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deleteModel=(id)=>{
|
||||
FetchUtil('/datalistrecord/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
message.info('删除成功!');
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
|
||||
handleRedirect=()=>{
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
render(){
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: 'No.',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Data Record',
|
||||
dataIndex: 'dataRecord'
|
||||
},{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
<EditDataListRecord metaList={this.state.metaList} dataListId={this.props.params.datalistId} row={r} reload={this.fetchTableData}/>
|
||||
<span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该模型吗?'} onConfirm={this.deleteModel.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<AddDataListRecord metaList={this.state.metaList} dataListId={this.props.params.datalistId} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} defaultPageSize={this.state.pageSize} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
163
webapp/component/datalist/modal/AddDataList.jsx
Normal file
163
webapp/component/datalist/modal/AddDataList.jsx
Normal file
@@ -0,0 +1,163 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddDataList extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
name:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
listType:'',
|
||||
status:"1",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true,
|
||||
|
||||
name:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
listType:'',
|
||||
status:"1",
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.modelId=this.props.modelId;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
param.comment=this.state.comment;
|
||||
param.listType=this.state.listType;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/datalist/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('添加成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
listType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入列表名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.listType){
|
||||
validate.listType.help='请选择名单类型';
|
||||
validate.listType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem {...formItemLayout} label="列表名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'列表显示名称,一般为中文,如"注册手机黑名单"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="备注:">
|
||||
<Input type="text" name="comment" value={this.state.comment} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="名单类型:" help={validate.listType.help} validateStatus={validate.listType.status}>
|
||||
<Select value={this.state.listType} style={{ width: 120 }} onChange={this.handleSelect.bind(this,'listType')}>
|
||||
<Option value="">请选择</Option>
|
||||
<Option value="BLACK">黑名单</Option>
|
||||
<Option value="WHITE">白名单</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
100
webapp/component/datalist/modal/AddDataListRecord.jsx
Normal file
100
webapp/component/datalist/modal/AddDataListRecord.jsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddDataListRecord extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
dataRecord:'',
|
||||
fieldNum:this.props.metaList.length
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleChange=(index,e)=>{
|
||||
var value=e.target.value;
|
||||
var valueArr=this.state.dataRecord.split(',');
|
||||
if(valueArr.length<this.state.fieldNum){
|
||||
var newArr=new Array(this.state.fieldNum);
|
||||
for(var i=0;i<this.state.fieldNum;i++){
|
||||
newArr[i]=valueArr[i]!=undefined?valueArr[i]:'';
|
||||
}
|
||||
|
||||
valueArr=newArr;
|
||||
}
|
||||
|
||||
valueArr[index]=trim(value);
|
||||
this.setState({
|
||||
dataRecord:valueArr.join(',')
|
||||
});
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
dataRecord:'',
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=()=>{
|
||||
var param={};
|
||||
param.dataListId=this.props.dataListId;
|
||||
param.dataRecord=this.state.dataRecord;
|
||||
|
||||
FetchUtil('/datalistrecord/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
let valueArr=this.state.dataRecord.split(',');
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="新增记录" visible={this.state.visible} onOk={this.handleSubmit} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
{this.props.metaList.map(function(info,i){
|
||||
return (
|
||||
<FormItem {...formItemLayout} key={'meta'+info.id} label={info.label}>
|
||||
<Input type="text" value={valueArr[i]} onChange={this.handleChange.bind(this,i)}/>
|
||||
</FormItem>
|
||||
);
|
||||
}.bind(this))}
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
179
webapp/component/datalist/modal/EditDataList.jsx
Normal file
179
webapp/component/datalist/modal/EditDataList.jsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditDataList extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
name:'',
|
||||
label:'',
|
||||
comment:'',
|
||||
listType:'',
|
||||
status:"1",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/datalist/'+this.props.row.id,'GET','',
|
||||
(data) => {
|
||||
const datalist=data.data.datalist;
|
||||
this.setState({
|
||||
name:datalist.name,
|
||||
label:datalist.label,
|
||||
comment:datalist.comment,
|
||||
listType:datalist.listType,
|
||||
status:datalist.status+""
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.modelId=this.props.modelId;
|
||||
param.name=this.state.name;
|
||||
param.label=this.state.label;
|
||||
param.comment=this.state.comment;
|
||||
param.listType=this.state.listType;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/datalist/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('修改成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
listType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入列表名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.listType){
|
||||
validate.listType.help='请选择名单类型';
|
||||
validate.listType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem {...formItemLayout} label="列表名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'列表显示名称,一般为中文,如"注册手机黑名单"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="备注:">
|
||||
<Input type="text" name="comment" value={this.state.comment} onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="名单类型:" help={validate.listType.help} validateStatus={validate.listType.status}>
|
||||
<Select value={this.state.listType} style={{ width: 120 }} onChange={this.handleSelect.bind(this,'listType')}>
|
||||
<Option value="">请选择</Option>
|
||||
<Option value="BLACK">黑名单</Option>
|
||||
<Option value="WHITE">白名单</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="状态:">
|
||||
<Select value={this.state.status} name="status" style={{ width: 120 }} onChange={this.handleSelect.bind(this,'status')}>
|
||||
<Option value="1">正常</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
176
webapp/component/datalist/modal/EditDataListMeta.jsx
Normal file
176
webapp/component/datalist/modal/EditDataListMeta.jsx
Normal file
@@ -0,0 +1,176 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
const OptGroup = Select.OptGroup;
|
||||
const InputGroup = Input.Group;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditDataListMeta extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
metaList:[],
|
||||
initialList:[]
|
||||
}
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/datalistmeta/list/'+this.props.row.id,'GET','',
|
||||
(data) => {
|
||||
let initialData = data.data.list.map((item)=>{
|
||||
return item.label
|
||||
});
|
||||
this.setState({
|
||||
metaList:data.data.list,
|
||||
initialList:initialData
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(index,e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
|
||||
var metaList=this.state.metaList;
|
||||
metaList[index][name]=trim(value);
|
||||
this.setState({
|
||||
metaList:metaList
|
||||
});
|
||||
}
|
||||
|
||||
addField=()=>{
|
||||
let metaList=this.state.metaList;
|
||||
metaList.push({
|
||||
dataListId:this.props.row.id,
|
||||
fieldName:'',
|
||||
label:'',
|
||||
seqNum:1
|
||||
});
|
||||
this.setState({
|
||||
metaList:metaList
|
||||
})
|
||||
}
|
||||
|
||||
deleteField=(index)=>{
|
||||
let metaList=this.state.metaList;
|
||||
metaList.splice(index,1);
|
||||
this.setState({
|
||||
metaList:metaList
|
||||
})
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=()=>{
|
||||
let labelIsNull = this.state.metaList.some((item)=>{
|
||||
if(!item.label){
|
||||
return true;
|
||||
}
|
||||
});
|
||||
let labelIsChange = this.state.metaList.some((item,index,array)=>{
|
||||
if( (array.length > this.state.initialList.length) || (item.label !== this.state.initialList[index]) ){
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,10}$/;
|
||||
let labelReg = this.state.metaList.every((item,index,array)=>{
|
||||
if(reg.test(item.label)){
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if(this.state.metaList.length==0){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请添加至少一个字段'
|
||||
});
|
||||
return false;
|
||||
}else if(labelIsNull){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '字段名不能为空!'
|
||||
});
|
||||
return false;
|
||||
}else if(!labelReg){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '字段名含有特殊字符,或者字符长度不符合!'
|
||||
});
|
||||
return false;
|
||||
}else if(labelIsChange){
|
||||
FetchUtil('/datalistmeta/','PUT',JSON.stringify(this.state.metaList),
|
||||
(data) => {
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="管理黑/白名单字段" onClick={this.showModal}><a>管理字段</a></Tooltip>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit} onCancel={this.handleCancel}>
|
||||
<Row>
|
||||
{this.state.initialList.length ?'':<Col span={6} offset={10}>
|
||||
<span className="addRule" style={{display:"block",marginBottom:10}} onClick={this.addField}><Icon type="plus" /> 添加字段</span>
|
||||
</Col>
|
||||
}
|
||||
{this.state.initialList.length ?<Col span={25} offset={2} style={{fontSize:14,marginBottom:10,color:'#f00'}}><span >现有字段不能删除,若需要删除字段,则建议直接删除列表!</span></Col>:<Col span={1} offset={1}>
|
||||
<Tooltip placement="right" title={'现有字段不能删除,若需要删除字段,则建议直接删除列表!'}>
|
||||
<Icon style={{fontSize:16,marginBottom:10}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>}
|
||||
</Row>
|
||||
<Form horizontal form={this.props.form}>
|
||||
{this.state.metaList.map(function(info,i){
|
||||
return (
|
||||
<FormItem key={i+'meta'} label='字段名' labelCol={{span:10}}>
|
||||
<Col span={4} offset={1}>
|
||||
<Input name="label" value={info.label} placeholder={'字段名'} onChange={this.handleChange.bind(this,i)}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段名,一般为中文,如"手机号码",2-10位可由中文、英文字母、数字、下划线的组合'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col span={1} offset={1}>
|
||||
<i onClick={this.deleteField.bind(this,i)} className="fa fa-trash" style={{fontSize:16}}/>
|
||||
</Col>
|
||||
</FormItem>
|
||||
);
|
||||
}.bind(this))}
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
99
webapp/component/datalist/modal/EditDataListRecord.jsx
Normal file
99
webapp/component/datalist/modal/EditDataListRecord.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditDataListRecord extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
dataRecord:this.props.row.dataRecord,
|
||||
fieldNum:this.props.metaList.length
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(index,e)=>{
|
||||
var value=e.target.value;
|
||||
var valueArr=this.state.dataRecord.split(',');
|
||||
if(valueArr.length<this.state.fieldNum){
|
||||
var newArr=new Array(this.state.fieldNum);
|
||||
for(var i=0;i<this.state.fieldNum;i++){
|
||||
newArr[i]=valueArr[i]!=undefined?valueArr[i]:'';
|
||||
}
|
||||
|
||||
valueArr=newArr;
|
||||
}
|
||||
|
||||
valueArr[index]=trim(value);
|
||||
this.setState({
|
||||
dataRecord:valueArr.join(',')
|
||||
});
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=()=>{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.dataListId=this.props.dataListId;
|
||||
param.dataRecord=this.state.dataRecord;
|
||||
|
||||
FetchUtil('/datalistrecord/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
let valueArr=this.state.dataRecord.split(',');
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑记录" visible={this.state.visible} onOk={this.handleSubmit} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
{this.props.metaList.map(function(info,i){
|
||||
return (
|
||||
<FormItem {...formItemLayout} key={'meta'+info.id} label={info.label}>
|
||||
<Input type="text" value={valueArr[i]} onChange={this.handleChange.bind(this,i)}/>
|
||||
</FormItem>
|
||||
);
|
||||
}.bind(this))}
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
204
webapp/component/field/Field.jsx
Normal file
204
webapp/component/field/Field.jsx
Normal file
@@ -0,0 +1,204 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Menu,Icon} from 'antd';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const SubMenu = Menu.SubMenu;
|
||||
const MenuItemGroup = Menu.ItemGroup;
|
||||
|
||||
import AddField from './modal/AddField';
|
||||
import EditField from './modal/EditField';
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class Field extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
fieldName:'',
|
||||
label:'',
|
||||
fieldType:'',
|
||||
indexedState:'',
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.params.id;
|
||||
param.fieldName=this.state.fieldName;
|
||||
param.label=this.state.label;
|
||||
param.fieldType=this.state.fieldType;
|
||||
|
||||
FetchUtil('/field','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
let indexedAll = data.data.page.list;
|
||||
let num = 0;
|
||||
let sum = indexedAll.reduce((pre,cur,index,array)=>{
|
||||
let preNum =pre.indexed ? 1 : 0;
|
||||
num += preNum ;
|
||||
return (num += array[index].indexed);
|
||||
});
|
||||
//console.log(sum);
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount,
|
||||
indexedAll:sum
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deleteModel=(id)=>{
|
||||
FetchUtil('/field/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
message.info('删除成功!');
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '字段名',
|
||||
dataIndex: 'fieldName'
|
||||
},
|
||||
{
|
||||
title: '显示名称',
|
||||
dataIndex: 'label'
|
||||
},
|
||||
{
|
||||
title: '字段类型',
|
||||
dataIndex: 'fieldType',
|
||||
render:(t)=>{
|
||||
switch(t){
|
||||
case 'STRING': return '字符串';
|
||||
case 'INTEGER': return '整型';
|
||||
case 'LONG': return '长整型';
|
||||
case 'DOUBLE': return '浮点型';
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '是否索引',
|
||||
dataIndex: 'indexed',
|
||||
render:(t)=>{
|
||||
if(t){
|
||||
return '是';
|
||||
}else {
|
||||
return '否'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
<EditField modelId={this.props.params.id} indexedAll={this.state.indexedAll} row={r} reload={this.fetchTableData}/>
|
||||
<span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该字段吗?'} onConfirm={this.deleteModel.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="字段名:">
|
||||
<Input value={this.state.fieldName} name="fieldName" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<AddField modelId={this.props.params.id} indexedAll={this.state.indexedAll} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData.filter((item,index,array)=>{
|
||||
var reg = new RegExp('('+ this.state.fieldName+')','gi');
|
||||
if(this.state.fieldName){
|
||||
return (reg.test(item.label));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
228
webapp/component/field/modal/AddField.jsx
Normal file
228
webapp/component/field/modal/AddField.jsx
Normal file
@@ -0,0 +1,228 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddField extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
fieldName:'',
|
||||
label:'',
|
||||
fieldType:'',
|
||||
indexed:false,
|
||||
|
||||
fieldTypes:[]
|
||||
}
|
||||
|
||||
FetchUtil('/common/fieldtypes','GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldTypes:data.data.fields
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
onCheck=(e)=>{
|
||||
if(e.target.checked && this.props.indexedAll>=8){
|
||||
Modal.warning({
|
||||
title: '提示信息',
|
||||
content: '索引已超过8项!',
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
indexed:e.target.checked
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true,
|
||||
|
||||
fieldName:'',
|
||||
label:'',
|
||||
fieldType:''
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param = {};
|
||||
param.modelId = this.props.modelId;
|
||||
param.fieldName = this.state.fieldName;
|
||||
param.label = this.state.label;
|
||||
param.fieldType = this.state.fieldType;
|
||||
param.indexed = this.state.indexed;
|
||||
|
||||
FetchUtil('/field/', 'PUT', JSON.stringify(param),
|
||||
(data) => {
|
||||
if (data.success) {
|
||||
message.success('添加成功');
|
||||
} else {
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
fieldName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
fieldType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.fieldName){
|
||||
validate.fieldName.help='请输入字段名';
|
||||
validate.fieldName.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let fieldName = this.state.fieldName;
|
||||
if(!reg.test(fieldName)){
|
||||
validate.fieldName.help='按照提示输入正确的字段名';
|
||||
validate.fieldName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入显示名称';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.fieldType){
|
||||
validate.fieldType.help='请选择字段类型';
|
||||
validate.fieldType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="新建字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="字段名:" help={validate.fieldName.help} validateStatus={validate.fieldName.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="fieldName" value={this.state.fieldName} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'2-30位英文字母、数字、下划线的组合,以英文字母开头,如"deviceId"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="显示名称:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段显示名称,一般为中文,如"设备ID"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="字段类型:" help={validate.fieldType.help} validateStatus={validate.fieldType.status}>
|
||||
<Row>
|
||||
<Col span={10}>
|
||||
<Select value={this.state.fieldType} onChange={this.handleSelect.bind(this,'fieldType')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.state.fieldTypes.map(x=><Option key={x.name} value={x.name}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段类型,目前有四种类型,分别为字符串(如"你好","abc"等),整数(其范围为 -2147483648 到 2147483647 之间),长整数(其范围为 -9223372036854775808 到 9223372036854775807 之间),浮点数(如 3.14)。'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="是否索引:">
|
||||
<Row>
|
||||
<Col span={1}>
|
||||
<Checkbox checked={this.state.indexed} onChange={this.onCheck}></Checkbox>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果勾选,则为该字段创建索引'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
239
webapp/component/field/modal/EditField.jsx
Normal file
239
webapp/component/field/modal/EditField.jsx
Normal file
@@ -0,0 +1,239 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditField extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
fieldName:'',
|
||||
label:'',
|
||||
fieldType:'',
|
||||
|
||||
fieldTypes:[],
|
||||
indexed:false
|
||||
}
|
||||
|
||||
FetchUtil('/common/fieldtypes','GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldTypes:data.data.fields
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/field/'+this.props.row.id,'GET','',
|
||||
(data) => {
|
||||
const field=data.data.field;
|
||||
this.setState({
|
||||
fieldName:field.fieldName,
|
||||
label:field.label,
|
||||
fieldType:field.fieldType,
|
||||
indexed:field.indexed
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
onCheck=(e)=>{
|
||||
if(e.target.checked && this.props.indexedAll>=8){
|
||||
Modal.warning({
|
||||
title: '提示信息',
|
||||
content: '索引已超过8项!',
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
indexed:e.target.checked
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param = {};
|
||||
param.id = this.props.row.id;
|
||||
param.modelId = this.props.modelId;
|
||||
param.fieldName = this.state.fieldName;
|
||||
param.label = this.state.label;
|
||||
param.fieldType = this.state.fieldType;
|
||||
param.indexed = this.state.indexed;
|
||||
|
||||
FetchUtil('/field/', 'PUT', JSON.stringify(param),
|
||||
(data) => {
|
||||
if (data.success) {
|
||||
message.success('修改成功');
|
||||
} else {
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible: false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
fieldName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
fieldType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.fieldName){
|
||||
validate.fieldName.help='请输入字段名';
|
||||
validate.fieldName.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let fieldName = this.state.fieldName;
|
||||
if(!reg.test(fieldName)){
|
||||
validate.fieldName.help='按照提示输入正确的字段名';
|
||||
validate.fieldName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入显示名称';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.fieldType){
|
||||
validate.fieldType.help='请选择字段类型';
|
||||
validate.fieldType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="字段名:" help={validate.fieldName.help} validateStatus={validate.fieldName.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="fieldName" value={this.state.fieldName} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'2-30位英文字母、数字、下划线的组合,以英文字母开头,如"deviceId"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="显示名称:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段显示名称,一般为中文,如"设备ID"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="字段类型:" help={validate.fieldType.help} validateStatus={validate.fieldType.status}>
|
||||
<Row>
|
||||
<Col span={10}>
|
||||
<Select value={this.state.fieldType} onChange={this.handleSelect.bind(this,'fieldType')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.state.fieldTypes.map(x=><Option key={x.name} value={x.name}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段类型,目前有四种类型,分别为字符串(如"你好","abc"等),整数(其范围为 -2147483648 到 2147483647 之间),长整数(其范围为 -9223372036854775808 到 9223372036854775807 之间),浮点数(如 3.14)'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="是否索引:">
|
||||
<Row>
|
||||
<Col span={1}>
|
||||
<Checkbox checked={this.state.indexed} onChange={this.onCheck}></Checkbox>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'如果勾选,则为该字段创建索引'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
199
webapp/component/model/Model.jsx
Normal file
199
webapp/component/model/Model.jsx
Normal file
@@ -0,0 +1,199 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Switch,Modal,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Menu,Icon} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
import moment from 'moment';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
const SubMenu = Menu.SubMenu;
|
||||
const MenuItemGroup = Menu.ItemGroup;
|
||||
const confirm = Modal.confirm;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
|
||||
export default class Model extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
model:null,
|
||||
|
||||
current:'',
|
||||
disable: false,
|
||||
visible: false
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchData=()=>{
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data)=>{
|
||||
if(data.data.model.status === 1){
|
||||
this.setState({
|
||||
checked:true,
|
||||
disable:true
|
||||
});
|
||||
}else if(data.data.model.status === 2){
|
||||
this.setState({
|
||||
checked:false,
|
||||
disable:true
|
||||
});
|
||||
}else if(data.data.model.status === 0){
|
||||
this.setState({
|
||||
checked:false,
|
||||
disable:false
|
||||
});
|
||||
}
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
model:data.data.model
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
componentDidMount() {
|
||||
let key='';
|
||||
switch(this.props.location.pathname.split('/')[1]){
|
||||
case 'field':
|
||||
key='field';break;
|
||||
case 'preItem':
|
||||
key='preItem';break;
|
||||
case 'datalist':
|
||||
case 'datalistRecord':
|
||||
key='datalist';break;
|
||||
case 'abstractionList':
|
||||
key='abstractionList';break;
|
||||
case 'activation':
|
||||
case 'ruleList':
|
||||
case 'historyRecordList':
|
||||
key='activation';break;
|
||||
}
|
||||
this.setState({
|
||||
current:key
|
||||
});
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
handleClick=(e)=>{
|
||||
window.location.href='/#/'+e.key+'/'+this.props.params.id;
|
||||
this.setState({
|
||||
current:e.key
|
||||
})
|
||||
};
|
||||
|
||||
handleBuild=()=>{
|
||||
this.setState({
|
||||
visible: true
|
||||
});
|
||||
var _self = this;
|
||||
let paramsId = this.props.params.id;
|
||||
//var success = false;
|
||||
confirm({
|
||||
title: '是否重新构建模型?',
|
||||
content: '确认重新构建模型将清空历史数据!',
|
||||
onOk() {
|
||||
FetchUtil('/model/build/'+paramsId,'POST','',
|
||||
(data)=>{
|
||||
console.log(data);
|
||||
if(!data.success){
|
||||
Modal.error({
|
||||
title: '构建状态',
|
||||
content: data.msg,
|
||||
});
|
||||
//alert(data.msg);
|
||||
}else {
|
||||
Modal.success({
|
||||
title: '构建状态',
|
||||
content: '构建成功!',
|
||||
});
|
||||
_self.setState({
|
||||
checked:true,
|
||||
disable:true
|
||||
});
|
||||
|
||||
console.log(_self);
|
||||
}
|
||||
});
|
||||
},
|
||||
onCancel() {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
onChange=()=>{
|
||||
this.setState({
|
||||
checked: !this.state.checked,
|
||||
});
|
||||
|
||||
if(!this.state.checked){
|
||||
FetchUtil('/model/enable/'+this.props.params.id,'POST','',
|
||||
(data)=>{
|
||||
console.log(data);
|
||||
if(!data.success){
|
||||
alert(data.msg);
|
||||
}
|
||||
});
|
||||
}else {
|
||||
FetchUtil('/model/disable/'+this.props.params.id,'POST','',
|
||||
(data)=>{
|
||||
console.log(data);
|
||||
if(!data.success){
|
||||
alert(data.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="ant-layout-wrapper">
|
||||
<div className="ant-layout-breadcrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>首页</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>{this.state.model==null?'':<Link to={"/model/"+this.state.model.id}>模型"{this.state.model.label}"</Link>}</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<div className="ant-layout-container">
|
||||
<div style={{lineHeight:"46px",padding:"0 20px 0",margin:"0 24px",borderBottom:"1px solid #e9e9e9"}}>
|
||||
{this.state.model==null?'':<span style={{marginRight:20}}>模型:"{this.state.model.label}"</span>}
|
||||
{this.state.model==null?'':<span style={{marginRight:20}}>模型创建时间:{moment(this.state.model.createTime).format('YYYY-MM-DD HH:mm:ss')}</span>}
|
||||
{this.state.disable===false?'':<Switch checkedChildren={'开'} unCheckedChildren={'关'} defaultChecked={this.state.checked} checked={this.state.checked} disabled={this.state.disabled} onChange={this.onChange} />}
|
||||
<Button type="primary" onClick={this.handleBuild} style={{float:"right",marginTop:9}}>构建模型</Button>
|
||||
</div>
|
||||
<div className="ant-layout-header" style={{padding:"0 24px 24px"}}>
|
||||
|
||||
<Menu onClick={this.handleClick}
|
||||
selectedKeys={[this.state.current]}
|
||||
mode="horizontal"
|
||||
>
|
||||
<Menu.Item key="field">
|
||||
<Icon type="file-text" />字段管理
|
||||
</Menu.Item>
|
||||
<Menu.Item key="preItem">
|
||||
<Icon type="copy" />预处理管理
|
||||
</Menu.Item>
|
||||
<Menu.Item key="datalist">
|
||||
<Icon type="appstore" />黑/白名单管理
|
||||
</Menu.Item>
|
||||
<Menu.Item key="abstractionList">
|
||||
<Icon type="picture" />抽象处理
|
||||
</Menu.Item>
|
||||
<Menu.Item key="activation">
|
||||
<Icon type="solution" />策略管理
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
12
webapp/component/model/Model.less
Normal file
12
webapp/component/model/Model.less
Normal file
@@ -0,0 +1,12 @@
|
||||
#header {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 0;
|
||||
padding-left: 20px;
|
||||
background: #ECECEC;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
i{
|
||||
cursor:pointer
|
||||
}
|
||||
225
webapp/component/model/ModelList.jsx
Normal file
225
webapp/component/model/ModelList.jsx
Normal file
@@ -0,0 +1,225 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message,Modal,Icon} from 'antd';
|
||||
import { Link } from 'react-router';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import AddModel from './modal/AddModel';
|
||||
import EditModel from './modal/EditModel';
|
||||
import StaticField from './modal/StaticField';
|
||||
import CopyModel from './modal/CopyModel';
|
||||
|
||||
import './Model.less';
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class ModelList extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
modelName:'',
|
||||
status:"1",
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.label=this.state.modelName;
|
||||
//param.status=this.state.status; 默认查询不传递该参数,否则只有单一数据,不完整
|
||||
|
||||
FetchUtil('/model','POST',JSON.stringify(param),
|
||||
(data)=>{
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
copyModel=(r)=>{
|
||||
var param={};
|
||||
param.id=r.id;
|
||||
param.modelName=r.modelName;
|
||||
param.label=r.label;
|
||||
param.entityName=r.entityName;
|
||||
param.entryName=r.entryName;
|
||||
param.guid=r.guid;
|
||||
param.referenceDate=r.referenceDate;
|
||||
param.status=r.status;
|
||||
FetchUtil('/model/copy','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('复制成功!');
|
||||
}
|
||||
else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.fetchTableData();
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deleteModel=(id)=>{
|
||||
FetchUtil('/model/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('删除成功!');
|
||||
}
|
||||
else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.fetchTableData();
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
let showGuid=function(guid){
|
||||
Modal.info({
|
||||
title: '通过接口上传请携带此参数',
|
||||
content: 'guid:'+guid,
|
||||
});
|
||||
}
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '模型名',
|
||||
dataIndex: 'label'
|
||||
},
|
||||
{
|
||||
title: '实体名',
|
||||
dataIndex: 'entityName'
|
||||
}, {
|
||||
title: '事件ID',
|
||||
dataIndex: 'entryName'
|
||||
}, {
|
||||
title: '唯一标识',
|
||||
dataIndex: 'guid',
|
||||
render:(t,r,i)=>{
|
||||
return <a onClick={showGuid.bind(this,r.guid)}>查看</a>;
|
||||
}
|
||||
},{
|
||||
title: '事件时间',
|
||||
dataIndex: 'referenceDate'
|
||||
},{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
{r.entityName?
|
||||
<Tooltip title="进入模型"><Link to={"/field/"+r.id}>进入模型</Link></Tooltip>
|
||||
:
|
||||
<StaticField row={r} reload={this.fetchTableData}/>
|
||||
}
|
||||
<span className="ant-divider"></span>
|
||||
{r.entityName?
|
||||
<CopyModel tData={this.state.tData} row={r} reload={this.fetchTableData}/>
|
||||
:
|
||||
''
|
||||
}
|
||||
{r.entityName?<span className="ant-divider"></span>:''}
|
||||
|
||||
<EditModel tData={this.state.tData} row={r} reload={this.fetchTableData}/><span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该模型吗?'} onConfirm={this.deleteModel.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-wrapper">
|
||||
<div className="ant-layout-breadcrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>首页</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>模型列表</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<div className="ant-layout-container">
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="模型名:">
|
||||
<Input value={this.state.modelName} name="modelName" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<AddModel tData={this.state.tData} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData.filter((item,index,array)=>{
|
||||
let reg = new RegExp('('+ this.state.modelName+')','gi');
|
||||
if(this.state.modelName){
|
||||
return (reg.test(item.label));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
193
webapp/component/model/modal/AddModel.jsx
Normal file
193
webapp/component/model/modal/AddModel.jsx
Normal file
@@ -0,0 +1,193 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddModel extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
label:'',
|
||||
|
||||
templateList:[],
|
||||
templateId:''
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var tData = this.props.tData.some((item)=>{
|
||||
if(item.label===e.target.value){
|
||||
return true;
|
||||
};
|
||||
});
|
||||
if(tData){
|
||||
Modal.error({
|
||||
title: '信息提示',
|
||||
content: '模型名重复',
|
||||
});
|
||||
}
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true,
|
||||
label:'',
|
||||
});
|
||||
FetchUtil('/model/list/template','GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
templateList:data.data.modelList
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else if(this.state.templateId!=""){
|
||||
var param={};
|
||||
param.id=this.state.templateId;
|
||||
param.modelName='';
|
||||
param.label=this.state.label;
|
||||
param.entityName='';
|
||||
param.entryName='';
|
||||
param.referenceDate='';
|
||||
|
||||
FetchUtil('/model/copy','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('添加成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.modelName='';
|
||||
param.label=this.state.label;
|
||||
param.entityName='';
|
||||
param.entryName='';
|
||||
param.referenceDate='';
|
||||
|
||||
FetchUtil('/model/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('添加成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入模型名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的模型名';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="编辑模型" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="模型名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型显示名称,一般为中文,如"注册模型"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
|
||||
<FormItem {...formItemLayout} label="模板:">
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select value={this.state.templateId} onChange={this.handleSelect.bind(this,'templateId')}>
|
||||
<Option value="">新建模型</Option>
|
||||
{
|
||||
this.state.templateList.map((info,index)=>{
|
||||
return <Option key={index} value={info.id+''}>{'[系统]'+info.label}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'可选择从模板一键创建模型,也可不选择模板而自行创建模型'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
146
webapp/component/model/modal/CopyModel.jsx
Normal file
146
webapp/component/model/modal/CopyModel.jsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class CopyModel extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
modelName:'',
|
||||
label:'',
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var tData = this.props.tData.some((item)=>{
|
||||
if(item.label===e.target.value){
|
||||
return true;
|
||||
};
|
||||
});
|
||||
if(tData){
|
||||
Modal.error({
|
||||
title: '信息提示',
|
||||
content: '模型名重复',
|
||||
});
|
||||
}
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true,
|
||||
|
||||
modelName:'',
|
||||
label:'',
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.modelName='';
|
||||
param.label=this.state.label;
|
||||
|
||||
FetchUtil('/model/copy','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('复制成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入模型名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的模型名';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="复制模型" onClick={this.showModal}><a>复制</a></Tooltip>
|
||||
<Modal title="复制模型" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem {...formItemLayout} label="复制模型:">
|
||||
<label>{this.props.row.label}</label>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="新模型名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型显示名称,一般为中文,如"注册模型"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
167
webapp/component/model/modal/EditModel.jsx
Normal file
167
webapp/component/model/modal/EditModel.jsx
Normal file
@@ -0,0 +1,167 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const createForm = Form.create;
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditModel extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
modelName:'',
|
||||
label:'',
|
||||
entityName:'',
|
||||
entryName:'',
|
||||
guid:'',
|
||||
referenceDate:'',
|
||||
status:'',
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/model/'+this.props.row.id,'GET',null,
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
modelName:model.modelName,
|
||||
label:model.label,
|
||||
entityName:model.entityName,
|
||||
entryName:model.entryName,
|
||||
guid:model.guid,
|
||||
referenceDate:model.referenceDate,
|
||||
status:model.status+''
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var tData = this.props.tData.some((item)=>{
|
||||
if(item.label===e.target.value){
|
||||
return true;
|
||||
};
|
||||
});
|
||||
if(tData){
|
||||
Modal.error({
|
||||
title: '信息提示',
|
||||
content: '模型名重复',
|
||||
});
|
||||
}
|
||||
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.modelName=this.state.modelName;
|
||||
param.label=this.state.label;
|
||||
param.entityName=this.state.entityName;
|
||||
param.entryName=this.state.entryName;
|
||||
param.guid=this.state.guid;
|
||||
param.referenceDate=this.state.referenceDate;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/model/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('修改成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入模型名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的模型名';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑模型" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="模型名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型显示名称,一般为中文,如"注册模型"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
402
webapp/component/model/modal/StaticField.jsx
Normal file
402
webapp/component/model/modal/StaticField.jsx
Normal file
@@ -0,0 +1,402 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class StaticField extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
entityName:'',
|
||||
entityType:'',
|
||||
entityLabel:'',
|
||||
|
||||
entryName:'',
|
||||
entryType:'',
|
||||
entryLabel:'',
|
||||
|
||||
referenceDate:'',
|
||||
referenceDateType:'LONG',
|
||||
referenceDateLabel:'',
|
||||
|
||||
visible:false,
|
||||
fieldTypes:[]
|
||||
}
|
||||
|
||||
FetchUtil('/common/fieldtypes','GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldTypes:data.data.fields
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true,
|
||||
|
||||
entityName:'',
|
||||
entityType:'',
|
||||
entityLabel:'',
|
||||
entryName:'',
|
||||
entryType:'',
|
||||
entryLabel:'',
|
||||
referenceDate:'',
|
||||
referenceDateType:'LONG',
|
||||
referenceDateLabel:'',
|
||||
})
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
let model=this.props.row;
|
||||
model.entityName=this.state.entityName;
|
||||
model.entryName=this.state.entryName;
|
||||
model.referenceDate=this.state.referenceDate;
|
||||
|
||||
FetchUtil('/model/','PUT',JSON.stringify(model),
|
||||
(data) => {
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
|
||||
var entity={};
|
||||
entity.modelId=this.props.row.id;
|
||||
entity.fieldName=this.state.entityName;
|
||||
entity.label=this.state.entityLabel;
|
||||
entity.fieldType=this.state.entityType;
|
||||
entity.indexed=true;
|
||||
FetchUtil('/field/','PUT',JSON.stringify(entity),() => {});
|
||||
|
||||
var entry={};
|
||||
entry.modelId=this.props.row.id;
|
||||
entry.fieldName=this.state.entryName;
|
||||
entry.label=this.state.entryLabel;
|
||||
entry.fieldType=this.state.entryType;
|
||||
entry.indexed=true;
|
||||
FetchUtil('/field/','PUT',JSON.stringify(entry),() => {});
|
||||
|
||||
var referenceDate={};
|
||||
referenceDate.modelId=this.props.row.id;
|
||||
referenceDate.fieldName=this.state.referenceDate;
|
||||
referenceDate.label=this.state.referenceDateLabel;
|
||||
referenceDate.fieldType=this.state.referenceDateType;
|
||||
referenceDate.indexed=true;
|
||||
FetchUtil('/field/','PUT',JSON.stringify(referenceDate),() => {});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 5 },
|
||||
wrapperCol: { span: 19 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
entityName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
entityLabel:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
entityType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
entryName:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
entryLabel:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
entryType:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
referenceDate:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
referenceDateLabel:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.entityName){
|
||||
validate.entityName.help='请输入实体名';
|
||||
validate.entityName.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let entityName = this.state.entityName;
|
||||
if(!reg.test(entityName)){
|
||||
validate.entityName.help='按照提示输入正确的实体名';
|
||||
validate.entityName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.entityLabel){
|
||||
validate.entityLabel.help='请输入实体显示名';
|
||||
validate.entityLabel.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let entityLabel = this.state.entityLabel;
|
||||
if(!reg.test(entityLabel)){
|
||||
validate.entityLabel.help='按照提示输入正确的实体显示名';
|
||||
validate.entityLabel.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.entityType){
|
||||
validate.entityType.help='请选择实体类型';
|
||||
validate.entityType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.entryName){
|
||||
validate.entryName.help='请输入事件ID';
|
||||
validate.entryName.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let entryName = this.state.entryName;
|
||||
if(!reg.test(entryName)){
|
||||
validate.entryName.help='按照提示输入正确的事件ID';
|
||||
validate.entryName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(this.state.entityName&&(this.state.entityName==this.state.entryName)){
|
||||
validate.entryName.help='事件ID不能与实体名相同!';
|
||||
validate.entryName.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.entryLabel){
|
||||
validate.entryLabel.help='请输入事件ID显示名';
|
||||
validate.entryLabel.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let entryLabel = this.state.entryLabel;
|
||||
if(!reg.test(entryLabel)){
|
||||
validate.entryLabel.help='按照提示输入正确的事件ID显示名';
|
||||
validate.entryLabel.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.entryType){
|
||||
validate.entryType.help='请选择事件ID类型';
|
||||
validate.entryType.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(this.state.entityName&&(this.state.entityName==this.state.referenceDate)){
|
||||
validate.referenceDate.help='事件时间不能与实体名相同!';
|
||||
validate.referenceDate.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
if(this.state.entryName&&(this.state.entryName==this.state.referenceDate)){
|
||||
validate.referenceDate.help='事件时间不能与事件ID相同!';
|
||||
validate.referenceDate.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.referenceDate){
|
||||
validate.referenceDate.help='请输入事件时间';
|
||||
validate.referenceDate.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[a-zA-z]\w{1,29}$/;
|
||||
let referenceDate = this.state.referenceDate;
|
||||
if(!reg.test(referenceDate)){
|
||||
validate.referenceDate.help='按照提示输入正确的事件时间';
|
||||
validate.referenceDate.status='error';
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
if(!this.state.referenceDateLabel){
|
||||
validate.referenceDateLabel.help='请输入事件时间显示名';
|
||||
validate.referenceDateLabel.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let referenceDateLabel = this.state.referenceDateLabel;
|
||||
if(!reg.test(referenceDateLabel)){
|
||||
validate.referenceDateLabel.help='按照提示输入正确的事件时间显示名';
|
||||
validate.referenceDateLabel.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="创建必备字段"><a onClick={this.showModal}>创建必备字段</a></Tooltip>
|
||||
<Modal title="创建必备字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="实体名:" help={validate.entityName.help} validateStatus={validate.entityName.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="entityName" value={this.state.entityName} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型目标实体字段,如"deviceId"(2-30位英文字母、数字、下划线的组合,以英文字母开头)'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="实体显示名:" help={validate.entityLabel.help} validateStatus={validate.entityLabel.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="entityLabel" value={this.state.entityLabel} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型目标实体显示名称,可以输入中文'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="实体类型:" help={validate.entityType.help} validateStatus={validate.entityType.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select size="large" name="entityType" value={this.state.entityType} onChange={this.handleSelect.bind(this,'entityType')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.state.fieldTypes.map(x=><Option key={x.name} value={x.name}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型目标实体类型,请选择类型'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件ID:" help={validate.entryName.help} validateStatus={validate.entryName.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="entryName" value={this.state.entryName} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型时间ID字段,一般为模型主键,如"id"(2-30位英文字母、数字、下划线的组合,以英文字母开头)'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件ID显示:" help={validate.entryLabel.help} validateStatus={validate.entryLabel.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="entryLabel" value={this.state.entryLabel} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型目标实体显示名称,可以输入中文'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件ID类型:" help={validate.entryType.help} validateStatus={validate.entryType.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select size="large" name="entryType" value={this.state.entryType} onChange={this.handleSelect.bind(this,'entryType')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.state.fieldTypes.map(x=><Option key={x.name} value={x.name}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型目标实体类型,请选择类型'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件时间:" help={validate.referenceDate.help} validateStatus={validate.referenceDate.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="referenceDate" value={this.state.referenceDate} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型事件时间字段,如"accessTime"(2-30位英文字母、数字、下划线的组合,以英文字母开头)'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件时间显示:" help={validate.referenceDateLabel.help} validateStatus={validate.referenceDateLabel.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input size="large" style={{marginTop:2}} type="text" name="referenceDateLabel" value={this.state.referenceDateLabel} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'模型事件时间显示名称,可以输入中文'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="事件时间类型:">
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select disabled size="large" value={this.state.referenceDateType}>
|
||||
<Option value="LONG">长整数</Option>
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'事件时间类型,固定为长整数'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
191
webapp/component/preItem/PreItem.jsx
Normal file
191
webapp/component/preItem/PreItem.jsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Form,Row,Col,Input,Button,Table,Tooltip,Pagination,Select,Popconfirm,message} from 'antd';
|
||||
const FormItem = Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import AddPreItem from './modal/AddPreItem';
|
||||
import EditPreItem from './modal/EditPreItem';
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class PreItem extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
destField:'',
|
||||
label:'',
|
||||
plugin:"",
|
||||
status:1,
|
||||
|
||||
tData:[],
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
loading:true,
|
||||
|
||||
model:null,
|
||||
filedList:[],
|
||||
plugins:[]
|
||||
}
|
||||
|
||||
FetchUtil('/model/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
const model=data.data.model;
|
||||
this.setState({
|
||||
model:model
|
||||
});
|
||||
});
|
||||
FetchUtil('/field/list/'+this.props.params.id,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldList:data.data.field
|
||||
});
|
||||
});
|
||||
|
||||
FetchUtil('/common/plugins','GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
plugins:data.data.plugins
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=1000;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.params.id;
|
||||
param.destField=this.state.destField;
|
||||
param.label=this.state.label;
|
||||
param.plugin=this.state.plugin;
|
||||
param.status=this.state.status;
|
||||
|
||||
FetchUtil('/preitem','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({loading:false});
|
||||
this.setState({
|
||||
tData:data.data.page.list,
|
||||
pageNo:data.data.page.pageNum,
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.setState({
|
||||
pageNo:1
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
deletePreItem=(id)=>{
|
||||
FetchUtil('/preitem/','DELETE','['+id+']',
|
||||
(data) => {
|
||||
message.info('删除成功!');
|
||||
this.fetchTableData();
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},{
|
||||
title: '字段名',
|
||||
dataIndex: 'label'
|
||||
},{
|
||||
title: '来源字段名',
|
||||
dataIndex: 'sourceLabel'
|
||||
},{
|
||||
title: '插件',
|
||||
dataIndex: 'plugin',
|
||||
render:
|
||||
(t) =>{
|
||||
let plugin=this.state.plugins.filter(x=>x.method==t);
|
||||
return plugin.length!=0?plugin[0].desc:'';
|
||||
}
|
||||
},{
|
||||
title: '插件参数(可选)',
|
||||
dataIndex: 'args'
|
||||
},{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:
|
||||
(t,r,i) => {
|
||||
return(
|
||||
<span>
|
||||
<EditPreItem modelId={this.props.params.id} row={r} fieldList={this.state.fieldList} plugins={this.state.plugins} reload={this.fetchTableData}/>
|
||||
<span className="ant-divider"></span>
|
||||
<Popconfirm placement="bottomRight" title={'确认删除该字段吗?'} onConfirm={this.deletePreItem.bind(this,r.id)}>
|
||||
<Tooltip title="删除"><a style={{color:'#FD5B5B'}}>删除</a></Tooltip>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="字段名:">
|
||||
<Input value={this.state.destField} name="destField" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
{' '}
|
||||
<AddPreItem modelId={this.props.params.id} fieldList={this.state.fieldList} plugins={this.state.plugins} reload={this.fetchTableData} />
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData.filter((item,index,array)=>{
|
||||
var reg = new RegExp('('+ this.state.destField+')','gi');
|
||||
if(this.state.destField){
|
||||
return (reg.test(item.label));
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
})}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<div style={{display:"none",width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
265
webapp/component/preItem/modal/AddPreItem.jsx
Normal file
265
webapp/component/preItem/modal/AddPreItem.jsx
Normal file
@@ -0,0 +1,265 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class AddPreItem extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
destField:'',
|
||||
label:'',
|
||||
sourceField:'',
|
||||
sourceLabel:'',
|
||||
plugin:'',
|
||||
status:1,
|
||||
args:''
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
if(name=='plugin'){
|
||||
state['sourceField']='';
|
||||
state['sourceLabel']='';
|
||||
state['args']='';
|
||||
}
|
||||
state[name] = trim(value);
|
||||
|
||||
if(name=='sourceField'){
|
||||
state['sourceLabel']=this.props.fieldList.filter(x=>x.fieldName==value)[0].label;
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleMultiSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
if(value==''){
|
||||
state[name]='';
|
||||
}
|
||||
else{
|
||||
state[name] = trim(value.join(','));
|
||||
state['sourceLabel'] = value.map((info)=>{
|
||||
return this.props.fieldList.filter(x=>x.fieldName==info)[0].label;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
destField:'',
|
||||
label:'',
|
||||
sourceField:'',
|
||||
sourceLabel:'',
|
||||
plugin:'',
|
||||
status:1,
|
||||
args:'',
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.modelId=this.props.modelId;
|
||||
param.destField=this.state.destField;
|
||||
param.label=this.state.label;
|
||||
param.sourceField=this.state.sourceField;
|
||||
param.sourceLabel=this.state.sourceLabel;
|
||||
param.plugin=this.state.plugin;
|
||||
param.status=this.state.status;
|
||||
param.args=this.state.args;
|
||||
|
||||
FetchUtil('/preitem/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('添加成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
plugin:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
sourceField:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
args:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.plugin){
|
||||
validate.plugin.help='请选择插件';
|
||||
validate.plugin.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入目标字段名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的目标显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.sourceField){
|
||||
validate.sourceField.help='请选择原始字段名';
|
||||
validate.sourceField.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.args){
|
||||
validate.args.help='请输入截取字段位数';
|
||||
validate.args.status='warning';
|
||||
if(this.state.plugin=='SUBSTRING'){
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
|
||||
const plugin=this.state.plugin;
|
||||
let fieldArr=this.state.sourceField==''?[]:this.state.sourceField.split(',');
|
||||
return (
|
||||
<span>
|
||||
<Button onClick={this.showModal} type="primary">新增</Button>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="插件种类:" help={validate.plugin.help} validateStatus={validate.plugin.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select value={this.state.plugin} onChange={this.handleSelect.bind(this,'plugin')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.props.plugins.map(x=><Option key={x.key} value={x.method}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'插件种类,如 IP转换成地址(将IP地址转换成详细的实际地址),字段合并(将多个原始字段合并起来),字符串截短(例将手机号码截取部分进行筛选,如前七位0,7),等等'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="目标字段名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段显示名称,一般为中文,如"IP归属地"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="原始字段名:" style={plugin!='ALLINONE'?{}:{display:"none"}} help={validate.sourceField.help} validateStatus={validate.sourceField.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select value={this.state.sourceField} onChange={this.handleSelect.bind(this,'sourceField')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.props.fieldList==null?'':this.props.fieldList.map(x=><Option key={x.id} value={x.fieldName}>{x.label}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'原始字段名,均为自己定义的字段名'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="原始字段名:" style={plugin=='ALLINONE'?{}:{display:"none"}} help={validate.sourceField.help} validateStatus={validate.sourceField.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select multiple placeholder="Please select" value={fieldArr} onChange={this.handleMultiSelect.bind(this,'sourceField')}>
|
||||
{
|
||||
this.props.fieldList==null?'':this.props.fieldList.map(x=><Option key={x.id} value={x.fieldName}>{x.label}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'原始字段名,均为自己定义的字段名'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="截取位数" style={plugin=='SUBSTRING'?{}:{display:"none"}} help={validate.args.help} validateStatus={validate.args.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="args" value={this.state.args} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'截取位数,属于字符串截短插件的参数,如筛选手机号码前7位,填写 0,7'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
280
webapp/component/preItem/modal/EditPreItem.jsx
Normal file
280
webapp/component/preItem/modal/EditPreItem.jsx
Normal file
@@ -0,0 +1,280 @@
|
||||
import React from 'react';
|
||||
import {Button,Checkbox,Select,Radio,Switch,Form,Row,Col,Icon,Modal,Input,InputNumber,Cascader,Tooltip,message } from 'antd';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../../utils/fetchUtil';
|
||||
import {trim} from '../../utils/validateUtil';
|
||||
|
||||
export default class EditPreItem extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
visible:false,
|
||||
|
||||
destField:'',
|
||||
label:'',
|
||||
sourceField:'',
|
||||
sourceLabel:'',
|
||||
plugin:'',
|
||||
status:1,
|
||||
args:'',
|
||||
|
||||
preItem:null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchData=()=>{
|
||||
FetchUtil('/preitem/'+this.props.row.id,'GET','',
|
||||
(data) => {
|
||||
const preItem=data.data.preItem;
|
||||
this.setState({
|
||||
destField:preItem.destField,
|
||||
label:preItem.label,
|
||||
sourceField:preItem.sourceField,
|
||||
sourceLabel:preItem.sourceLabel,
|
||||
plugin:preItem.plugin,
|
||||
status:preItem.status,
|
||||
args:preItem.args
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
if(name=='plugin'){
|
||||
state['sourceField']='';
|
||||
state['sourceLabel']='';
|
||||
state['args']='';
|
||||
}
|
||||
state[name] = trim(value);
|
||||
|
||||
if(name=='sourceField'){
|
||||
state['sourceLabel']=this.props.fieldList.filter(x=>x.fieldName==value)[0].label;
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleMultiSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
if(value==''){
|
||||
state[name]='';
|
||||
}
|
||||
else{
|
||||
state[name] = trim(value.join(','));
|
||||
state['sourceLabel'] = value.map((info)=>{
|
||||
return this.props.fieldList.filter(x=>x.fieldName==info)[0].label;
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
showModal=()=>{
|
||||
this.fetchData();
|
||||
this.setState({
|
||||
visible:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSubmit=(validated)=>{
|
||||
if(!validated){
|
||||
Modal.error({
|
||||
title: '提交失败',
|
||||
content: '请确认表单内容输入正确',
|
||||
});
|
||||
}
|
||||
else{
|
||||
var param={};
|
||||
param.id=this.props.row.id;
|
||||
param.modelId=this.props.modelId;
|
||||
param.destField=this.state.destField;
|
||||
param.label=this.state.label;
|
||||
param.sourceField=this.state.sourceField;
|
||||
param.sourceLabel=this.state.sourceLabel;
|
||||
param.plugin=this.state.plugin;
|
||||
param.status=this.state.status;
|
||||
param.args=this.state.args;
|
||||
|
||||
FetchUtil('/preitem/','PUT',JSON.stringify(param),
|
||||
(data) => {
|
||||
if(data.success){
|
||||
message.success('修改成功');
|
||||
}else{
|
||||
message.error(data.msg);
|
||||
}
|
||||
this.setState({
|
||||
visible:false
|
||||
});
|
||||
this.props.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
const formItemLayout = {
|
||||
labelCol: { span: 6 },
|
||||
wrapperCol: { span: 16 },
|
||||
};
|
||||
|
||||
let validate={
|
||||
plugin:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
label:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
sourceField:{
|
||||
help:'',
|
||||
status:'success'
|
||||
},
|
||||
args:{
|
||||
help:'',
|
||||
status:'success'
|
||||
}
|
||||
};
|
||||
let isValidated=true;
|
||||
|
||||
if(!this.state.plugin){
|
||||
validate.plugin.help='请选择插件';
|
||||
validate.plugin.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.label){
|
||||
validate.label.help='请输入目标字段名';
|
||||
validate.label.status='warning';
|
||||
isValidated=false;
|
||||
}else {
|
||||
let reg = /^[\u4e00-\u9fa5 \w]{2,20}$/;
|
||||
let label = this.state.label;
|
||||
if(!reg.test(label)){
|
||||
validate.label.help='按照提示输入正确的目标显示名称';
|
||||
validate.label.status='error';
|
||||
isValidated=false;
|
||||
|
||||
}
|
||||
}
|
||||
if(!this.state.sourceField){
|
||||
validate.sourceField.help='请选择原始字段名';
|
||||
validate.sourceField.status='warning';
|
||||
isValidated=false;
|
||||
}
|
||||
if(!this.state.args){
|
||||
validate.args.help='请输入截取字段位数';
|
||||
validate.args.status='warning';
|
||||
if(this.state.plugin=='SUBSTRING'){
|
||||
isValidated=false;
|
||||
}
|
||||
}
|
||||
|
||||
const plugin=this.state.plugin;
|
||||
let fieldArr=this.state.sourceField==''?[]:this.state.sourceField.split(',');
|
||||
return (
|
||||
<span>
|
||||
<Tooltip title="编辑" onClick={this.showModal}><a>编辑</a></Tooltip>
|
||||
<Modal title="编辑字段" visible={this.state.visible} onOk={this.handleSubmit.bind(this,isValidated)} onCancel={this.handleCancel}>
|
||||
<Form horizontal form={this.props.form}>
|
||||
<FormItem required={true} {...formItemLayout} label="插件种类:" help={validate.plugin.help} validateStatus={validate.plugin.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select value={this.state.plugin} onChange={this.handleSelect.bind(this,'plugin')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.props.plugins.map(x=><Option key={x.key} value={x.method}>{x.desc}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'插件种类,如 IP转换成地址(将IP地址转换成详细的实际地址),字段合并(将多个原始字段合并起来),字符串截短(例将手机号码截取部分进行筛选,如前七位0,7),等等'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="目标字段名:" help={validate.label.help} validateStatus={validate.label.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="label" value={this.state.label} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'字段显示名称,一般为中文,如"IP归属地"'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="原始字段名:" style={plugin!='ALLINONE'?{}:{display:"none"}} help={validate.sourceField.help} validateStatus={validate.sourceField.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select value={this.state.sourceField} onChange={this.handleSelect.bind(this,'sourceField')}>
|
||||
<Option value="">请选择</Option>
|
||||
{
|
||||
this.props.fieldList.map(x=><Option key={x.id} value={x.fieldName}>{x.label}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'原始字段名,均为自己定义的字段名'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="原始字段名:" style={plugin=='ALLINONE'?{}:{display:"none"}} help={validate.sourceField.help} validateStatus={validate.sourceField.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Select multiple placeholder="Please select" value={fieldArr} onChange={this.handleMultiSelect.bind(this,'sourceField')}>
|
||||
{
|
||||
this.props.fieldList.map(x=><Option key={x.id} value={x.fieldName}>{x.label}</Option>)
|
||||
}
|
||||
</Select>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'原始字段名,均为自己定义的字段名'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
<FormItem required={true} {...formItemLayout} label="截取位数" style={plugin=='SUBSTRING'?{}:{display:"none"}} help={validate.args.help} validateStatus={validate.args.status}>
|
||||
<Row>
|
||||
<Col span={20}>
|
||||
<Input type="text" name="args" value={this.state.args} onChange={this.handleChange}/>
|
||||
</Col>
|
||||
<Col span={2} offset={1}>
|
||||
<Tooltip placement="right" title={'截取位数,属于字符串截短插件的参数,如筛选手机号码前7位,填写 0,7'}>
|
||||
<Icon style={{fontSize:16}} type="question-circle-o" />
|
||||
</Tooltip>
|
||||
</Col>
|
||||
</Row>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
509
webapp/component/report/ListEvent.jsx
Normal file
509
webapp/component/report/ListEvent.jsx
Normal file
@@ -0,0 +1,509 @@
|
||||
import React from 'react';
|
||||
import {Form,Button,Table,Pagination,Input,Select,Modal,DatePicker,Cascader} from 'antd';
|
||||
import moment from 'moment';
|
||||
|
||||
const FormItem=Form.Item;
|
||||
const Option = Select.Option;
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
import './ListEvent.less';
|
||||
|
||||
import ExportField from './modal/ExportField';
|
||||
|
||||
export default class ListEvent extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
fieldName:'',
|
||||
fieldValue:'',
|
||||
activationName:'',
|
||||
ruleId:'',
|
||||
risk:'',
|
||||
beginTime:moment().add(-3,'days'),
|
||||
endTime:moment(),
|
||||
rangeSelect:'-3',
|
||||
|
||||
tData:[],
|
||||
loading:true,
|
||||
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
pageSize:30,
|
||||
|
||||
exportDisabled:true,
|
||||
showAdvance:false,
|
||||
searchType:''
|
||||
}
|
||||
|
||||
if(this.props.params.modelId){
|
||||
this.state.showAdvance=true;
|
||||
this.state.searchType='rule';
|
||||
this.state.activationName=this.props.params.activationName;
|
||||
this.state.ruleId=this.props.params.ruleId+'';
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=30;
|
||||
let param={};
|
||||
let errMsg='';
|
||||
switch(this.state.searchType){
|
||||
case '':param.fieldName='';param.fieldValue='';break;
|
||||
case 'field':
|
||||
if(!this.state.fieldName){
|
||||
errMsg='请选择字段!';
|
||||
break;
|
||||
}
|
||||
if(!this.state.fieldValue){
|
||||
errMsg='请输入字段值!';
|
||||
break;
|
||||
}
|
||||
param.fieldName=this.state.fieldName;
|
||||
param.fieldValue=this.state.fieldValue;
|
||||
break;
|
||||
case 'rule':
|
||||
if(!this.state.activationName){
|
||||
errMsg='请选择策略!';
|
||||
break;
|
||||
}
|
||||
if(!this.state.ruleId){
|
||||
errMsg='请选择规则!';
|
||||
break;
|
||||
}
|
||||
param.fieldName='hitsDetail.'+this.state.activationName+'.rule_'+this.state.ruleId+'.key';
|
||||
param.fieldValue=this.state.ruleId;
|
||||
break;
|
||||
case 'risk':
|
||||
if(!this.state.activationName){
|
||||
errMsg='请选择策略!';
|
||||
break;
|
||||
}
|
||||
if(!this.state.risk){
|
||||
errMsg='请选择评估结果!';
|
||||
break;
|
||||
}
|
||||
param.fieldName='activations.'+this.state.activationName+'.risk';
|
||||
param.fieldValue=this.state.risk;
|
||||
break;
|
||||
}
|
||||
|
||||
if(errMsg){
|
||||
Modal.error({
|
||||
title:errMsg
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.modelId;
|
||||
param.beginTime=this.state.beginTime.format('YYYY-MM-DD HH:mm:ss');
|
||||
param.endTime=this.state.endTime.format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
this.setState({loading:true});
|
||||
FetchUtil('/event/search','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({
|
||||
tData:data.data.page.list.map((info)=>{
|
||||
info=info.replace(/":(-?\d+)/g, "\":\"$1\"");
|
||||
return JSON.parse(info)}),
|
||||
pageNo:data.data.page.pageNum
|
||||
});
|
||||
if(data.data.page.rowCount > 9990){
|
||||
this.setState({
|
||||
rowCount:9990
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
}
|
||||
},
|
||||
()=>{
|
||||
this.setState({loading:false,exportDisabled:false});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(nextProps.modelId!=this.props.modelId){
|
||||
this.setState({
|
||||
fieldName:'',
|
||||
fieldValue:'',
|
||||
activationName:'',
|
||||
ruleId:'',
|
||||
risk:'',
|
||||
pageNo:1,
|
||||
fieldName:'',
|
||||
fieldValue:'',
|
||||
beginTime:moment().add(-3,'days'),
|
||||
endTime:moment(),
|
||||
rangeSelect:'-3',
|
||||
showAdvance:false,
|
||||
searchType:''
|
||||
},this.fetchTableData());
|
||||
}
|
||||
}
|
||||
|
||||
toggleAdvance=()=>{
|
||||
this.setState({
|
||||
showAdvance:!this.state.showAdvance,
|
||||
searchType:'',
|
||||
fieldName:'',
|
||||
fieldValue:'',
|
||||
activationName:'',
|
||||
ruleId:'',
|
||||
risk:'',
|
||||
});
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
state['exportDisabled']=true;
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name]=value;
|
||||
state['exportDisabled']=true;
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleCalendar=(dates,dateStrings)=>{
|
||||
this.setState({
|
||||
beginTime:dates[0],
|
||||
endTime:dates[1],
|
||||
rangeSelect:'',
|
||||
exportDisabled:true
|
||||
});
|
||||
}
|
||||
|
||||
handleChangeDate=(value)=>{
|
||||
//console.log(value);
|
||||
if(value === '-1'){
|
||||
this.setState({
|
||||
beginTime:moment().add(value,'months'),
|
||||
endTime:moment()
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
beginTime:moment().add(value,'days'),
|
||||
endTime:moment()
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
rangeSelect:value,
|
||||
exportDisabled:true
|
||||
});
|
||||
}
|
||||
|
||||
handleField=(value)=>{
|
||||
this.setState({
|
||||
fieldName:value.join("."),
|
||||
fieldValue:'',
|
||||
exportDisabled:true
|
||||
})
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.fetchTableData();
|
||||
if(this.props.location.pathname.indexOf('ruleid')!=-1){
|
||||
window.location.href='/#/event';
|
||||
}
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
displayRender = (labels, selectedOptions) => labels.map((label, i) => {
|
||||
const option = selectedOptions[i];
|
||||
if (i === labels.length - 1) {
|
||||
return (
|
||||
<span key={option.value+i}>
|
||||
{label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return <span key={option.value+i}>{label} / </span>;
|
||||
})
|
||||
|
||||
showModal=(record)=>{
|
||||
const hitsDetail=record.hitsDetail;
|
||||
const activations=record.activations;
|
||||
const columns=[{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},{
|
||||
title: '命中规则',
|
||||
dataIndex: 'desc',
|
||||
key: 'rule'
|
||||
},{
|
||||
title: '得分',
|
||||
dataIndex:'value'
|
||||
}];
|
||||
let data=[];
|
||||
for(var Key in hitsDetail){
|
||||
for(var subKey in hitsDetail[Key]){
|
||||
data.push(hitsDetail[Key][subKey]);
|
||||
}
|
||||
}
|
||||
const columnsActivation=[{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},{
|
||||
title: '策略名称',
|
||||
dataIndex: 'name',
|
||||
},{
|
||||
title: '得分',
|
||||
dataIndex:'score'
|
||||
},{
|
||||
title: '处理结果',
|
||||
dataIndex:'risk'
|
||||
}];
|
||||
let dataActivation=[];
|
||||
for(var Keys in activations){
|
||||
activations[Keys].name = Keys;
|
||||
if(activations[Keys].risk === 'pass'){
|
||||
activations[Keys].risk = '通过';
|
||||
}else if(activations[Keys].risk === 'review'){
|
||||
activations[Keys].risk = '人工审核';
|
||||
}else if(activations[Keys].risk === 'reject'){
|
||||
activations[Keys].risk = '拒绝';
|
||||
}
|
||||
dataActivation.push(activations[Keys]);
|
||||
}
|
||||
|
||||
Modal.info({
|
||||
title: '风险详情',
|
||||
width:600,
|
||||
content: (
|
||||
<div style={{paddingTop:20}}>
|
||||
<h3>命中明细</h3>
|
||||
<Table
|
||||
dataSource={data}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<h3 style={{paddingTop:20}}>策略明细</h3>
|
||||
<Table
|
||||
dataSource={dataActivation}
|
||||
columns={columnsActivation}
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
let columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
fixed:'left',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
let getChildren=(valueArr,children)=>{
|
||||
return children.map((info)=>{
|
||||
let va=valueArr.concat(info.value);
|
||||
if(info.children==undefined){
|
||||
let column={
|
||||
title:info.label,
|
||||
dataIndex:va.join(''),
|
||||
key:va.join(''),
|
||||
rowSpan:4-va.length,
|
||||
className:'fixed-table'
|
||||
};
|
||||
if(this.state.model!=null&&this.state.model.referenceDate==info.value){
|
||||
column.render=(t)=>{
|
||||
return moment(parseInt(t)).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
else{
|
||||
return {
|
||||
title:info.label,
|
||||
children:getChildren(va,info.children)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
columns=columns.concat(getChildren([],this.props.fieldList));
|
||||
|
||||
let dataList=[];
|
||||
this.state.tData.map((info)=>{
|
||||
let data={};
|
||||
|
||||
for(var Key in info.fields){
|
||||
data['fields'+Key]=info.fields[Key];
|
||||
}
|
||||
|
||||
for(var Key in info.preItems){
|
||||
if(typeof info.preItems[Key]=='object'){
|
||||
for(var subKey in info.preItems[Key]){
|
||||
data['preItems'+Key+subKey]=info.preItems[Key][subKey];
|
||||
}
|
||||
}
|
||||
else{
|
||||
data['preItems'+Key]=info.preItems[Key];
|
||||
}
|
||||
}
|
||||
|
||||
data['hitsDetail']=info.hitsDetail;
|
||||
data['activations']=info.activations;
|
||||
|
||||
dataList.push(data);
|
||||
});
|
||||
|
||||
const actList=this.props.activationList.filter(x=>x.value==this.state.activationName);
|
||||
let ruleList=[];
|
||||
if(actList.length!=0){
|
||||
ruleList=actList[0].children;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="起始时间">
|
||||
<Select dropdownMatchSelectWidth={false} showSearch placeholder="选择时间段" value={this.state.rangeSelect} onChange={this.handleChangeDate} style={{width:100,marginRight:10}}>
|
||||
<Option value='-3'>三天内</Option>
|
||||
<Option value='-7'>七天内</Option>
|
||||
<Option value='-1'>一月内</Option>
|
||||
</Select>
|
||||
<RangePicker value={[this.state.beginTime,this.state.endTime]} showTime format="YYYY/MM/DD HH:mm:ss" onChange={this.handleCalendar} />
|
||||
</FormItem>
|
||||
|
||||
<Button type="primary" onClick={this.handleSearch}>查询</Button>
|
||||
{' '}
|
||||
<ExportField eventFieldList={this.props.eventFieldList} disabled={this.state.exportDisabled}/>
|
||||
|
||||
<a onClick={this.toggleAdvance}>高级搜索>></a>
|
||||
</Form>
|
||||
{this.state.showAdvance?
|
||||
<Form inline style={{marginTop:5}}>
|
||||
<FormItem label="搜索种类">
|
||||
<Select dropdownMatchSelectWidth={false} placeholder="选择时间段" value={this.state.searchType} onChange={this.handleSelect.bind(this,'searchType')} style={{marginRight:10}}>
|
||||
<Option value=''>请选择搜索种类</Option>
|
||||
<Option value='field'>按字段搜索</Option>
|
||||
<Option value='rule'>按规则搜索</Option>
|
||||
<Option value='risk'>按评估结果搜索</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
{this.state.searchType==''?''
|
||||
:this.state.searchType=='field'?
|
||||
<span>
|
||||
<FormItem label="选择字段:">
|
||||
<Cascader
|
||||
options={this.props.fieldList}
|
||||
value={this.state.fieldName.split('.')}
|
||||
displayRender={this.displayRender}
|
||||
onChange={this.handleField}
|
||||
allowClear
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="字段值:">
|
||||
<Input value={this.state.fieldValue} name="fieldValue" id="blue" onChange={this.handleChange}/>
|
||||
</FormItem>
|
||||
</span>
|
||||
:this.state.searchType=='rule'?
|
||||
<span>
|
||||
<FormItem label="选择策略:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.activationName} onChange={this.handleSelect.bind(this,'activationName')} style={{width:100}}>
|
||||
{this.props.activationList.map((info,i)=>{
|
||||
return <Option key={info.label} value={info.value}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="选择规则:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.ruleId} onChange={this.handleSelect.bind(this,'ruleId')} style={{width:100}}>
|
||||
{ruleList==undefined?'':ruleList.map((info,i)=>{
|
||||
return <Option key={info.label} value={info.type}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
</span>
|
||||
:this.state.searchType=='risk'?
|
||||
<span>
|
||||
<FormItem label="选择策略:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.activationName} onChange={this.handleSelect.bind(this,'activationName')} style={{width:100}}>
|
||||
{this.props.activationList.map((info,i)=>{
|
||||
return <Option key={info.label} value={info.value}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="处理结果:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.risk} onChange={this.handleSelect.bind(this,'risk')} style={{width:100}}>
|
||||
<Option value='pass'>通过</Option>
|
||||
<Option value='review'>人工审核</Option>
|
||||
<Option value='reject'>拒绝</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</span>
|
||||
:''}
|
||||
</Form>
|
||||
:''
|
||||
}
|
||||
</div>
|
||||
|
||||
<div id="table" className="fixed-table">
|
||||
<Table
|
||||
dataSource={dataList}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
bordered
|
||||
onRowClick={this.showModal}
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
scroll={{ x: true }}
|
||||
/>
|
||||
<div style={{width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} defaultPageSize={this.state.pageSize} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
3
webapp/component/report/ListEvent.less
Normal file
3
webapp/component/report/ListEvent.less
Normal file
@@ -0,0 +1,3 @@
|
||||
.fixed-table{
|
||||
white-space: nowrap;
|
||||
}
|
||||
413
webapp/component/report/ListRule.jsx
Normal file
413
webapp/component/report/ListRule.jsx
Normal file
@@ -0,0 +1,413 @@
|
||||
import React from 'react';
|
||||
import {Form,Button,Table,Pagination,Input,Select,Modal,DatePicker,Cascader} from 'antd';
|
||||
import moment from 'moment';
|
||||
|
||||
const FormItem=Form.Item;
|
||||
const Option = Select.Option;
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
import './ListEvent.less';
|
||||
|
||||
export default class Rule extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
beginTime:moment().add(-3,'days'),
|
||||
endTime:moment(),
|
||||
rangeSelect:'-3',
|
||||
|
||||
endOpen:false,
|
||||
|
||||
tData:[],
|
||||
loading:true,
|
||||
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
pageSize:30,
|
||||
|
||||
activationName:'',
|
||||
ruleId:'',
|
||||
risk:[],
|
||||
activationNameOne:'' //存储策略中的第一个value值,便于按处理结果查询
|
||||
}
|
||||
|
||||
if(this.props.params.modelId){
|
||||
this.state.activationName=this.props.params.activationName;
|
||||
this.state.ruleId=this.props.params.ruleId+'';
|
||||
}
|
||||
}
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=()=>{
|
||||
const pageSize=30;
|
||||
this.setState({loading:true});
|
||||
|
||||
var param={};
|
||||
param.pageNo=this.state.pageNo;
|
||||
param.pageSize=pageSize;
|
||||
param.modelId=this.props.modelId;
|
||||
if(this.state.risk.length != 0){
|
||||
if(this.state.activationName!=''){
|
||||
param.fieldName='activations.'+this.state.activationName+'.risk';
|
||||
param.fieldValue=this.state.risk;
|
||||
}else {
|
||||
param.fieldName='activations.'+this.state.activationNameOne+'.risk';
|
||||
param.fieldValue=this.state.risk;
|
||||
}
|
||||
}else{
|
||||
if(this.state.activationName!=''){
|
||||
param.fieldName='hitsDetail.'+this.state.activationName+'.rule_'+this.state.ruleId+'.key';
|
||||
param.fieldValue=this.state.ruleId;
|
||||
}
|
||||
}
|
||||
|
||||
param.beginTime=this.state.beginTime.format('YYYY-MM-DD HH:mm:ss');
|
||||
param.endTime=this.state.endTime.format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
FetchUtil('/event/search','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
this.setState({
|
||||
tData:data.data.page.list.map((info)=>{return JSON.parse(info)}),
|
||||
pageNo:data.data.page.pageNum
|
||||
});
|
||||
if(data.data.page.rowCount > 9990){
|
||||
this.setState({
|
||||
rowCount:9990
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
rowCount:data.data.page.rowCount
|
||||
});
|
||||
}
|
||||
},
|
||||
()=>{
|
||||
this.setState({loading:false});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(nextProps.modelId!=this.props.modelId){
|
||||
this.setState({
|
||||
beginTime:moment().add(-3,'days'),
|
||||
endTime:moment(),
|
||||
rangeSelect:'-3',
|
||||
activationName:'',
|
||||
ruleId:'',
|
||||
},this.fetchTableData());
|
||||
}
|
||||
}
|
||||
|
||||
handleChange=(e)=>{
|
||||
var name = e.target.name;
|
||||
var value = e.target.value;
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
// if(name=='modelId'){
|
||||
// this.setState({
|
||||
// tData:[]
|
||||
// });
|
||||
// FetchUtil('/abstraction/datacolumns/'+value,'GET','',
|
||||
// (data) => {
|
||||
// this.setState({
|
||||
// fieldList:data.data.list
|
||||
// });
|
||||
// });
|
||||
// FetchUtil('/activation/rulecolumns/'+value,'GET','',
|
||||
// (data) => {
|
||||
// this.setState({
|
||||
// activationList:data.data.list
|
||||
// });
|
||||
// });
|
||||
// FetchUtil('/model/'+value,'GET','',
|
||||
// (data) => {
|
||||
// this.setState({
|
||||
// model:data.data.model
|
||||
// })
|
||||
// }
|
||||
// )
|
||||
// this.setState({
|
||||
// activationName:'',
|
||||
// ruleId:''
|
||||
// })
|
||||
// }
|
||||
if(name=='activationName'){
|
||||
const activation=this.props.activationList.filter(x=>x.value==value)[0];
|
||||
if(activation.children&&activation.children.length>0){
|
||||
this.setState({
|
||||
ruleId:activation.children[0].type
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleCalendar=(dates,dateStrings)=>{
|
||||
this.setState({
|
||||
beginTime:dates[0],
|
||||
endTime:dates[1]
|
||||
});
|
||||
}
|
||||
|
||||
handleChangeDate=(value)=>{
|
||||
//console.log(value);
|
||||
if(value === '-1'){
|
||||
this.setState({
|
||||
beginTime:moment().add(value,'months'),
|
||||
endTime:moment()
|
||||
});
|
||||
}else {
|
||||
this.setState({
|
||||
beginTime:moment().add(value,'days'),
|
||||
endTime:moment()
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
handleSearch=()=>{
|
||||
this.fetchTableData();
|
||||
}
|
||||
|
||||
selectPage=(page)=>{
|
||||
this.setState({
|
||||
pageNo:page
|
||||
},()=>{this.fetchTableData()});
|
||||
}
|
||||
|
||||
showModal=(record)=>{
|
||||
const hitsDetail=record.hitsDetail;
|
||||
const activations=record.activations;
|
||||
const columns=[{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},{
|
||||
title: '命中规则',
|
||||
dataIndex: 'desc',
|
||||
key: 'rule'
|
||||
},{
|
||||
title: '得分',
|
||||
dataIndex:'value'
|
||||
}];
|
||||
let data=[];
|
||||
for(var Key in hitsDetail){
|
||||
for(var subKey in hitsDetail[Key]){
|
||||
data.push(hitsDetail[Key][subKey]);
|
||||
}
|
||||
}
|
||||
|
||||
const columnsActivation=[{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
},{
|
||||
title: '策略名称',
|
||||
dataIndex: 'name',
|
||||
},{
|
||||
title: '得分',
|
||||
dataIndex:'score'
|
||||
},{
|
||||
title: '处理结果',
|
||||
dataIndex:'risk'
|
||||
}];
|
||||
let dataActivation=[];
|
||||
for(var Keys in activations){
|
||||
activations[Keys].name = Keys;
|
||||
if(activations[Keys].risk === 'pass'){
|
||||
activations[Keys].risk = '通过';
|
||||
}else if(activations[Keys].risk === 'review'){
|
||||
activations[Keys].risk = '人工审核';
|
||||
}else if(activations[Keys].risk === 'reject'){
|
||||
activations[Keys].risk = '拒绝';
|
||||
}
|
||||
dataActivation.push(activations[Keys]);
|
||||
}
|
||||
|
||||
Modal.info({
|
||||
title: '风险详情',
|
||||
width:600,
|
||||
content: (
|
||||
<div style={{paddingTop:20}}>
|
||||
<h3>命中明细</h3>
|
||||
<Table
|
||||
dataSource={data}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
<h3 style={{paddingTop:20}}>策略明细</h3>
|
||||
<Table
|
||||
dataSource={dataActivation}
|
||||
columns={columnsActivation}
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
let columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'id',
|
||||
key:'id',
|
||||
width:50,
|
||||
fixed:'left',
|
||||
render:(t,r,i)=>{
|
||||
return i+1;
|
||||
}
|
||||
}];
|
||||
|
||||
|
||||
let getChildren=(valueArr,children)=>{
|
||||
return children.map((info)=>{
|
||||
let va=valueArr.concat(info.value);
|
||||
if(info.children==undefined){
|
||||
let column={
|
||||
title:info.label,
|
||||
dataIndex:va.join(''),
|
||||
key:va.join(''),
|
||||
rowSpan:4-va.length,
|
||||
className:'fixed-table'
|
||||
};
|
||||
if(this.state.model!=null&&this.state.model.referenceDate==info.value){
|
||||
column.render=(t)=>{
|
||||
return moment(t).format('YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
else{
|
||||
return {
|
||||
title:info.label,
|
||||
children:getChildren(va,info.children)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
columns=columns.concat(getChildren([],this.props.fieldList));
|
||||
|
||||
let dataList=[];
|
||||
this.state.tData.map((info)=>{
|
||||
let data={};
|
||||
|
||||
for(var Key in info.fields){
|
||||
data['fields'+Key]=info.fields[Key];
|
||||
}
|
||||
|
||||
for(var Key in info.preItems){
|
||||
if(typeof info.preItems[Key]=='object'){
|
||||
for(var subKey in info.preItems[Key]){
|
||||
data['preItems'+Key+subKey]=info.preItems[Key][subKey];
|
||||
}
|
||||
}
|
||||
else{
|
||||
data['preItems'+Key]=info.preItems[Key];
|
||||
}
|
||||
}
|
||||
|
||||
data['hitsDetail']=info.hitsDetail;
|
||||
data['activations']=info.activations;
|
||||
|
||||
dataList.push(data);
|
||||
});
|
||||
|
||||
const actList=this.props.activationList.filter(x=>x.value==this.state.activationName);
|
||||
let ruleList=[];
|
||||
if(actList.length!=0){
|
||||
ruleList=actList[0].children;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<div id="header">
|
||||
<Form inline>
|
||||
<FormItem label="选择策略:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.activationName} onChange={this.handleSelect.bind(this,'activationName')} style={{width:100}}>
|
||||
{this.props.activationList.map((info,i)=>{
|
||||
return <Option key={info.label} value={info.value}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem label="选择规则:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.ruleId} onChange={this.handleSelect.bind(this,'ruleId')} style={{width:100}}>
|
||||
{ruleList==undefined?'':ruleList.map((info,i)=>{
|
||||
return <Option key={info.label} value={info.type}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
|
||||
<FormItem label="处理结果:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.risk} onChange={this.handleSelect.bind(this,'risk')} style={{width:100}}>
|
||||
<Option value='pass'>通过</Option>
|
||||
<Option value='review'>人工审核</Option>
|
||||
<Option value='reject'>拒绝</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
|
||||
|
||||
<FormItem label="起始时间">
|
||||
<Select dropdownMatchSelectWidth={false} showSearch defaultValue='-3' onChange={this.handleChangeDate} style={{width:100,marginRight:10}}>
|
||||
<Option value='-3'>三天内</Option>
|
||||
<Option value='-7'>七天内</Option>
|
||||
<Option value='-1'>一月内</Option>
|
||||
</Select>
|
||||
<RangePicker value={[this.state.beginTime,this.state.endTime]} showTime format="YYYY/MM/DD HH:mm:ss" onChange={this.handleCalendar} />
|
||||
</FormItem>
|
||||
|
||||
<Button type="primary" onClick={this.handleSearch}>查询</Button>
|
||||
{' '}
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div id="table" className="fixed-table">
|
||||
<Table
|
||||
dataSource={dataList}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
bordered
|
||||
onRowClick={this.showModal}
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
scroll={{ x: true }}
|
||||
/>
|
||||
<div style={{width:"100%",marginTop:16,height:40}}>
|
||||
<div style={{float:"right"}}>
|
||||
<Pagination onChange={this.selectPage} defaultCurrent={this.state.pageNo} defaultPageSize={this.state.pageSize} total={this.state.rowCount} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
143
webapp/component/report/Report.jsx
Normal file
143
webapp/component/report/Report.jsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import React from 'react';
|
||||
import {Breadcrumb,Menu,Icon,Form,Select} from 'antd';
|
||||
|
||||
const FormItem=Form.Item;
|
||||
const Option = Select.Option;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
|
||||
export default class Report extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
current:'',
|
||||
|
||||
modelList:[],
|
||||
modelId:'',
|
||||
fieldList:[],
|
||||
eventFieldList:[],
|
||||
activationList:[]
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=(e)=>{
|
||||
window.location.href='/#/'+e.key;
|
||||
this.setState({
|
||||
current:e.key
|
||||
})
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
let state=this.state;
|
||||
state[name]=value;
|
||||
this.setState(state);
|
||||
|
||||
FetchUtil('/abstraction/datacolumns/'+value,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
fieldList:data.data.list
|
||||
});
|
||||
});
|
||||
FetchUtil('/event/datacolumns/'+value,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
eventFieldList:data.data.list
|
||||
});
|
||||
});
|
||||
FetchUtil('/activation/rulecolumns/'+value,'GET','',
|
||||
(data) => {
|
||||
this.setState({
|
||||
activationList:data.data.list,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
let key='';
|
||||
let modelId='';
|
||||
switch(this.props.location.pathname.split('/')[1]){
|
||||
case 'event':
|
||||
key='event';break;
|
||||
case 'graph':
|
||||
key='graph';break;
|
||||
case 'ruleid':
|
||||
key='event';
|
||||
modelId=this.props.location.pathname.split('/')[2];
|
||||
break;
|
||||
case 'dashboard':
|
||||
key='dashboard';break;
|
||||
}
|
||||
this.setState({
|
||||
current:key
|
||||
});
|
||||
|
||||
FetchUtil('/model/list','GET',{},
|
||||
(data) => {
|
||||
this.setState({
|
||||
modelList:data.data.modelList
|
||||
},()=>{
|
||||
if(this.state.modelList.length>0&&modelId==''){
|
||||
this.handleSelect('modelId',this.state.modelList[0].id+'');
|
||||
}
|
||||
else{
|
||||
this.handleSelect('modelId',modelId);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getItems=()=>{
|
||||
if(this.state.modelId==''){
|
||||
return '请选择模型!';
|
||||
}
|
||||
const props={
|
||||
modelId:this.state.modelId,
|
||||
model:this.state.modelList.filter(x=>x.id==this.state.modelId)[0],
|
||||
fieldList:this.state.fieldList,
|
||||
eventFieldList:this.state.eventFieldList,
|
||||
activationList:this.state.activationList
|
||||
}
|
||||
return React.cloneElement(this.props.children,props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="ant-layout-wrapper">
|
||||
<div className="ant-layout-breadcrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>首页</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>报表查询</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<div className="ant-layout-container">
|
||||
<div style={{lineHeight:"46px",padding:"0 20px 0",margin:"0 24px",borderBottom:"1px solid #e9e9e9"}}>
|
||||
<Form inline>
|
||||
<FormItem label="模型:">
|
||||
<Select dropdownMatchSelectWidth={false} value={this.state.modelId} onChange={this.handleSelect.bind(this,'modelId')} style={{width:100}}>
|
||||
{this.state.modelList.map((info)=>{
|
||||
return <Option key={info.id} value={info.id+''}>{info.label}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="ant-layout-header" style={{padding:"0 24px 24px"}}>
|
||||
<Menu onClick={this.handleClick} selectedKeys={[this.state.current]} mode="horizontal">
|
||||
<Menu.Item key="event">
|
||||
<Icon type="file-text"/>调用查询
|
||||
</Menu.Item>
|
||||
<Menu.Item key="graph">
|
||||
<Icon type="pushpin-o"/>规则命中
|
||||
</Menu.Item>
|
||||
<Menu.Item key="dashboard">
|
||||
<Icon type="file-text"/>指示板
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</div>
|
||||
{this.getItems()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
171
webapp/component/report/RuleGraph.jsx
Normal file
171
webapp/component/report/RuleGraph.jsx
Normal file
@@ -0,0 +1,171 @@
|
||||
import React from 'react';
|
||||
import {Form,Button,Table,Pagination,Input,Select,Modal,DatePicker,Cascader} from 'antd';
|
||||
//import moment from 'moment';
|
||||
import { Link } from 'react-router';
|
||||
import echarts from 'echarts';
|
||||
|
||||
|
||||
const FormItem=Form.Item;
|
||||
const Option = Select.Option;
|
||||
/*
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
*/
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
export default class RuleGraph extends React.Component{
|
||||
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
modelId:'',
|
||||
tData:[],
|
||||
|
||||
loading:true,
|
||||
|
||||
pageNo:1,
|
||||
rowCount:0,
|
||||
|
||||
ruleLabelList:[],
|
||||
countList:[],
|
||||
|
||||
modelList:[],
|
||||
fieldList:[]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData=(value)=>{
|
||||
this.setState({loading:true});
|
||||
|
||||
FetchUtil('/rule/hitsSort/'+value,'GET',{},
|
||||
(data) => {
|
||||
this.setState({
|
||||
countList:data.data.hits.map((hit)=>{return hit.count}),
|
||||
ruleLabelList:data.data.hits.map((hit)=>{return hit.ruleLable}),
|
||||
tData:data.data.hits,
|
||||
loading:false
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount=()=>{
|
||||
this.fetchTableData(this.props.modelId);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(nextProps.modelId!=this.props.modelId){
|
||||
this.fetchTableData(nextProps.modelId);
|
||||
}
|
||||
}
|
||||
|
||||
handleSelect=(name,value)=>{
|
||||
var state = this.state;
|
||||
state[name] = trim(value);
|
||||
this.setState(state);
|
||||
|
||||
FetchUtil('/rule/hitsSort/'+value,'GET',{},
|
||||
(data) => {
|
||||
console.log(data.data.hits);
|
||||
this.setState({
|
||||
countList:data.data.hits.map((hit)=>{return hit.count}),
|
||||
ruleLabelList:data.data.hits.map((hit)=>{return hit.ruleLable}),
|
||||
tData:data.data.hits
|
||||
});
|
||||
|
||||
this.setState({loading:false});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
render(){
|
||||
|
||||
/*定义表格列*/
|
||||
const columns = [
|
||||
{
|
||||
title: '字段名',
|
||||
dataIndex: 'ruleLable'
|
||||
},
|
||||
{
|
||||
title: '命中数',
|
||||
dataIndex: 'count'
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'handle',
|
||||
render:(t,r)=>{
|
||||
return <Link to={"/ruleid/"+this.props.modelId+"/"+r.id+"/"+r.activationName} target="_blank">查看明细</Link>;
|
||||
}
|
||||
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
|
||||
<div id="echartsMain" style={{width:900,height:400}}></div>
|
||||
<div id="table">
|
||||
<Table
|
||||
dataSource={this.state.tData}
|
||||
columns={columns}
|
||||
size="middle"
|
||||
bordered
|
||||
pagination={false}
|
||||
loading={this.state.loading}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
componentDidUpdate=()=>{
|
||||
// 基于准备好的dom元素,初始化echarts实例
|
||||
let myChart = echarts.init(document.getElementById('echartsMain'));
|
||||
// 绘制图表
|
||||
myChart.setOption({
|
||||
tooltip : {
|
||||
trigger: 'axis',
|
||||
axisPointer : { // 坐标轴指示器,坐标轴触发有效
|
||||
type : 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['命中数']
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
yAxis: {
|
||||
type: 'category',
|
||||
data: this.state.ruleLabelList
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '命中数',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'right'
|
||||
}
|
||||
},
|
||||
data: this.state.countList
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
||||
52
webapp/component/report/dashboard.jsx
Normal file
52
webapp/component/report/dashboard.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import {Form,Button,Table,Pagination,Input,Select,Modal,DatePicker,Cascader} from 'antd';
|
||||
import moment from 'moment';
|
||||
|
||||
const FormItem=Form.Item;
|
||||
const Option = Select.Option;
|
||||
const RangePicker = DatePicker.RangePicker;
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
import {trim} from '../utils/validateUtil';
|
||||
|
||||
import './ListEvent.less';
|
||||
|
||||
export default class DashBoard extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
modelId:'',
|
||||
loading:true,
|
||||
modelList:[],
|
||||
dashboardUrl:''
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if(!this.props.model.dashboardUrl){
|
||||
Modal.warning({
|
||||
title: '信息提醒',
|
||||
content: '该模型统计报表未初始化!',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(this.props.modelId!=nextProps.modelId&&!nextProps.model.dashboardUrl){
|
||||
Modal.warning({
|
||||
title: '信息提醒',
|
||||
content: '该模型统计报表未初始化!',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<iframe ref="dashBoard" name="dashBoard" src={this.props.model.dashboardUrl} style={{minHeight:'800px',width:'100%',border:'0px'}}></iframe>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
99
webapp/component/report/modal/ExportField.jsx
Normal file
99
webapp/component/report/modal/ExportField.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import {Button,Modal,Tree,Tooltip} from 'antd';
|
||||
|
||||
const TreeNode = Tree.TreeNode;
|
||||
|
||||
import {FetchUtil,fetchVersion} from '../../utils/fetchUtil';
|
||||
|
||||
export default class ExportField extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
loading:false,
|
||||
visible:false,
|
||||
|
||||
selectedKeys:[]
|
||||
};
|
||||
|
||||
console.log(this.props.eventFieldList);
|
||||
}
|
||||
|
||||
|
||||
showModal=()=>{
|
||||
this.setState({
|
||||
visible:true
|
||||
});
|
||||
}
|
||||
|
||||
handleOk=()=>{
|
||||
if(this.state.selectedKeys.length==0){
|
||||
Modal.error({
|
||||
title: '请选择需要导出的字段'
|
||||
});
|
||||
}
|
||||
|
||||
let param={
|
||||
fields:[],
|
||||
preItems:[],
|
||||
activations:[],
|
||||
rules:[]
|
||||
};
|
||||
this.state.selectedKeys.forEach((info)=>{
|
||||
if(info&&info.indexOf('.')!=-1){
|
||||
let arr=info.split('.');
|
||||
param[arr[0]].push(arr[1]);
|
||||
}
|
||||
});
|
||||
FetchUtil('/event/export','POST',JSON.stringify(param),
|
||||
(data) => {
|
||||
var url=fetchVersion+"/event/download";
|
||||
var a = document.createElement('a');
|
||||
var filename = 'download.xlsx';
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
});
|
||||
}
|
||||
|
||||
handleCancel=()=>{
|
||||
this.setState({
|
||||
selectedKeys:[],
|
||||
visible:false
|
||||
})
|
||||
}
|
||||
|
||||
onSelect=(selectedKeys)=>{
|
||||
this.setState({ selectedKeys });
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<span>
|
||||
{this.props.disabled?
|
||||
<Tooltip title="导出前请先执行查询!">
|
||||
<Button disabled type="primary" loading={this.state.loading} onClick={this.showModal}>导出</Button>
|
||||
</Tooltip>
|
||||
:<Button type="primary" loading={this.state.loading} onClick={this.showModal}>导出</Button>
|
||||
}
|
||||
<Modal title="选择需要导出的字段" visible={this.state.visible} maskClosable={false} closable={false} onOk={this.handleOk} okText={'导出报表'} onCancel={this.handleCancel}>
|
||||
{this.props.eventFieldList.length==0?'该模型无字段可选':
|
||||
<Tree checkable onCheck={this.onCheck} onCheck={this.onSelect} selectedKeys={this.state.selectedKeys}>
|
||||
{this.props.eventFieldList.map((info,i)=>{
|
||||
return (
|
||||
<TreeNode key={info.value} title={info.label}>
|
||||
{info.children.map((child,i)=>{
|
||||
return <TreeNode key={info.value+'.'+child.value} title={child.label}/>
|
||||
})}
|
||||
</TreeNode>
|
||||
);
|
||||
})}
|
||||
</Tree>
|
||||
}
|
||||
</Modal>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
93
webapp/component/test/Collapse.jsx
Normal file
93
webapp/component/test/Collapse.jsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import React from 'react';
|
||||
import {Switch} from 'antd';
|
||||
|
||||
import './Collapse.less';
|
||||
|
||||
export default class Collapse extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
height:0
|
||||
}
|
||||
|
||||
//this.props.handleClick(this);
|
||||
|
||||
}
|
||||
|
||||
slideDown=()=>{
|
||||
if(this.state.height=="auto"){
|
||||
return;
|
||||
}
|
||||
if(this.state.height<this.refs.pChild.offsetHeight){
|
||||
this.setState({
|
||||
height:this.state.height+15
|
||||
},()=>{
|
||||
setTimeout(this.slideDown,1);
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:"auto"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
slideUp=()=>{
|
||||
if(this.state.height=="auto"){
|
||||
this.state.height=this.refs.pChild.offsetHeight;
|
||||
}
|
||||
if(this.state.height>0){
|
||||
this.setState({
|
||||
height:this.state.height-15
|
||||
},()=>{
|
||||
setTimeout(this.slideUp,1);
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=()=>{
|
||||
this.props.handleClick();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
if(nextProps.slide){
|
||||
this.slideDown();
|
||||
}
|
||||
else{
|
||||
this.slideUp();
|
||||
}
|
||||
}
|
||||
|
||||
handleDragStart=()=>{
|
||||
console.log(2);
|
||||
}
|
||||
|
||||
switchClick=(e)=>{
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div className="p-block" draggable="true" onDragStart={this.handleDragStart}>
|
||||
<div className={'p-block-titles'+(this.props.slide?' p-block-title-select':'')} onClick={this.handleClick}>
|
||||
<div className='p-block-title-left'>{this.props.title}</div>
|
||||
{this.props.switcher!=undefined?
|
||||
<div className='p-block-title-right' onClick={this.switchClick}><Switch /></div>
|
||||
:''}
|
||||
</div>
|
||||
<div className={'p-block-contents'+(this.props.slide?' p-block-content-select':'')} style={{height:this.state.height}} ref="pContent">
|
||||
<div ref="pChild" className="p-block-main">
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
48
webapp/component/test/Collapse.less
Normal file
48
webapp/component/test/Collapse.less
Normal file
@@ -0,0 +1,48 @@
|
||||
.p-block{
|
||||
margin-bottom:8px;
|
||||
}
|
||||
|
||||
.p-block-titles{
|
||||
height: 40px;
|
||||
border:1px solid #d9d9d9;
|
||||
padding-left: 30px;
|
||||
cursor:pointer;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.p-block-titles:hover{
|
||||
background-color:#FAFAFA;
|
||||
}
|
||||
|
||||
.p-block-title-left{
|
||||
float:left;
|
||||
line-height:38px;
|
||||
}
|
||||
|
||||
.p-block-title-right{
|
||||
float:right;
|
||||
line-height:34px;
|
||||
margin-right:20px;
|
||||
}
|
||||
|
||||
.p-block-title-select{
|
||||
background-color:#f7f7f7;
|
||||
border-bottom-right-radius:0;
|
||||
border-bottom-left-radius:0;
|
||||
border-bottom:none;
|
||||
}
|
||||
|
||||
.p-block-contents{
|
||||
clear:both;
|
||||
background-color:white;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.p-block-content-select{
|
||||
border:1px solid #d9d9d9;
|
||||
border-top:none;
|
||||
}
|
||||
|
||||
.p-block-main{
|
||||
padding:20px
|
||||
}
|
||||
48
webapp/component/test/CollapseGroup.jsx
Normal file
48
webapp/component/test/CollapseGroup.jsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React from 'react';
|
||||
|
||||
export default class CollapseGroup extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
activeKey:'',
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getItems=()=>{
|
||||
return this.props.children.map((child,index)=>{
|
||||
const key=child.key;
|
||||
const props={
|
||||
slide:child.key==this.state.activeKey?true:false,
|
||||
index:index,
|
||||
|
||||
handleClick:()=>{
|
||||
if(this.state.activeKey==key){
|
||||
this.setState({
|
||||
activeKey:''
|
||||
})
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
activeKey:key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return React.cloneElement(child,props);
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
{this.getItems()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
80
webapp/component/test/Test.jsx
Normal file
80
webapp/component/test/Test.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import {Icon,Popover} from 'antd';
|
||||
|
||||
import CollapseGroup from './CollapseGroup';
|
||||
import Collapse from './Collapse';
|
||||
|
||||
import './Test.less';
|
||||
|
||||
import {FetchUtil} from '../utils/fetchUtil';
|
||||
|
||||
export default class Test extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state={
|
||||
slide:false,
|
||||
height:0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slideDown=()=>{
|
||||
if(this.state.height<this.refs.pChild.offsetHeight){
|
||||
this.setState({
|
||||
height:this.state.height+=5
|
||||
})
|
||||
setTimeout(this.slideDown,10);
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:"auto",
|
||||
slide:true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
slideUp=()=>{
|
||||
if(this.state.height>0){
|
||||
this.setState({
|
||||
height:this.state.height-=5
|
||||
})
|
||||
setTimeout(this.slideUp,10);
|
||||
}
|
||||
else{
|
||||
this.setState({
|
||||
height:0,
|
||||
slide:false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleClick=()=>{
|
||||
// if(this.state.slide==false){
|
||||
// this.slideDown();
|
||||
// }
|
||||
// else{
|
||||
// let height=this.refs.pContent.clientHeight;
|
||||
// this.setState({
|
||||
// height:height
|
||||
// },this.slideUp)
|
||||
// }
|
||||
|
||||
// this.setState({
|
||||
// slide:!this.state.slide
|
||||
// })
|
||||
}
|
||||
|
||||
render(){
|
||||
var content=<span>hello world</span>;
|
||||
return (
|
||||
<div className="ant-layout-content">
|
||||
<CollapseGroup>
|
||||
<Collapse key="a" title="a" ><div>ad<br/>asfdasdflasdf</div></Collapse>
|
||||
<Collapse key="b" title="b"><div>bd</div></Collapse>
|
||||
<Collapse key="c" title="c"><div>cd</div></Collapse>
|
||||
</CollapseGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
18
webapp/component/test/Test.less
Normal file
18
webapp/component/test/Test.less
Normal file
@@ -0,0 +1,18 @@
|
||||
.p-block-title{
|
||||
height: 40px;
|
||||
border:1px solid #d9d9d9;
|
||||
line-height: 40px;
|
||||
padding-left: 30px;
|
||||
cursor:pointer;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.p-block-title:hover{
|
||||
background-color:#f7f7f7;
|
||||
}
|
||||
|
||||
.p-block-content{
|
||||
border:1px solid #d9d9d9;
|
||||
background-color:white;
|
||||
overflow: hidden;
|
||||
}
|
||||
67
webapp/component/utils/fetchUtil.jsx
Normal file
67
webapp/component/utils/fetchUtil.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import {Modal,message} from 'antd';
|
||||
import 'whatwg-fetch';
|
||||
import 'es6-promise/dist/es6-promise.min.js';
|
||||
import 'fetch-ie8/fetch.js';
|
||||
|
||||
export var fetchVersion='/services/v1';
|
||||
|
||||
export var FetchUtil=function(url,method,param,callback,done=()=>{}){
|
||||
let config={
|
||||
credentials: 'include'
|
||||
};
|
||||
let hide=null;
|
||||
if(method!='GET'){
|
||||
config.method=method;
|
||||
config.headers={"Content-Type": "application/json"};
|
||||
config.body=param;
|
||||
hide = message.loading('正在执行中...', 0);
|
||||
}
|
||||
|
||||
return fetch(fetchVersion+url,config)
|
||||
.then((res) => {
|
||||
if(method!='GET'){hide();}
|
||||
if(res.ok){
|
||||
return res.json();
|
||||
}
|
||||
else{
|
||||
if(window.modal==undefined){
|
||||
window.modal=Modal.error({
|
||||
title: '系统错误',
|
||||
content: '请检查是否有参数配置错误',
|
||||
onOk:()=>{
|
||||
window.modal=undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.then((data)=>{
|
||||
if(!data.success&&data.code==600){
|
||||
if(window.modal==undefined){
|
||||
window.modal=Modal.error({
|
||||
title: '您尚未登录',
|
||||
content: '请返回登录页面重新登录',
|
||||
onOk:()=>{
|
||||
window.modal=undefined;
|
||||
window.location.href="#/login";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if(!data.success){
|
||||
if(window.modal==undefined){
|
||||
window.modal=Modal.error({
|
||||
title: '系统错误',
|
||||
content: data.msg,
|
||||
});
|
||||
}
|
||||
}
|
||||
else{
|
||||
callback(data);
|
||||
}
|
||||
done();
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e.message);
|
||||
});
|
||||
}
|
||||
191
webapp/component/utils/groovyUtil.jsx
Normal file
191
webapp/component/utils/groovyUtil.jsx
Normal file
@@ -0,0 +1,191 @@
|
||||
function getIndent(level) {
|
||||
var result = "";
|
||||
for (var i = 0; i < level; i++) {
|
||||
result = result + " ";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getExpression(expreObject) {
|
||||
if(!expreObject){
|
||||
return null;
|
||||
}
|
||||
var className = expreObject["class"];
|
||||
var type = expreObject["type"];
|
||||
var column = expreObject["column"];
|
||||
var value = expreObject["value"];
|
||||
//console.log(expreObject);
|
||||
//console.log(value);
|
||||
if (className == "ENTATTR") // 选择的数据类型
|
||||
return "data." + column;
|
||||
else if (className == "CONST") {
|
||||
if (type == "STRING") {
|
||||
return "'" + value + "'";
|
||||
} else if (type == "DOUBLE") {
|
||||
return "" + value;
|
||||
} else {
|
||||
return "" + value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processRule(ruleObject, level) {
|
||||
var className = ruleObject["class"];
|
||||
var enabled = ruleObject["enabled"];
|
||||
var operator = ruleObject["operator"];
|
||||
var expressions = ruleObject["expressions"];
|
||||
if (className == "PDCT") {
|
||||
return processRules(ruleObject, level + 1);
|
||||
}
|
||||
// if (operator=="Equal") {
|
||||
// return getExpression(expressions[0]) + "==" + getExpression(expressions[1]);
|
||||
// } else if (operator=="InList") {
|
||||
// return getExpression(expressions[0]) + " in blackList["+getExpression(expressions[1])+"]";
|
||||
// } else if (operator=="IsNull") {
|
||||
// return getExpression(expressions[0]) + " is null";
|
||||
// } else if (operator=="Field_Equal") {
|
||||
// return getExpression(expressions[0]) + "==" + getExpression(expressions[1]);
|
||||
// } else if (operator=="StartsWith") {
|
||||
// return getExpression(expressions[0]) + ".startsWith("+getExpression(expressions[1])+")";
|
||||
// }
|
||||
//console.log(ruleObject);
|
||||
switch (operator) {
|
||||
case "StartsWith":
|
||||
return getExpression(expressions[0]) + ".startsWith(" + getExpression(expressions[1]) + ")";
|
||||
case "NotStartsWith":
|
||||
return "!" + getExpression(expressions[0]) + ".startsWith(" + getExpression(expressions[1]) + ")";
|
||||
case "Contains":
|
||||
return getExpression(expressions[0]) + ".contains(" + getExpression(expressions[1]) + ")";
|
||||
case "NotContains":
|
||||
return "!" + getExpression(expressions[0]) + ".contains(" + getExpression(expressions[1]) + ")";
|
||||
case "Equal":
|
||||
case "Field_Equal":
|
||||
return getExpression(expressions[0]) + "==" + getExpression(expressions[1]);
|
||||
case "NotEqual":
|
||||
case "Field_Not_Equal":
|
||||
return getExpression(expressions[0]) + "!=" + getExpression(expressions[1]);
|
||||
case "Less":
|
||||
case "Field_Less":
|
||||
return getExpression(expressions[0]) + "<" + getExpression(expressions[1]);
|
||||
case "Less_Equal":
|
||||
case "Field_Less_Equal":
|
||||
return getExpression(expressions[0]) + "<=" + getExpression(expressions[1]);
|
||||
case "Greater":
|
||||
case "Field_Greater":
|
||||
return getExpression(expressions[0]) + ">" + getExpression(expressions[1]);
|
||||
case "Greater_Equal":
|
||||
case "Field_Greater_Equal":
|
||||
return getExpression(expressions[0]) + ">=" + getExpression(expressions[1]);
|
||||
case "InList":
|
||||
return "lists." + getExpression(expressions[1]) + ".containsKey(" + getExpression(expressions[0]) + ")";
|
||||
case "NotInList":
|
||||
return "!lists." + getExpression(expressions[1]) + ".containsKey(" + getExpression(expressions[0]) + ")";
|
||||
case "IsNull":
|
||||
return "!" + getExpression(expressions[0]);
|
||||
case "IsNotNull":
|
||||
return getExpression(expressions[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function processRules(jsonObject, level) {
|
||||
var className = jsonObject["class"];
|
||||
var enabled = jsonObject["enabled"];
|
||||
var linking = jsonObject["linking"];
|
||||
var conditions = jsonObject["conditions"];
|
||||
var length = conditions.length;
|
||||
var result="";
|
||||
if (linking == "NotAll" || linking == "None") {
|
||||
result += "!";
|
||||
}
|
||||
result += "(";
|
||||
for (var i in conditions) {
|
||||
result = result + processRule(conditions[i], level);
|
||||
if (i != length - 1) {
|
||||
// if (linking=="All") {
|
||||
// result = result + "\n"+getIndent(level)+"and ";
|
||||
// } else if (linking=="Any") {
|
||||
// result = result + "\n"+getIndent(level)+"or ";
|
||||
// }
|
||||
switch (linking) {
|
||||
case "All":
|
||||
case "NotAll":
|
||||
result += "&&";
|
||||
break;
|
||||
case "Any":
|
||||
case "None":
|
||||
result += "||";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result + ")";
|
||||
}
|
||||
|
||||
export var generateScript = function(jsonObject, className) {
|
||||
if(jsonObject==null){
|
||||
return '';
|
||||
}
|
||||
var script = "class " + className + "CheckScript {" + "\n";
|
||||
script += " public boolean check(def data, def lists) {";
|
||||
script += " if (" + processRules(jsonObject, 1) + ")\n";
|
||||
script += " return true;" + "\n";
|
||||
script += " else" + "\n";
|
||||
script += " return false;" + "\n";
|
||||
script += "}";
|
||||
script += "}";
|
||||
return script;
|
||||
}
|
||||
|
||||
export let validateRules = function(jsonObject) {
|
||||
if(jsonObject==null){
|
||||
return true;
|
||||
}
|
||||
|
||||
let conditions = jsonObject["conditions"];
|
||||
for (let i in conditions) {
|
||||
if(!validateRule(conditions[i])){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateRule(ruleObject){
|
||||
var className = ruleObject["class"];
|
||||
var operator = ruleObject["operator"];
|
||||
var expressions = ruleObject["expressions"];
|
||||
if (className == "PDCT") {
|
||||
return validateRules(ruleObject);
|
||||
}
|
||||
|
||||
if(!operator){
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (operator) {
|
||||
case "StartsWith":
|
||||
case "NotStartsWith":
|
||||
case "Contains":
|
||||
case "NotContains":
|
||||
case "Equal":
|
||||
case "Field_Equal":
|
||||
case "NotEqual":
|
||||
case "Field_Not_Equal":
|
||||
case "Less":
|
||||
case "Field_Less":
|
||||
case "Less_Equal":
|
||||
case "Field_Less_Equal":
|
||||
case "Greater":
|
||||
case "Field_Greater":
|
||||
case "Greater_Equal":
|
||||
case "Field_Greater_Equal":
|
||||
case "InList":
|
||||
case "NotInList":
|
||||
return getExpression(expressions[1])&&getExpression(expressions[0]);
|
||||
case "IsNull":
|
||||
case "IsNotNull":
|
||||
return getExpression(expressions[0])&&true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
99
webapp/component/utils/operatorUtil.jsx
Normal file
99
webapp/component/utils/operatorUtil.jsx
Normal file
@@ -0,0 +1,99 @@
|
||||
export var Operator = {
|
||||
StartsWith:{label:'以...开始',value:'StartsWith',nextType:'input'},
|
||||
Contains:{label:'包含',value:'Contains',nextType:'input'},
|
||||
Equal : {label:'等于',value:'Equal',nextType:'input'},
|
||||
Less : {label:'小于',value:'Less',nextType:'input'},
|
||||
Less_Equal : {label:'小于等于',value:'Less_Equal',nextType:'input'},
|
||||
Greater : {label:'大于',value:'Greater',nextType:'input'},
|
||||
Greater_Equal : {label:'大于等于',value:'Greater_Equal',nextType:'input'},
|
||||
InList : {label:'在列表...中',value:'InList',nextType:'list'},
|
||||
NotStartsWith : {label:'不以...开始',value:'NotStartsWith',nextType:'input'},
|
||||
NotContains : {label:'不包含',value:'NotContains',nextType:'input'},
|
||||
NotEqual : {label:'不等于',value:'NotEqual',nextType:'input'},
|
||||
NotInList : {label:'不在列表...中',value:'NotInList',nextType:'list'},
|
||||
IsNull : {label:'为空',value:'IsNull',nextType:'empty'},
|
||||
IsNotNull : {label:'不为空',value:'IsNotNull',nextType:'empty'},
|
||||
Field_Greater : {label:'大于(字段)',value:'Field_Greater',nextType:'field'},
|
||||
Field_Less : {label:'小于(字段)',value:'Field_Less',nextType:'field'},
|
||||
Field_Greater_Equal : {label:'大于等于(字段)',value:'Field_Greater_Equal',nextType:'field'},
|
||||
Field_Less_Equal : {label:'小于等于(字段)',value:'Field_Less_Equal',nextType:'field'},
|
||||
Field_Equal : {label:'等于(字段)',value:'Field_Equal',nextType:'field'},
|
||||
Field_Not_Equal : {label:'不等于(字段)',value:'Field_Not_Equal',nextType:'field'}
|
||||
};
|
||||
|
||||
/*nextType:{
|
||||
input,list,empty,field
|
||||
}
|
||||
*/
|
||||
|
||||
export var operatorMap={
|
||||
'STRING':[
|
||||
Operator.StartsWith,
|
||||
Operator.NotStartsWith,
|
||||
Operator.Contains,
|
||||
Operator.NotContains,
|
||||
Operator.Equal,
|
||||
Operator.NotEqual,
|
||||
Operator.InList,
|
||||
Operator.NotInList,
|
||||
Operator.IsNull,
|
||||
Operator.IsNotNull,
|
||||
Operator.Field_Equal,
|
||||
Operator.Field_Not_Equal
|
||||
],
|
||||
'INTEGER':[
|
||||
Operator.Equal,
|
||||
Operator.NotEqual,
|
||||
Operator.InList,
|
||||
Operator.NotInList,
|
||||
Operator.Less,
|
||||
Operator.Less_Equal,
|
||||
Operator.Greater,
|
||||
Operator.Greater_Equal,
|
||||
Operator.IsNull,
|
||||
Operator.IsNotNull,
|
||||
Operator.Field_Greater,
|
||||
Operator.Field_Less,
|
||||
Operator.Field_Greater_Equal,
|
||||
Operator.Field_Less_Equal,
|
||||
Operator.Field_Equal,
|
||||
Operator.Field_Not_Equal
|
||||
],
|
||||
'DOUBLE':[
|
||||
Operator.Equal,
|
||||
Operator.NotEqual,
|
||||
Operator.InList,
|
||||
Operator.NotInList,
|
||||
Operator.Less,
|
||||
Operator.Less_Equal,
|
||||
Operator.Greater,
|
||||
Operator.Greater_Equal,
|
||||
Operator.IsNull,
|
||||
Operator.IsNotNull,
|
||||
Operator.Field_Greater,
|
||||
Operator.Field_Less,
|
||||
Operator.Field_Greater_Equal,
|
||||
Operator.Field_Less_Equal,
|
||||
Operator.Field_Equal,
|
||||
Operator.Field_Not_Equal
|
||||
],
|
||||
'LONG':[
|
||||
Operator.Equal,
|
||||
Operator.NotEqual,
|
||||
Operator.InList,
|
||||
Operator.NotInList,
|
||||
Operator.Less,
|
||||
Operator.Less_Equal,
|
||||
Operator.Greater,
|
||||
Operator.Greater_Equal,
|
||||
Operator.IsNull,
|
||||
Operator.IsNotNull,
|
||||
Operator.Field_Greater,
|
||||
Operator.Field_Less,
|
||||
Operator.Field_Greater_Equal,
|
||||
Operator.Field_Less_Equal,
|
||||
Operator.Field_Equal,
|
||||
Operator.Field_Not_Equal
|
||||
],
|
||||
'':[]
|
||||
};
|
||||
3
webapp/component/utils/validateUtil.jsx
Normal file
3
webapp/component/utils/validateUtil.jsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export var trim=function(str){
|
||||
return str.replace(/(^\s*)|(\s*$)/g, "");
|
||||
}
|
||||
124
webapp/index.jsx
Normal file
124
webapp/index.jsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Router, Route, Link, hashHistory,browserHistory,IndexRoute,IndexRedirect } from 'react-router';
|
||||
|
||||
import Abstraction from './component/abstraction/Abstraction';
|
||||
import AbstractionList from './component/abstraction/AbstractionList';
|
||||
import Activation from './component/activation/Activation';
|
||||
import Datalist from './component/datalist/Datalist';
|
||||
import DatalistRecord from './component/datalist/DatalistRecord';
|
||||
import Field from './component/field/Field';
|
||||
import ModelList from './component/model/ModelList';
|
||||
import Model from './component/model/Model';
|
||||
import PreItem from './component/preItem/PreItem';
|
||||
import RuleList from './component/activation/RuleList';
|
||||
import HistoryRecordList from './component/activation/HistoryRecordList';
|
||||
|
||||
import Report from './component/report/Report';
|
||||
import ListEvent from './component/report/ListEvent';
|
||||
import RuleGraph from './component/report/RuleGraph';
|
||||
import ListRule from './component/report/ListRule';
|
||||
import Rule from './component/report/ListRule';
|
||||
import DashBoard from './component/report/DashBoard';
|
||||
|
||||
|
||||
//import Test from './component/test/Test';
|
||||
|
||||
import Index from './component/Index';
|
||||
import Login from './component/Login';
|
||||
|
||||
// 引入Ant-Design样式 & Animate.CSS样式
|
||||
import 'antd/dist/antd.min.css';
|
||||
import 'animate.css/animate.min.css';
|
||||
|
||||
import './main.less';
|
||||
|
||||
class NotFound extends React.Component{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="ibox">
|
||||
<div className="ibox-content">
|
||||
<div style={{
|
||||
width:450,margin:"200px auto",fontSize:26
|
||||
}}>功能尚未完成或页面未找到,敬请期待</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class Welcome extends React.Component{
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="ibox">
|
||||
<div className="ibox-content">
|
||||
<h2>欢迎登录风控引擎管理平台!</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class App extends React.Component{
|
||||
render(){
|
||||
return (
|
||||
<div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppRoutes extends React.Component{
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Router history={hashHistory}>
|
||||
<Route path="/" component={App}>
|
||||
<IndexRedirect to="login"/>
|
||||
<Route path="/welcome" component={Welcome}>
|
||||
</Route>
|
||||
<Route path="/login" component={Login}>
|
||||
</Route>
|
||||
<Route path="/index" component={Index}>
|
||||
<Route path="/modelList" component={ModelList}/>
|
||||
<Route path="/model/:id" component={Model}>
|
||||
<IndexRedirect to="/field/:id"/>
|
||||
<Route path="/field/:id" component={Field}/>
|
||||
<Route path="/activation/:id" component={Activation}/>
|
||||
<Route path="/datalist/:id" component={Datalist}/>
|
||||
<Route path="/datalistRecord/:id/:datalistId" component={DatalistRecord}/>
|
||||
<Route path="/preItem/:id" component={PreItem}/>
|
||||
<Route path="/ruleList/:id/:activationId" component={RuleList}/>
|
||||
<Route path="/historyRecordList/:id/:activationId/:ruleId" component={HistoryRecordList}/>
|
||||
<Route path="/abstractionList/:id" component={AbstractionList}/>
|
||||
|
||||
{/*<Route path="/test/:id" component={Test}/>*/}
|
||||
</Route>
|
||||
|
||||
<Route path="/report" component={Report}>
|
||||
<IndexRedirect to="/event"/>
|
||||
<Route path="/event" component={ListEvent}/>
|
||||
<Route path="/graph" component={RuleGraph}/>
|
||||
<Route path="/rule" component={ListRule}/>
|
||||
<Route path="/ruleid/:modelId/:ruleId/:activationName" component={ListEvent}/>
|
||||
<Route path="/dashboard" component={DashBoard}/>
|
||||
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="*" component={Index}>
|
||||
<IndexRoute component={NotFound} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<AppRoutes />
|
||||
, document.getElementById("react-content"));
|
||||
14
webapp/main.less
Normal file
14
webapp/main.less
Normal file
@@ -0,0 +1,14 @@
|
||||
body{
|
||||
margin:0;
|
||||
padding:0;
|
||||
|
||||
}
|
||||
|
||||
html,body{
|
||||
height:100%;
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
#react-content{
|
||||
height:100%;
|
||||
}
|
||||
Reference in New Issue
Block a user