Commit 9091a37b authored by 张苏雅's avatar 张苏雅

init

parent 4ca4a65f
{
"presets": [
["env", {
"targets": {
"browsers": [
"last 2 versions",
"Firefox ESR",
"> 1%",
"ie >= 9",
"iOS >= 8",
"Android >= 4"
]
}
}], "react", "stage-1"
],
"plugins": [
"transform-runtime", "transform-decorators-legacy"
],
"comments": false,
"compact": "false"
}
\ No newline at end of file
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
src/formsy/jqueryMultiSelect/*
src/components/navigation/noticeTipModal/Parabola.js
src/containers/account/finance/exportCashOrder/html2canvas.js
\ No newline at end of file
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: 'standard',
// required to lint *.vue files
plugins: [
'react'
],
parser: "babel-eslint",
// add your custom rules here
rules: {
// allow callback-literal
'no-callback-literal': 0,
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
semi: ['error', 'always'],
'space-before-function-paren': ['error', 'never'],
'no-useless-escape': 0,
'no-extra-boolean-cast': 0,
'no-new': 0,
'react/jsx-uses-vars': 2,
'react/jsx-uses-react': 2,
'prefer-spread': 'error'
},
globals: {
}
};
\ No newline at end of file
node_modules
dist
bower_components
uploads
npm-debug.log
yarn-error.log
yarn.lock
package-lock.json
.vscode
\ No newline at end of file
# 风控管理平台
## 启动项目
```javascript
yarn dev
```
## 发布项目
```javascript
yarn build
```
## 目录结构
``` bash
|____bin
| |____www // node 启动文件
|____dist
|____build
| |____build.js
| |____webpack.dev.conf.js
| |____webpack.prod.conf.js
| |____webpack.base.conf.js
| |____utils.js
|____config // webpack 配置
| |____dev.env.js
| |____index.js
| |____prod.env.js
| |____entry.js
|____mock // mock 数据配置
| |____server
| |____router
|____html // 模板html
| |____index.html
|____static // 静态文件
| |____favicon.ic
|____src
| |____entry
| | |____index.js
| |____styles // 公共样式
| |____components // 公共组件
| | |____footer
| | | |____index.less
| | | |____index.jsx
| | |____loading
| | | |____index.js
| | | |____loading.gif
| | | |____index.less
| | |____menu
| | | |____index.less
| | | |____index.jsx
| | | |____menuData.js // 侧边栏配置文件
| | |____breadcrumb
| | | |____index.less
| | | |____index.jsx
| | |____header
| | | |____index.less
| | | |____index.jsx
| |____lib // 工具库
| | |____permissionTools.js
| | |____dataFormate.js
| | |____common.js // fetch请求相关
| | |____utils.js
| | |____cookie.js
| |____containers // 业务页面
| | |____example // demo
| | | |____index.jsx
| | | |____example.less
| | | |____child
| | | | |____index.jsx
| | | |____store
| | | | |____index.js
| |____routes // 前端路由配置
| | |____nameFilter.js
| | |____index.js
| | |____riskmng.js
| | |____example.js
| | |____App.js
|____.editorconfig
|____README.md
|____yarn.lock
|____.gitignore
|____package.json
|____.eslintrc.js
|____.eslintignore
|____.babelrc
|____app.js
|____postcss.config.js
```
## 环境
```bash
前端项目 tuia-risk-manager-node
后端项目 tuia-risk-manager
开发环境 zhongkui.tuiadev.cn
测试环境 zhongkui.tuiatest.cn
预发环境 zhongkui.tuia.cn(118.31.40.85)
正式环境 zhongkui.tuia.cn
```
## 发布
先发后端系统,再发前端系统
## Jenkins
开发环境Jenkins
地址:http://jenkins.duibar.com
测试环境Jenkins
地址:http://172.16.80.21:8080/job/tiantianquwen-h5-node/
账号密码 http://cf.dui88.com/pages/viewpage.action?pageId=5806560
\ No newline at end of file
const express = require('express');
const path = require('path');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./config');
const utils = require('./build/utils');
const devConfig = require('./build/webpack.dev.conf');
const compiler = webpack(devConfig);
const app = express();
app.use(webpackDevMiddleware(compiler, {
publicPath: devConfig.output.publicPath,
stats: {
colors: true,
chunks: false
},
headers: {
'Access-Control-Allow-Origin': '*'
}
}));
app.use(webpackHotMiddleware(compiler));
app.use(express.static('./'));
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, './dist/html/'));
app.engine('ejs', require('ejs').__express);
app.engine('html', require('ejs').__express);
require('./mock/router/')(app);
console.log(`<http://${utils.getIPAdress()}:${config.dev.port}> with Chrome`);
module.exports = app;
#!/usr/bin/env node
const config = require('../config');
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('epack:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || config.dev.port);
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
const path = require('path');
const chalk = require('chalk');
const webpack = require('webpack');
const TuiaAutoUpload = require('tuia-auto-upload');
const config = require('../config');
const webpackConfig = require('./webpack.prod.conf');
webpack(webpackConfig, function(err, stats) {
if (err) throw err;
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n');
console.log(chalk.cyan(' Build complete.\n'));
if (process.env.NODE_ENV === 'production') {
const uploader = new TuiaAutoUpload({
dir: path.join(__dirname, '../dist/assets/'),
originDir: config.path
});
uploader.start();
}
});
/*
* @Author: 周成
* @Date: 2018-01-16 15:51:14
* @Last Modified by: 周成
* @Last Modified time: 2018-05-28 15:42:14
*/
const path = require('path');
exports.computeEntry = function(entry = []) {
let result = {};
for (let i = 0; i < entry.length; i++) {
const item = entry[i];
const name = item.name;
result[name] = [path.join(__dirname, item.path)];
}
return result;
};
exports.computeTemplate = function(entry = []) {
let result = [];
for (let i = 0; i < entry.length; i++) {
const item = entry[i];
let params = {
name: item.name,
filename: path.join(__dirname, '../dist/html/', `${item.name}.html`),
template: `html-loader?attrs[]=img:src&attrs[]=img:data-src!${path.join(__dirname, item.template)}`,
chunks: ['vendors', item.name],
favicon: path.join(__dirname, '../static/favicon.ico')
};
if (process.env.NODE_ENV === 'production') {
params.minify = {
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true,
removeComments: true
};
}
result.push(params);
}
return result;
};
exports.getIPAdress = function() {
let interfaces = require('os').networkInterfaces();
// 有WLAN先returnWLAN中的IP
if ('WLAN' in interfaces) {
let iface = interfaces['WLAN'];
for (let i = 0; i < iface.length; i++) {
let alias = iface[i];
if (
alias.family === 'IPv4' &&
alias.address !== '127.0.0.1' &&
!alias.internal
) {
return alias.address;
}
}
delete interfaces['WLAN'];
}
for (let devName in interfaces) {
let iface = interfaces[devName];
for (let i = 0; i < iface.length; i++) {
let alias = iface[i];
if (
alias.family === 'IPv4' &&
alias.address !== '127.0.0.1' &&
!alias.internal
) {
return alias.address;
}
}
}
};
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const utils = require('./utils');
const config = require('../config');
const entryConfig = require('../config/entry');
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
entry: Object.assign(utils.computeEntry(entryConfig), {
vendors: ['react', 'react-dom', 'react-router', 'antd']
}),
output: {
path: path.join(__dirname, '../dist/assets/'),
filename: isProd ? '[chunkhash].[name].js' : '[name].js',
publicPath: config[isProd ? 'build' : 'dev'].assetsPublicPath,
chunkFilename: isProd ? '[chunkhash].[name].js' : '[name].js'
},
resolve: {
alias: {
src: path.join(__dirname, '../src/')
},
extensions: ['.js', '.jsx']
},
externals: {
jquery: 'jQuery'
},
module: {
rules: [
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre',
options: {
configFile: './.eslintrc.js',
formatter: require('eslint-friendly-formatter')
}
},
{
test: /\.js[x]?$/,
loaders: (isProd ? [] : ['react-hot-loader']).concat(['babel-loader?cacheDirectory=true']),
exclude: /node_modules/
},
{
test: /\.(svg|png|jpg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
loader: 'url-loader',
options: {
limit: 10240
}
}
]
},
node: {
fs: 'empty'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendors',
filename: isProd ? '[chunkhash].vendors.js' : 'vendors.js'
}),
...utils.computeTemplate(entryConfig).map(el => {
return new HtmlWebpackPlugin(
Object.assign({}, el, {
alwaysWriteToDisk: true
})
);
}),
new HtmlWebpackHarddiskPlugin()
]
};
const webpack = require('webpack');
const merge = require('webpack-merge');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
const config = require('../config');
const webpackBaseConfig = require('./webpack.base.conf');
Object.keys(webpackBaseConfig.entry).forEach(function(name) {
if (name !== 'verdors') {
webpackBaseConfig.entry[name] = webpackBaseConfig.entry[name].concat('webpack-hot-middleware/client?reload=true');
}
});
module.exports = merge(webpackBaseConfig, {
devtool: config.dev.sourceMap ? '#eval-source-map' : false,
module: {
rules: [
{
test: /(\.less|\.css)$/,
exclude: /node_modules|antd\.less/,
use: ['style-loader?sourceMap', 'css-loader?sourceMap&modules=true&localIdentName=[local]_[hash:base64:5]', 'postcss-loader?sourceMap', 'less-loader?sourceMap&javascriptEnabled=true&modules=true&localIdentName=[local]-[hash:base64:5]']
},
{
test: /(\.less|\.css)$/,
include: /node_modules|antd\.less/,
use: ['style-loader?sourceMap', 'css-loader?sourceMap', 'less-loader?sourceMap&javascriptEnabled=true']
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: config.dev.env
}
}),
new FriendlyErrorsWebpackPlugin(),
new webpack.HotModuleReplacementPlugin()
]
});
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
const chalk = require('chalk');
const os = require('os');
const config = require('../config/index');
const webpackBaseConfig = require('./webpack.base.conf');
module.exports = merge(webpackBaseConfig, {
module: {
rules: [
{
test: /(\.less|\.css)$/,
exclude: /node_modules|antd\.less/,
use: ExtractTextPlugin.extract({
fallback: {
loader: 'style-loader',
options: {
insertAt: 'top'
}
},
use: [
{
loader: 'css-loader',
options: {
modules: true,
minimize: true,
localIdentName: '[name]__[local]_[hash:base64:5]'
}
},
{
loader: 'postcss-loader'
},
{
loader: 'less-loader',
options: {
outputStyle: 'expanded',
javascriptEnabled: true
}
}
]
})
},
{
test: /(\.less|\.css)$/,
include: /node_modules|antd\.less/,
use: ExtractTextPlugin.extract({
fallback: {
loader: 'style-loader',
options: {
insertAt: 'top'
}
},
use: [
{
loader: 'css-loader',
options: {
minimize: true
}
},
{
loader: 'postcss-loader'
},
{
loader: 'less-loader',
options: {
outputStyle: 'expanded',
javascriptEnabled: true
}
}
]
})
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: config.build.env
}
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
drop_console: true
}
},
cache: true,
parallel: os.cpus().length
}),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
new ProgressBarPlugin({
format: chalk.yellow('打包中 [:bar] :current/:total :percent :elapseds :msg'),
complete: '●',
incomplete: '○',
width: 20
}),
new CleanWebpackPlugin(
['dist'], {
root: path.resolve(__dirname, '../'),
verbose: false,
dry: false
}
),
new ExtractTextPlugin({
filename: '[contenthash].index.css',
allChunks: true
}),
new ImageminPlugin({
/**
* Linux依赖于libpng-devel
* yum install libpng-devel
*/
pngquant: {
quality: '95-100'
},
cacheFolder: path.join(__dirname, '../node_modules/.cache/imagemin-webpack-plugin')
})
]
});
const merge = require('webpack-merge');
const prodEnv = require('./prod.env');
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
});
module.exports = [
{
name: 'index',
path: '../src/entry',
template: '../html/index.html'
}
];
const utils = require('../build/utils');
const packagejson = require('../package.json');
const path = `/tuia/${packagejson.name}/dist/`;
const port = 17790;
module.exports = {
path,
build: {
env: require('./prod.env'),
assetsPublicPath: `//yun.tuia.cn${path}`,
sourceMap: false,
cssSourceMap: false
},
dev: {
env: require('./dev.env'),
assetsPublicPath: `http://${utils.getIPAdress()}:${port}/dist/`,
sourceMap: true,
cssSourceMap: false,
port
}
};
module.exports = {
NODE_ENV: '"production"'
};
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>审核操作台 - 钟馗</title>
</head>
<body>
<div id="app"></div>
<!--[if lte IE 9]>
<img style="width:600px; display:block; margin:250px auto 0;" src="http://yun.duiba.com.cn/tuia/myimg/support.png" alt="推荐使用Chrome最新版,火狐最新版来使用本网站,谢谢。">
<script type="text/javascript">document.getElementById('app').className='hide';</script>
<![endif]-->
</body>
</html>
\ No newline at end of file
const path = require('path');
const fs = require('fs');
// const url = require('url');
const router = require('express').Router();
const httpProxyMiddleware = require('http-proxy-middleware');
// const config = require('../../config');
// const upload = require('../server/upload');
const Router = function(app) {
router.get('/', function(req, res) {
// 根路由
res.render('index.html');
});
router.get(/html/, function(req, res) {
// html路由
res.render(req.path.replace('/', ''));
});
/**
* npm命令中带有process.env.proxy参数,则开启代理到指定服务器
*/
if (process.env.proxy) {
const filter = function(pathname, req) {
return !(pathname.match('html') || pathname === '/');
};
app.use(httpProxyMiddleware(filter, {
target: 'http://' + process.env.proxy + ':17811',
changeOrigin: false
}));
} else {
router.all('*', (req, res) => {
// mock路由,优先查找JS,其次是JSON,找不到返回默认值
const JSFilePath = path.join(__dirname, '../server/', `${req.path}.js`);
const JSONFilePath = path.join(__dirname, '../server/', `${req.path}.json`);
if (fs.existsSync(JSFilePath)) {
const file = fs.readFileSync(JSFilePath);
res.json(JSON.parse(file));
} else if (fs.existsSync(JSONFilePath)) {
const file = fs.readFileSync(JSONFilePath);
res.json(JSON.parse(file));
} else {
res.json({
code: '0',
desc: '成功',
data: '0',
success: true
});
}
});
}
app.use(router);
};
module.exports = Router;
{
"success": true,
"nowVersion": 1522031458229,
"authList": [
"specialADFeeShow",
"/advertMaterial/duibaAuditList",
"/appWhiteList/delete",
"advertMaterialPage",
"rechargePage",
"sellShow",
"advertWeightShow",
"queryAllAccountAuditList",
"/appFlowStrategy/queryAppFlowStrategyList",
"seeAllApplication",
"/landPageAudit/landPageAuditSearch",
"duibaAdvertMaterialPage",
"materialDataPage",
"invoice/refuseInvoice",
"appDataPageShow",
"accountQualificationsPage",
"invoice/exportAgentInvoiceStatisticsData",
"/financeReconciliation/list",
"/export/updateAppData",
"urlTagsShow",
"/phone/update",
"adverts/addPrivilegeAdvert",
"queryAllAdvertiserData",
"appDataShow",
"/advertStatistics/getAppData",
"/advertGroupData/groupDataEnter",
"/advertMaterial/list",
"/couponRecoveryLog/getRecoveryLogData",
"/advertGroupNew/unBindAdvert",
"/appPackage/update",
"tagLibraryNew",
"advertGroupPage",
"advertStatistics/exportAdvertMaterialStatistics",
"recoveryLogPage",
"adManage",
"AdvertSortPage",
"tradeShow",
"tagLibraryPage",
"queryAllMaterialData",
"/specialApp/deleteByAppId",
"invoice/saveCourierNumber",
"appointmentInfoPage",
"/account/changeAccountInfo",
"/qualification/auditQualifications",
"/adverts/updateAdvertPlan",
"appManagerDuibaSource",
"/advertGroupNew/deleteAdvertGroup",
"queryAllOrientPkgData",
"/tag/add",
"queryAllAdvertGroupData",
"appManagePage",
"/advertStatistics/exportLandingPageData",
"queryAllAppPackage",
"OrientPkgDataPage",
"/finance/commitApplication",
"/advertStatistics/getDailyData",
"export/removePrivilegeApp",
"/finance/consumeRecord",
"/advertiser/pageQuery",
"realizeAct",
"/adverts/pageQuery",
"/tag/queryTagLibrary",
"landPage",
"/appWhiteList/AppFlowStrategyDelete",
"/advertStatistics/getLandingAnalysisData",
"materialTagsShow",
"bannedTagShow",
"/qualification/updateQualificationsAuditRemark",
"/export/getAppBannedTags",
"/finance/getRecord",
"appManagerTuiaSource",
"financeManage",
"/advertStatistics/getAdvertiserData",
"appManagerAllSource",
"advertiserDataPage",
"advertiserManage",
"/export/updateSendLuckybag",
"appPackagePage",
"/finance/assistantRefuse",
"/appWhiteList/bindAdvert",
"/specialApp/specialList",
"advertPage",
"financeReconciliation",
"advertStatistics/exportAdvertiserData",
"agentInvoiceStatisticsDataPage",
"/newTag/addAppByNewTagNum",
"/qualification/updateQualifications",
"/advertGroupNew/groupList",
"/qualification/fastAuditQualifications",
"/land/save",
"/adverts/validAdvertSort",
"/finance/managerAgree",
"/appFlowStrategy/findAppFlowStrategyById",
"systemConfig/updateSystemConfig",
"appName",
"appWhiteListPage",
"/finance/recharge",
"/appPackage/list",
"advertOrientPackageShow",
"/advertStatistics/getAdvertMaterialStatistics",
"/appWhiteList/bindAppFlowStrategyAdvert",
"/finance/getFinanceInfo",
"advertMaterialShow",
"appManage",
"coinExRate",
"/appWhiteList/getStrategyAppWhiteList",
"/landPageAudit/auditLandPage",
"/advertGroupNew/insertAdvertGroup",
"/appWhiteList/orderBindAdvert",
"/finance/exportConsumeRecord",
"/finance/managerRefuse",
"cashAudit",
"/land/exportLandData",
"/newTag/addNewTag",
"export/addPrivilegeApp",
"/adverts/queryValidAdverts",
"/advertGroupNew/bindAdvert",
"/newTag/queryNewTagLibrary",
"orientPkgStatistics/exportOrientPkgData",
"advertStatistics/exportAppData",
"/land/query",
"flowStrategyAllSource",
"landingPageEditPage",
"/adverts/updateAdvertDuiBaBannedTag",
"resourceShow",
"/correction/update",
"/advertStatistics/getStatistics",
"/adverts/updateCoupon",
"flowStrategyTuiaSource",
"/adverts/updateCheckAdvert",
"materialTagsEditShow",
"invoice/exportAgentInvoiceRecord",
"test/",
"adverts/removePrivilegeAdvert",
"/advertGroup/bindAdvert",
"matchTagShow",
"advertDuiBaBannedTagShow",
"invoiceRecordPage",
"/advertGroupData/groupDailyData",
"/newTag/addAdvertByNewTagNum",
"/advertiser/updateFreezeStatus",
"SystemConfigPage",
"/advertiser/pageQueryAppointmentInfoReq",
"dataManage",
"/landPageAudit/landPageAuditListSearch",
"/advertGroupNew/updateAdvertGroup",
"/advertiser/updateCheckStatus",
"/orientPkg/updateAdvertOrientPackageBudget",
"urlTagsEditShow",
"advertDiagnosisShow",
"globalShow",
"systemConfig/getSystemConfig",
"tuiaAct",
"/appWhiteList/getAppWhiteList",
"recoveryLogDownload",
"weightwhitelist",
"AEShow",
"/export/findAppData",
"/orientPkgStatistics/getOrientPkgStatistics",
"/specialApp/addApps",
"consumeRecordPage",
"/adverts/saveTagsByAdvertId",
"/landPageAudit",
"appDataPage",
"appFlowStrategyPage",
"advertGroupDataPage",
"phonePage",
"/finance/exportbalanceRecord",
"rechargeRecordPage",
"/advertStatistics/exportAdvertData",
"/land/queryList",
"advertStatistics/exportDailyData",
"balanceRecordPage",
"advertDataPage",
"/appWhiteList/queryAdvertPlan",
"/qualification/pageQueryAccountQualifications",
"privilegeAdvertLibraryPage",
"advertStatistics/exportDailyDataByHour",
"platformManage",
"invoice/queryAgentInvoiceRecord",
"/finance/assistantAgree",
"/finance/balanceRecord",
"/newTag/deleteAllAdvertByNewTagNum",
"/finance/exportExcel",
"advertiserManagePage",
"editAppFlowStrategyPage",
"/advertGroupData/groupDataList",
"invoice/queryAgentInvoiceStatisticsData",
"/advertStatistics/queryDataByHour",
"queryAllAdvertData",
"landManager",
"flowStrategyDuibaSource",
"/phone/get",
"/newTag/deleteAdvertByNewTagNum",
"/adverts/findAdvertInfo",
"tagLibraryManage",
"/newTag/deleteAppByTagNum",
"invoice/passInvoice",
"/qualification/auditQualifications,/qualification/fastAuditQualif",
"displayAeWorkBench",
"accountManager",
"accountManager/weMediaAccount",
"contentConfig",
"contentConfig/stickManager",
"/***risk风控****/",
"riskmng",
"riskmng/auditsys",
"riskmng/auditcase",
"riskmng/innercheck",
"nameFilter",
"/nameFilter/black",
"/nameFilter/white",
"/plan/canAdvertReview",
"ruleEngine",
"ruleEngine/scence",
"ruleEngine/strategy",
"ruleEngine/strategy/rule",
"ruleEngine/report",
"ruleEngine/field"
],
"version": 1522031458229
}
{
"code": "0",
"desc": "修改失败",
"success": false
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 11,
"totalPage": 2,
"list": [
{
"id": 20,
"dimension": 0,
"val": "测试时间下午15:29",
"stat": 0,
"src": "测试",
"memo": "测试nemo",
"gmtCreate": 1526887770000,
"creator": "舒曼",
"gmtModified": null,
"mender": null
},
{
"id": 19,
"dimension": 0,
"val": "名单",
"stat": 0,
"src": "来源",
"memo": "备注",
"gmtCreate": 1526886808000,
"creator": "徐恒飞",
"gmtModified": null,
"mender": null
},
{
"id": 18,
"dimension": 0,
"val": "名单值是什么2",
"stat": 0,
"src": "名单值是什么2",
"memo": "名单值是什么",
"gmtCreate": 1526875280000,
"creator": "徐恒飞",
"gmtModified": null,
"mender": null
},
{
"id": 17,
"dimension": 0,
"val": "名单值是什么1",
"stat": 0,
"src": "名单值是什么1",
"memo": "名单值是什么",
"gmtCreate": 1526875271000,
"creator": "徐恒飞",
"gmtModified": null,
"mender": null
},
{
"id": 15,
"dimension": 0,
"val": "名单值是什么",
"stat": 0,
"src": "名单值是什么",
"memo": "名单值是什么",
"gmtCreate": 1526875257000,
"creator": "徐恒飞",
"gmtModified": null,
"mender": null
},
{
"id": 14,
"dimension": 2,
"val": "名单值是什么",
"stat": 0,
"src": "奇货",
"memo": "11111",
"gmtCreate": 1526875250000,
"creator": "徐恒飞",
"gmtModified": null,
"mender": null
},
{
"id": 8,
"dimension": 0,
"val": "3",
"stat": 0,
"src": "3",
"memo": "3",
"gmtCreate": 1526869590000,
"creator": "徐恒飞",
"gmtModified": 1526869725000,
"mender": "徐恒飞"
},
{
"id": 4,
"dimension": 0,
"val": "1",
"stat": 0,
"src": "1",
"memo": "1",
"gmtCreate": 1526869513000,
"creator": "徐恒飞",
"gmtModified": 1526869721000,
"mender": "徐恒飞"
},
{
"id": 3,
"dimension": 0,
"val": "22",
"stat": 0,
"src": "22",
"memo": "2222",
"gmtCreate": 1526869090000,
"creator": "徐恒飞",
"gmtModified": 1526871712000,
"mender": "徐恒飞"
},
{
"id": 2,
"dimension": 1,
"val": "1",
"stat": 0,
"src": "推啊",
"memo": "11111",
"gmtCreate": 1526869076000,
"creator": "徐恒飞",
"gmtModified": 1526869700000,
"mender": "徐恒飞"
}
],
"sum": null
}
}
\ No newline at end of file
{
"code": "string",
"data": [
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-30T01:23:18.895Z",
"gmtModified": "2018-07-30T01:23:18.895Z",
"gmtModifiedView": "string",
"id": 0,
"name": "string",
"sceneId": 1,
"sceneName": "string",
"tableColumn": "string",
"tableName": "string",
"type": "string"
}, {
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-30T01:23:18.895Z",
"gmtModified": "2018-07-30T01:23:18.895Z",
"gmtModifiedView": "string",
"id": 1,
"name": "string1",
"sceneId": 1,
"sceneName": "string",
"tableColumn": "string",
"tableName": "string",
"type": "string"
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": {
"list": [
{
"creator": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:52.992Z",
"gmtModified": "2018-07-25T08:44:52.992Z",
"gmtModifiedView": "string",
"id": 0,
"name": "string",
"sceneId": 0,
"sceneNames": [
{
"creator": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:52.992Z",
"gmtModified": "2018-07-25T08:44:52.992Z",
"gmtModifiedView": "string",
"id": 0,
"name": "string",
"sceneId": 0,
"sceneName": "string",
"tableColumn": "string",
"tableName": "string",
"type": "string"
},
{
"creator": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:52.992Z",
"gmtModified": "2018-07-25T08:44:52.992Z",
"gmtModifiedView": "string",
"id": 1,
"name": "string",
"sceneId": 1,
"sceneName": "string1",
"tableColumn": "string",
"tableName": "string",
"type": "数值"
}
],
"tableColumn": "string",
"tableName": "string",
"type": "数值"
}
],
"sum": {
"creator": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:52.992Z",
"gmtModified": "2018-07-25T08:44:52.992Z",
"gmtModifiedView": "string",
"id": 0,
"name": "string",
"sceneId": 0,
"sceneNames": [
{
"creator": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:52.992Z",
"gmtModified": "2018-07-25T08:44:52.992Z",
"gmtModifiedView": "string",
"id": 0,
"name": "string",
"sceneId": 0,
"sceneName": "string",
"tableColumn": "string",
"tableName": "string",
"type": "string"
}
],
"tableColumn": "string",
"tableName": "string",
"type": "string"
},
"totalCount": 0,
"totalPage": 0
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": [
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-26T03:44:17.215Z",
"gmtModified": "2018-07-26T03:44:17.215Z",
"gmtModifiedView": "string",
"id": 0,
"sceneKey": "string",
"sceneName": "string",
"sceneType": 0
},
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-26T03:44:17.215Z",
"gmtModified": "2018-07-26T03:44:17.215Z",
"gmtModifiedView": "string",
"id": 1,
"sceneKey": "string1",
"sceneName": "string1",
"sceneType": 0
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": {
"list": [
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.024Z",
"gmtModified": "2018-07-25T08:44:53.024Z",
"gmtModifiedView": "string",
"id": 0,
"sceneKey": "string",
"sceneName": "string",
"sceneType": 1
}
],
"sum": {
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.024Z",
"gmtModified": "2018-07-25T08:44:53.024Z",
"gmtModifiedView": "string",
"id": 0,
"sceneKey": "string",
"sceneName": "string",
"sceneType": 0
},
"totalCount": 0,
"totalPage": 0
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"data": {"num": 0},
"desc": ""
}
\ No newline at end of file
{
"code": "string",
"data": [
{
"tagName": "哈",
"tagNum": "0"
},
{
"tagName": "哈ha",
"tagNum": "1"
},
{
"tagName": "哈haha",
"tagNum": "2"
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": [
{
"tagName": "啦",
"tagNum": "1"
},
{
"tagName": "啦la",
"tagNum": "2"
},
{
"tagName": "啦lalala",
"tagNum": "3"
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": true,
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": true,
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": true,
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 838,
"totalPage": 84,
"list": [
{
"advertId": 2899,
"advertName": "www",
"advertMaster": "dd",
"agentName": "公司网炸了!",
"source": 0,
"inspectStatus": 3,
"inspectResult": 3,
"inspectCount": 6,
"inspectMemo": "sss",
"inspectTime": 1526539754000,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526538473000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2901,
"advertName": "testing_jzl_ads",
"advertMaster": "杭州虎妞科技",
"agentName": "兑吧科技网络有限公司",
"source": 0,
"inspectStatus": 3,
"inspectResult": 3,
"inspectCount": 2,
"inspectMemo": "dd",
"inspectTime": 1526540462000,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526538468000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2900,
"advertName": "105",
"advertMaster": "testtest",
"agentName": "杭州兑吧网络科技有限公司23",
"source": 0,
"inspectStatus": 1,
"inspectResult": 1,
"inspectCount": 1,
"inspectMemo": "",
"inspectTime": 1526539660000,
"firstReviewer": "",
"ae": "zjy",
"sale": "方雄韬",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537782000,
"advertStatusShow": "失效",
"advertStatus": 1
},
{
"advertId": 2902,
"advertName": "jzl_testing_ads",
"advertMaster": "杭州虎妞科技",
"agentName": "兑吧科技网络有限公司",
"source": 0,
"inspectStatus": 3,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537777000,
"advertStatusShow": "失效",
"advertStatus": 1
},
{
"advertId": 2903,
"advertName": "jzl_testing_ad",
"advertMaster": "杭州虎妞科技",
"agentName": "兑吧科技网络有限公司",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537695000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2904,
"advertName": "106",
"advertMaster": "3级广告主",
"agentName": "二级代理商",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537631000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2905,
"advertName": "107",
"advertMaster": "3级广告主",
"agentName": "二级代理商",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537556000,
"advertStatusShow": "失效",
"advertStatus": 1
},
{
"advertId": 2906,
"advertName": "108",
"advertMaster": "3级广告主2",
"agentName": "二级代理商",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537362000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2907,
"advertName": "109",
"advertMaster": "3级广告主2",
"agentName": "二级代理商",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537289000,
"advertStatusShow": "有效",
"advertStatus": 0
},
{
"advertId": 2908,
"advertName": "110",
"advertMaster": "4级广告主",
"agentName": "3级代理商",
"source": 0,
"inspectStatus": 0,
"inspectResult": 0,
"inspectCount": 0,
"inspectMemo": "",
"inspectTime": null,
"firstReviewer": "",
"ae": "",
"sale": "",
"secondReviewer": "徐恒飞",
"lastReviewTime": 1526537266000,
"advertStatusShow": "有效",
"advertStatus": 0
}
],
"sum": null
}
}
{
"code": "string",
"data": true,
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 12,
"totalPage": 2,
"list": [
{
"advertId": 4,
"advertName": "广告4sssssssssssssssssssssssssssssssssssss",
"advertMaster": "广告主4",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": "",
"labels": [
{
"tagNum":1,
"tagName": "行业标签",
"child": [
{
"tagNum":2,
"tagName": "金融理财",
"child": [{ "tagName": "借贷",
"tagNum":3
}]
}
]
}, {
"tagNum":2,
"tagName": "属性标签",
"child": [
{
"tagNum":1,
"tagName": "屏蔽标签",
"child": [{ "tagName": "APP直链",
"tagNum":3
}]
},
{
"tagNum":1,
"tagName": "包装形式",
"child": [{ "tagName": "360系" ,
"tagNum":3
}, {"tagName": "美团系" ,
"tagNum":4
}]
}
]
}, {
"tagNum":2,
"tagName": "属性标签",
"child": [
{
"tagNum":1,
"tagName": "屏蔽标签",
"child": [{ "tagName": "APP直链",
"tagNum":3
}]
},
{
"tagNum":1,
"tagName": "包装形式",
"child": [{ "tagName": "360系" ,
"tagNum":3
}, {"tagName": "美团系" ,
"tagNum":4
}]
}
]
}
]
},
{
"advertId": 5,
"advertName": "广告5",
"advertMaster": "广告主5",
"agentName": "代理2",
"source": 1,
"reviewStatus": 1,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 6,
"advertName": "广告6",
"advertMaster": "广告主6",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 7,
"advertName": "广告7",
"advertMaster": "广告主7",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 8,
"advertName": "广告8",
"advertMaster": "广告主8",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 9,
"advertName": "广告9",
"advertMaster": "广告主9",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 10,
"advertName": "广告10",
"advertMaster": "广告主10",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 11,
"advertName": "广告11",
"advertMaster": "广告主11",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 13,
"advertName": "广告13",
"advertMaster": "广告主13",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
},
{
"advertId": 15,
"advertName": "广告15",
"advertMaster": "广告主15",
"agentName": "代理2",
"source": 1,
"reviewStatus": 0,
"firstResult": "1",
"secondResult": "0",
"firstMemo": "",
"secondMemo": "",
"lastReviewTime": 1524931200000,
"firstReviewer": "运营1",
"ae": "ae2",
"sale": "sale2",
"secondReviewer": ""
}
],
"sum": null
}
}
{
"code": "string",
"data": [
{
"exampleId": 0,
"id": 0,
"imgUrl": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
}, {
"exampleId": 0,
"id": 0,
"imgUrl": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": [
{
"exampleId": 0,
"id": 0,
"imgUrl": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
}, {
"exampleId": 0,
"id": 0,
"imgUrl": "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
}
],
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 5,
"totalPage": 1,
"list": [
{
"id": 67,
"curDate": "2018-03-12",
"dHour": null,
"slotId": 114,
"slotName": "左上角红点位置",
"appId": 20551,
"appName": "KC网络电话",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 99988,
"cheatFee": 99.9999,
"cheatFeeRate": 0.9999,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.8866,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 100.9999,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C1、C2",
"mediaName": "胡子爷爷",
"agentName": "包警长",
"appAdConsume": 777,
"cheatGrade": "2",
"riskReviewId": null,
"preRiskReviewer": "徐恒飞",
"preResult": null,
"preResultTime": null,
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": 11,
"reviewCount": 13,
"exampleFeatures": "1",
"exampleDemand": "1",
"exampleResult": null,
"gmtCreate": "2018-05-09 10:15:44",
"exampleStatus": 0,
"cpm": null,
"countOfImgs": 0,
"imgs": null
},
{
"id": 66,
"curDate": "2018-03-13",
"dHour": null,
"slotId": 114,
"slotName": "左上角红点位置",
"appId": 20551,
"appName": "KC网络电话",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 99988,
"cheatFee": 99.9999,
"cheatFeeRate": 0.9999,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.8866,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 100.9999,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C1、C2",
"mediaName": "胡子爷爷",
"agentName": "包警长",
"appAdConsume": 777,
"cheatGrade": "2",
"riskReviewId": null,
"preRiskReviewer": "徐恒飞",
"preResult": null,
"preResultTime": null,
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": 22,
"reviewCount": 13,
"exampleFeatures": "1",
"exampleDemand": "1",
"exampleResult": null,
"gmtCreate": "2018-05-09 10:02:12",
"exampleStatus": 0,
"cpm": null,
"countOfImgs": 1,
"imgs": null
},
{
"id": 65,
"curDate": "2018-03-31",
"dHour": null,
"slotId": 5208,
"slotName": "600*250物料投放",
"appId": null,
"appName": null,
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 974694,
"cheatFee": 184638.0,
"cheatFeeRate": 0.1894,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.3705,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 9.47,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C5,C7,C8,C9",
"mediaName": null,
"agentName": null,
"appAdConsume": 976181,
"cheatGrade": "3",
"riskReviewId": null,
"preRiskReviewer": "张舒曼",
"preResult": null,
"preResultTime": null,
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": 33,
"reviewCount": 1,
"exampleFeatures": "test1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
"exampleDemand": "test1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
"exampleResult": "ustguq2ftwd782r36d1111111111111111111111111111",
"gmtCreate": "2018-05-08 17:30:53",
"exampleStatus": 0,
"cpm": null,
"countOfImgs": 2,
"imgs": null
},
{
"id": 64,
"curDate": "2018-03-31",
"dHour": null,
"slotId": 5202,
"slotName": "600*250物料投放",
"appId": null,
"appName": null,
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 974694,
"cheatFee": 184638.0,
"cheatFeeRate": 0.1894,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.3705,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 9.47,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C5,C7,C8,C9",
"mediaName": null,
"agentName": null,
"appAdConsume": 976181,
"cheatGrade": "3",
"riskReviewId": null,
"preRiskReviewer": null,
"preResult": null,
"preResultTime": null,
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": 44,
"reviewCount": 1,
"exampleFeatures": "test",
"exampleDemand": "test",
"exampleResult": null,
"gmtCreate": "2018-05-08 16:42:18",
"exampleStatus": 0,
"cpm": null,
"countOfImgs": 3,
"imgs": null
},
{
"id": 63,
"curDate": "2018-03-13",
"dHour": null,
"slotId": 114,
"slotName": "左上角红点位置",
"appId": 20551,
"appName": "KC网络电话",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 99988,
"cheatFee": 99.9999,
"cheatFeeRate": 0.9999,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.8866,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 100.9999,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C1、C2",
"mediaName": "胡子爷爷",
"agentName": "包警长",
"appAdConsume": 777,
"cheatGrade": "2",
"riskReviewId": null,
"preRiskReviewer": "徐恒飞",
"preResult": null,
"preResultTime": null,
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": 55,
"reviewCount": 13,
"exampleFeatures": "test",
"exampleDemand": "test",
"exampleResult": null,
"gmtCreate": "2018-05-08 14:15:26",
"exampleStatus": 0,
"cpm": null,
"countOfImgs": 4,
"imgs": null
}
],
"sum": null
}
}
{
"code": "0",
"desc": "成功",
"success": true,
"data": [
{
"id": 1,
"name": "徐恒飞",
"account": "xhf",
"enable": true,
"tokenSecret": null,
"superAdmin": true,
"canRecharge": true,
"staffId": 1,
"email": "xhf@duiba.com.cn",
"mobile": "13333333333",
"gmtCreate": 1403090180000,
"gmtModified": 1521100577000,
"systemIdSet": [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14, 15, 17],
"isRoleSuperAuth": true,
"sensitiveDataAuth": true,
"dingUserId": null
},
{
"id": 89,
"name": "张舒曼",
"account": "zhangshuman",
"enable": true,
"tokenSecret": null,
"superAdmin": false,
"canRecharge": false,
"staffId": null,
"email": "zhangshuman@duiba.com.cn",
"mobile": "13606632435",
"gmtCreate": 1504233036000,
"gmtModified": 1520423548000,
"systemIdSet": [0, 3, 14],
"isRoleSuperAuth": false,
"sensitiveDataAuth": true,
"dingUserId": null
},
{
"id": 148,
"name": "舒曼",
"account": "5e28c30daad999e6b268a783f6c0cf3d",
"enable": true,
"tokenSecret": null,
"superAdmin": false,
"canRecharge": false,
"staffId": null,
"email": "zsm@duiba.com.cn",
"mobile": "13606632435",
"gmtCreate": 1522304547000,
"gmtModified": 1522304547000,
"systemIdSet": [0, 14],
"isRoleSuperAuth": false,
"sensitiveDataAuth": true,
"dingUserId": null
}
]
}
{
"code": "0",
"data": 111.11,
"desc": "成功",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": {
"list": [
{
"cheatGrade": "1",
"curDate": "2018-03-26T10:45:59.608Z",
"preResult": 0,
"preRiskReviewer": "string",
"reviewRemarks": "string",
"reviewResult": 0,
"riskReviewer": "string",
"slotId": 0,
"slotName": "string"
},
{
"cheatGrade": "1",
"curDate": "2018-03-26T10:45:59.608Z",
"preResult": 0,
"preRiskReviewer": "string",
"reviewRemarks": "string",
"reviewResult": 0,
"riskReviewer": "string",
"slotId": 0,
"slotName": "string"
},
{
"cheatGrade": "1",
"curDate": "2018-03-26T10:45:59.608Z",
"preResult": 0,
"preRiskReviewer": "string",
"reviewRemarks": "string",
"reviewResult": 0,
"riskReviewer": "string",
"slotId": 0,
"slotName": "string"
}
],
"sum": {
"cheatGrade": "string",
"curDate": "2018-03-26T10:45:59.608Z",
"preResult": 0,
"preRiskReviewer": "string",
"reviewRemarks": "string",
"reviewResult": 0,
"riskReviewer": "string",
"slotId": 0,
"slotName": "string"
},
"totalCount": 88,
"totalPage": 9
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "string",
"data": {
"cheatGradeFive": 10,
"cheatGradeFour": 110,
"cheatGradeOne": 1110,
"cheatGradeSix": 1110,
"cheatGradeThree": 11110,
"cheatGradeTwo": 110,
"cheatGradeZero": 110,
"toDOCount": 10,
"finalDealMoneySum": "300.00"
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 16,
"totalPage": 2,
"list": [
{
"id": 10118,
"curDate": "2018-05-21",
"dHour": "13",
"slotId": 9509,
"slotName": "YL009",
"appId": 45557,
"appName": "有利网(脉速)",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 1389337,
"cheatFee": 51077.9,
"cheatFeeRate": 0.0368,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.0,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 1.84,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "c4,c5,c2,c7",
"mediaName": "陈莉莉",
"agentName": "李鸿媛",
"appAdConsume": null,
"cheatGrade": "1",
"riskReviewId": 1067,
"preRiskReviewer": "陈薇",
"preResult": null,
"preResultTime": "",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "雷后阳",
"isInExample": null,
"reviewRemarks": "11111111111111111111111111111111111",
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-05-21 14:33:23",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": true,
"countOfImgs": 0,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 10060,
"curDate": "2018-05-20",
"dHour": "1",
"slotId": 1017,
"slotName": "追小说-sdk-首页-banner",
"appId": 24858,
"appName": "追小说",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 87513,
"cheatFee": 14389.6004,
"cheatFeeRate": 0.1644,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.5,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 12.22,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C9,A2",
"mediaName": "蒋碧莲",
"agentName": "沈丽师",
"appAdConsume": null,
"cheatGrade": "2",
"riskReviewId": 1056,
"preRiskReviewer": "陈薇",
"preResult": 3,
"preResultTime": "2018-05-21 10:13:27",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "雷后阳",
"isInExample": null,
"reviewRemarks": "222222222222222222222222222222222",
"exampleId": null,
"reviewCount": 4,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-05-21 08:22:29",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": true,
"countOfImgs": 1,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 10092,
"curDate": "2018-05-20",
"dHour": "1",
"slotId": 4420,
"slotName": "banner",
"appId": 37191,
"appName": "消方方",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 161466,
"cheatFee": 28896.0008,
"cheatFeeRate": 0.179,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.88,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 0.0,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "2",
"riskReviewId": 1057,
"preRiskReviewer": null,
"preResult": 3,
"preResultTime": "2018-05-21 10:13:30",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "王培珍",
"isInExample": null,
"reviewRemarks": "33333333333333333333333",
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": false,
"countOfImgs": 2,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 111108,
"curDate": "2018-02-25",
"dHour": "1",
"slotId": 1013,
"slotName": "睿道-信息流大图",
"appId": 23542,
"appName": "今日头条",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 0,
"cheatFee": 0.0,
"cheatFeeRate": 0.0,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.0,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 0.0,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "4",
"riskReviewId": 4,
"preRiskReviewer": "刘瑶",
"preResult": 1,
"preResultTime": "2018-03-29 16:48:52",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "徐恒飞",
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": false,
"countOfImgs": 3,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 111105,
"curDate": "2018-02-25",
"dHour": "1",
"slotId": 1,
"slotName": "插屏",
"appId": 17775,
"appName": "测试应用",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 0,
"cheatFee": 0.0,
"cheatFeeRate": 0.0,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.0,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 0.0,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "1",
"riskReviewId": 8,
"preRiskReviewer": "徐恒飞",
"preResult": 2,
"preResultTime": "2018-03-29 16:52:22",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "徐恒飞",
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": false,
"countOfImgs": 4,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 111112,
"curDate": "2018-02-25",
"dHour": "15",
"slotId": 1026,
"slotName": "首页-图标",
"appId": 26465,
"appName": "微米浏览器",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 132249,
"cheatFee": 6582.6001,
"cheatFeeRate": 0.0498,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.4087,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 2.49,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "4",
"riskReviewId": 9,
"preRiskReviewer": "郭鹏飞",
"preResult": 1,
"preResultTime": "2018-05-22 14:38:45",
"isSuperiorReview": 1,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "雷后阳",
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-05-21 08:22:34",
"exampleStatus": null,
"cpm": null,
"currentProgress": "媒体运营反馈",
"needNotify": true,
"countOfImgs": 5,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 10108,
"curDate": "2018-05-20",
"dHour": "1",
"slotId": 7970,
"slotName": "icon",
"appId": 42934,
"appName": "101!-hc",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 24233,
"cheatFee": 388.0,
"cheatFeeRate": 0.016,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.4308,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 6.8,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C2,C4,C5,A7",
"mediaName": "余韵",
"agentName": "曹佳宾",
"appAdConsume": null,
"cheatGrade": "0",
"riskReviewId": null,
"preRiskReviewer": null,
"preResult": null,
"preResultTime": "",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理完成",
"needNotify": false,
"mediaDealOpinion": "",
"finalDealMoney": "300"
},
{
"id": 111114,
"curDate": "2018-02-25",
"dHour": "15",
"slotId": 1029,
"slotName": "赚钱中心",
"appId": 26595,
"appName": "触宝电话2",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 31784,
"cheatFee": 1134.8,
"cheatFeeRate": 0.0357,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.6944,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 1.785,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "0",
"riskReviewId": null,
"preRiskReviewer": null,
"preResult": null,
"preResultTime": "",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-05-21 08:22:29",
"exampleStatus": null,
"cpm": null,
"currentProgress": "通知媒体运营",
"needNotify": false,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 10097,
"curDate": "2018-05-20",
"dHour": "1",
"slotId": 181634,
"slotName": "众盟-xmrs-4-yd-浮标",
"appId": 26736,
"appName": "北京易汇众盟",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 223111,
"cheatFee": 510.0,
"cheatFeeRate": 0.0023,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.317,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 6.115,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "C2,C4,C5,A7",
"mediaName": "陈莉莉",
"agentName": "唐振鹏",
"appAdConsume": null,
"cheatGrade": "0",
"riskReviewId": null,
"preRiskReviewer": null,
"preResult": null,
"preResultTime": "",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": null,
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "最终处理结果",
"needNotify": true,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
},
{
"id": 111113,
"curDate": "2018-02-25",
"dHour": "15",
"slotId": 1027,
"slotName": "彭咻咻anner",
"appId": 26506,
"appName": "咻咻红包",
"actExposeCount": null,
"actClickCount": null,
"actClickRate": null,
"sdkPv": null,
"sdkUv": null,
"actRequestPv": null,
"actRequestUv": null,
"participatePv": null,
"participateUv": null,
"participateRate": null,
"dupliParticipate": null,
"launchPv": null,
"eachLaunchUv": null,
"advertExposePv": null,
"advertClickPv": null,
"advertVclickPv": null,
"advertClickRate": null,
"advertVclickRate": null,
"eachClickUv": null,
"adConsume": 600,
"cheatFee": 0.0,
"cheatFeeRate": 0.0,
"jsClickPv": null,
"visitPv": null,
"visitUv": null,
"effectPv": null,
"effectUv": null,
"cvr": null,
"estiCvr": null,
"mediaDueDivide": null,
"divideRate": 0.35,
"adviseDivideRate": null,
"priceUv": null,
"arpu": null,
"creditsScore": 0.0,
"corrClick": null,
"stddevClick": null,
"corrCvr": null,
"stddevCvr": null,
"rules": "",
"mediaName": null,
"agentName": null,
"appAdConsume": null,
"cheatGrade": "5",
"riskReviewId": 7,
"preRiskReviewer": "刘瑶",
"preResult": null,
"preResultTime": "",
"isSuperiorReview": null,
"reviewResult": null,
"reviewResultTime": "",
"riskReviewer": "徐恒飞",
"isInExample": null,
"reviewRemarks": null,
"exampleId": null,
"reviewCount": 0,
"exampleFeatures": null,
"exampleDemand": null,
"exampleResult": null,
"gmtCreate": "2018-02-27 09:43:40",
"exampleStatus": null,
"cpm": null,
"currentProgress": "初步处理结果",
"needNotify": false,
"mediaDealOpinion": "同意",
"finalDealMoney": "300"
}
],
"sum": null
}
}
{
"code": "0",
"desc": "成功",
"success": true,
"data": [
{
"id": 28,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "初步处理结果",
"reviewTime": "2018-05-22 14:12:54",
"rate": null,
"mediaMemo": null
},
{
"id": 29,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "最终处理结果",
"reviewTime": "2018-05-22 14:13:02",
"rate": null,
"mediaMemo": null
},
{
"id": 30,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 2,
"reviewAction": "最终处理结果",
"reviewTime": "2018-05-22 14:14:06",
"rate": null,
"mediaMemo": null
},
{
"id": 35,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "初步处理结果",
"reviewTime": "2018-05-22 16:58:21",
"rate": null,
"mediaMemo": null
},
{
"id": 36,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 2,
"reviewAction": "最终处理结果",
"reviewTime": "2018-05-22 16:59:35",
"rate": null,
"mediaMemo": null
},
{
"id": 37,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "最终处理结果",
"reviewTime": "2018-05-23 09:37:03",
"rate": null,
"mediaMemo": null
},
{
"id": 43,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "初步处理结果",
"reviewTime": "2018-05-23 15:33:27",
"rate": null,
"mediaMemo": null
},
{
"id": 45,
"riskAllId": 211111,
"riskReviewer": "徐恒飞",
"reviewResult": 1,
"reviewAction": "初步处理结果",
"reviewTime": "2018-05-31 09:52:31",
"rate": null,
"mediaMemo": null
},
{
"id": null,
"riskAllId": null,
"riskReviewer": "meida-test",
"reviewResult": null,
"reviewAction": "通知媒体运营",
"reviewTime": "2018-01-01 00:00:01",
"rate": 6000,
"mediaMemo": null
},
{
"id": null,
"riskAllId": null,
"riskReviewer": "meida-test",
"reviewResult": null,
"reviewAction": "媒体运营反馈",
"reviewTime": "",
"rate": 4000,
"mediaMemo": "hello world"
}
]
}
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 5,
"totalPage": 1,
"list": [
{
"name": "场景1",
"type": "wawaji",
"scence": "wawaji",
"detail": "c端产品",
"user": "前端",
"time": "2018-07-19"
}
],
"sum": null
}
}
{
"code": "0",
"desc": "查询媒体包列表",
"data": {
"totalCount": 5,
"totalPage": 1,
"list": [
{
"id": 3,
"name": "一个被逼疯的测试",
"remark": "一个被逼疯的测试",
"status": "启用"
},
{
"id": 3,
"name": "一个被逼疯的测试",
"remark": "一个被逼疯的测试",
"status": "启用",
"child": 1
},
{
"id": 3,
"name": "一个被逼疯的测试",
"remark": "一个被逼疯的测试",
"status": "启用",
"child": 1
},
{
"id": 3,
"name": "一个被逼疯的测试",
"remark": "一个被逼疯的测试",
"status": "启用",
"child": 1
},
{
"id": 3,
"name": "一个被逼疯的测试",
"remark": "一个被逼疯的测试",
"status": "启用"
}
]
}
}
\ No newline at end of file
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 5,
"totalPage": 1,
"list": [
{
"name": "场景1",
"sign": "wawaji",
"type": "wawaji",
"detail": "c端产品",
"createUser": "前端",
"updateTime": "2018-07-19"
}
],
"sum": null
}
}
{
"code": "0",
"desc": "成功",
"success": true,
"data": {
"totalCount": 5,
"totalPage": 1,
"list": [
{
"name": "场景1",
"sign": "wawaji",
"scence": "wawaji",
"status": 0,
"detail": "c端产品",
"user": "前端",
"time": "2018-07-19"
}
],
"sum": null
}
}
{
"code": "string",
"data": {
"list": [
{
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}, {
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 1,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 0,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"mode": 0,
"name": "string",
"status": 0,
"strategyId": 1,
"type": 0
},
{
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 0,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 1,
"mode": 1,
"name": "string",
"parentRuleId": 1,
"status": 0,
"strategyId": 2,
"type": 0
},
{
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 0,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 2,
"mode": 0,
"name": "string",
"parentRuleId": 2,
"status": 0,
"strategyId": 3,
"type": 0
},
{
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 0,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 3,
"mode": 0,
"name": "string",
"parentRuleId": 3,
"status": 0,
"strategyId": 4,
"type": 0
},
{
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 111,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 4,
"mode": 0,
"name": "string",
"status": 0,
"strategyId": 5,
"type": 1
}
],
"sum": {
"conditions": [
{
"creator": "string",
"editor": "string",
"fieldId": 0,
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"operation": 0,
"ruleId": 0,
"threshold": "string"
}
],
"creator": "string",
"decision": 111,
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.228Z",
"gmtModified": "2018-07-25T08:44:53.228Z",
"id": 0,
"mode": 0,
"name": "string",
"status": 0,
"strategyId": 6,
"type": 0
},
"totalCount": 0,
"totalPage": 0
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"adminName": "徐恒飞",
"success": true,
"adminId": 1,
"email": "xhf@duiba.com.cn",
"code": "SSO:01001"
}
\ No newline at end of file
{
"success": true
}
\ No newline at end of file
{
"system": {
"id": 24,
"appNameAlias": "tuia-news-manager",
"appName": "天天趣闻媒体管理平台",
"icon": null
},
"success": true,
"ssoHomeURL": "http://sso.duibadev.com.cn"
}
\ No newline at end of file
{
"code": "string",
"data": {
"list": [
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.042Z",
"gmtModified": "2018-07-25T08:44:53.042Z",
"id": 0,
"sceneId": 0,
"score1": 1,
"score2": 2,
"score3": 3,
"score4": 4,
"status": 0,
"strategyKey": "string",
"strategyName": "string",
"strategyType": 0
},
{
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.042Z",
"gmtModified": "2018-07-25T08:44:53.042Z",
"id": 1,
"sceneId": 0,
"score1": 1,
"score2": 2,
"score3": 3,
"score4": 4,
"status": 0,
"strategyKey": "string",
"strategyName": "string",
"strategyType": 0
}
],
"sum": {
"creator": "string",
"description": "string",
"editor": "string",
"gmtCreate": "2018-07-25T08:44:53.042Z",
"gmtModified": "2018-07-25T08:44:53.042Z",
"id": 0,
"sceneId": 0,
"score1": 0,
"score2": 0,
"score3": 0,
"score4": 0,
"status": 0,
"strategyKey": "string",
"strategyName": "string",
"strategyType": 0
},
"totalCount": 0,
"totalPage": 0
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"code": "0",
"desc": "success",
"data": [
{
"tagId": 2,
"contents": "父标签->字标签1"
},
{
"tagId": 3,
"contents": "父标签->字标签2"
},
{
"tagId": 4,
"contents": "父标签->字标签3"
},
{
"tagId": 5,
"contents": "父标签->字标签4"
},
{
"tagId": 6,
"contents": "父标签->字标5"
},
{
"tagId": 7,
"contents": "父标签->字标签6"
},
{
"tagId": 8,
"contents": "父标签->字标签7"
},
{
"tagId": 9,
"contents": "父标签->字标签8"
},
{
"tagId": 10,
"contents": "父标签->字标签9"
},
{
"tagId": 11,
"contents": "父标签->字标签10"
},
{
"tagId": 12,
"contents": "父标签->字标签11"
}
]
}
\ No newline at end of file
{
"code": "0",
"data": {
"fileName": "string",
"md5": "string",
"url": "string"
},
"desc": "string",
"success": true
}
\ No newline at end of file
{
"success": true,
"data": {
"list": [
{
"creator": "string",
"dimension": 0,
"gmtCreate": "2018-05-11T06:01:10.389Z",
"gmtModified": "2018-05-11T06:01:10.389Z",
"id": 0,
"memo": "string",
"mender": "string",
"src": "string",
"stat": 0,
"val": "string"
}
],
"sum": {
"creator": "string",
"dimension": 0,
"gmtCreate": "2018-05-11T06:01:10.389Z",
"gmtModified": "2018-05-11T06:01:10.389Z",
"id": 0,
"memo": "string",
"mender": "string",
"src": "string",
"stat": 0,
"val": "string"
},
"totalCount": 0,
"totalPage": 0
}
}
{
"name": "tuia-risk-manager-node",
"version": "1.0.0",
"description": "风控管理后台",
"main": "app.js",
"scripts": {
"start": "ncu && yarn install && cross-env NODE_ENV=development node ./bin/www",
"build": "yarn install && cross-env BUILD_TYPE=production NODE_ENV=production node build/build.js",
"lint": "eslint --fix --ext .js,.jsx src test/unit/specs test/e2e/specs"
},
"author": "heyesheng@duiba.com.cn",
"license": "ISC",
"dependencies": {
"antd": "^3.4.1",
"mobx": "^4.2.0",
"mobx-react": "^5.0.0",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-router": "^3.2.1"
},
"devDependencies": {
"babel-core": "~6.26.0",
"babel-eslint": "^8.2.3",
"babel-loader": "~7.1.2",
"babel-plugin-import": "^1.7.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "~6.24.1",
"babel-preset-stage-1": "^6.24.1",
"chalk": "^2.4.0",
"clean-webpack-plugin": "^0.1.17",
"cross-env": "^5.0.5",
"css-loader": "~0.28.10",
"ejs": "^2.5.9",
"eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.0.0",
"eslint-plugin-import": "^2.11.0",
"eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.7.0",
"eslint-plugin-react": "^7.7.0",
"eslint-plugin-standard": "^3.0.1",
"express": "^4.16.2",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.9",
"formidable": "^1.0.17",
"friendly-errors-webpack-plugin": "^1.7.0",
"html-loader": "^0.5.5",
"html-webpack-harddisk-plugin": "^0.2.0",
"html-webpack-plugin": "^3.1.0",
"http-proxy-middleware": "^0.18.0",
"imagemin-webpack-plugin": "^2.1.1",
"jsx-loader": "~0.13.2",
"less": "^3.0.1",
"less-loader": "^4.1.0",
"postcss-loader": "^2.1.4",
"progress-bar-webpack-plugin": "^1.11.0",
"react-hot-loader": "^2.0.0-alpha-4",
"style-loader": "~0.20.2",
"tuia-auto-upload": "git+ssh://git@gitlab2.dui88.com:frontend/tuia-auto-upload.git#1.1.1",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "~1.0.1",
"webpack": "^3.11.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-dev-middleware": "^2.0.6",
"webpack-hot-middleware": "^2.21.0",
"webpack-merge": "^4.1.2"
},
"repository": {
"type": "git",
"url": "git@gitlab2.dui88.com:frontend/tuia-risk-manager-node.git"
},
"keywords": [
"Webpack",
"React",
"Antd",
"ES6"
]
}
module.exports = {
plugins: [
require('autoprefixer')({
browsers: [
'last 2 versions',
'Firefox ESR',
'> 1%',
'ie >= 9',
'iOS >= 8',
'Android >= 4'
]
}),
require('cssnano')({
preset: 'default',
zindex: false,
reduceTdent: false
})
]
};
import React from 'react';
import {
Link,
hashHistory
} from 'react-router';
import {
Breadcrumb as AntdBreadcrumb
} from 'antd';
import styles from './index.less';
const routes = [{
path: '//',
breadcrumbName: '首页'
}, {
path: 'accountManager/weMediaAccount',
breadcrumbName: '自媒体账号'
}];
class Breadcrumb extends React.Component {
constructor(props) {
super(props);
hashHistory.getCurrentLocation();
}
itemRender = (route, params, routes, paths) => {
const last = routes.indexOf(route) === routes.length - 1;
return last ? <span>{route.breadcrumbName}</span> : <Link to={paths.join('/')}>{route.breadcrumbName}</Link>;
}
render() {
const { show = false } = this.props;
return (
show
? <AntdBreadcrumb
className={styles.container}
itemRender={this.itemRender}
routes={routes}
/>
: <span></span>
);
}
}
export default Breadcrumb;
/**
* 目前因为没有footer需求,用于今后拓展
*/
import React from 'react';
import { Layout } from 'antd';
import styles from './index.less';
const { Footer: AntdFooter } = Layout;
class Footer extends React.Component {
render() {
return (
<AntdFooter className={styles.footer}></AntdFooter>
);
};
};
export default Footer;
.footer {
padding: 0!important;
}
\ No newline at end of file
import React from 'react';
import common from 'src/lib/common';
import utils from 'src/lib/utils';
import {
Layout
} from 'antd';
import Breadcrumb from 'src/components/breadcrumb';
import styles from './index.less';
const { Header: AntdHeader } = Layout;
class Header extends React.Component {
handleQuit = () => {
const _quit = () => {
common.fetch('/sso/outLogin')
.then((res) => {
if (res.success) {
utils.logout();
}
});
};
_quit();
}
render() {
const { accountInfo = {} } = this.props;
const { name = '' } = (accountInfo || {});
return (
<AntdHeader className={styles.header}>
<div
className={styles.logo}
onClick={() => utils.jumpTo('/')}
>
{/* <img src="../../../static/favicon.ico" className={styles.img_wid} alt=""/> */}
<img className = {styles.img_wid} src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAAAmCAMAAABtX0w5AAAArlBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8tivQqAAAAOXRSTlMABhL7Zuy6HNwgCQ8V9zQMq9OeLb5JJuDKfmBP6MGkmYZvxonOkTcxd/Pwsmnk169FKo1WPBlcP5VadjJvAAAFN0lEQVRIx6WU2ZaiMBBAKyC7yKogIpuIKO5La/3/j01CRGXGM/Mw95zuJiHerlSVBZxbiG8KBXocUH7vDFAaQcfExyMw9CU67EyK5Q2ekAg/EJcEPrDmmBp/l1rCBeMfw7gVmCoG/7SwXWPPWt/gjbfDWrkpw79Iz36BGMhyaeLe9z0glnK0O1vQPcx/JsNndCSn+47j2DyALUoVcPTRpcS8qirDDgJVjRFjVQ2CoIJ6Ib8CbO6J2S32yVkHij4LpDAsyzIxtoPBIEpwnUX04Q4wwiez08rzvBrjy4n+HVmALzY0c2Qh4QsBKKvdJlcEiqHhJwmA4soxzps1jmGoaacl7q8aBeAtDaZtZLnal1Z+BBwFxTJN52ge0nQtuu2Wj5WwxzGZ+n65RjMs5r5vAIjIaSqWeFaXpCfVV+NZC1HQzAAijE8AKrbS0xzvmkqlB9xMKdmUtubwJX2wqKOwZv/+LH5IYSvFQRBLkkGlC179t7QQr63URocw4Gy+pKLLBNMYN6xFjVz8kN7Pvoj+8qx/kXqh+ZJCy+IlXdcCVbmsWU17yLpIekuJRVe5YMEX6cqRqqfUVBl7qbv+bqYDeDIPTywqKjo6Lyn1SDgA+CYdqcHqKZXchOI6IpeGHgDM9tTJCX5YyWSxJyVfpdfYOfVySnhO1weBRjbj7bnmDZtRhZ6az+p72QYX1Uj5Ij2avtZJjZZlK82AVYbb9lHI4522dbPaG8bY9QdtqVa6An2HKVBmmAy7nIYtMcspQ1vybPoTGB5MZLgTeKK5BzomyuYwoFJ3tVrgJlrVa5wCJcKFPuHStdwSPKWrhl+9bSuy5Inwr/AikjBqC/XBrmITL6MVfEpLaMnMVnos+ampTpV0nfNRpV4A+oUayow97Q9ZbiKgaLI45tKuT4UGN1T6s+PpZCX3pm0jOMiQctKXQm/08XzvTlzaoFRPKa6JNum+pr7GPqyiumX35Dnu96l+/WNIky0eCJfWTePLjKT2xjMuTSb0yFRi8bECCKn4Kd1KOB3I7h9SpZAGQKV89HFuMHECJjWnN4Cbu+b1SqlrWG/6ke42uPxDOhZlg57d81cdW1GkUunHoumRReSIstfO+56U5nz4u9R4xGOgyLgu5x1+EWMBonolbDJQZ2d1ZkB3wvf1N+VAAUpfOkzPBCgnOxY/2MgrkDVWcBU/aSMYNgZwViOBwEsqxk+pMHsesIQeFoBON3MT+2xynb35CiHwb7oO6rNU4H8QZPxGc4P/QCm+SgsN/odJ+c05ed1EUxSFGBZ7JPRnIrAqsuSyX5rC9tnYUIhlsE22oozKP51e57Qui2xhT7ZHAKM+kePivDgSeFxoMGcwojTLFcivtNiRfokAlEzI78DQkt/L9E4o0arRXB7aOQ3PH8/CizcrZyAFd7irxtQ/Vm5qydEwOSv6IgXwHKUZPPP66DltAT6J6HBNspV3n1/OCV3bS32XFdbV8eQtADmRJnczAazsQaWhYg+6xH3EKj6Ufs6LiEBSJK7tRGlNN+pE2K3Sxcq5y5WxlG3hEKgZUOkS4PSW8hHC2Wz7cQ5TNr7tzJtc/Z80pTuua+0m2jwrR/IFRpdYOzzuYQR65gJUxe0tpfOSt9a8Ij2nXss6UOmWdfTx4nhwDC4Qn2BshsZifgNtpx0imNGBsQ0FWByMA5dyhJ/5pvgxoI+3N9VgN2i2BIbykeROoOYWk1pnB5Tlbr9/6E0EJHKuQh3u7RFQ6Se6pQOnt0khOouftaOhGPwJCFveFINA+9JiTUp7lK5+AQTzAL9if75kAAAAAElFTkSuQmCC" alt=""/>
<span>风控管理平台</span>
</div>
<div className={styles.header_wrap}>
<Breadcrumb show={false}/>
<div className={styles.user_info_wrap}>
<span>{name}</span>
<span onClick={this.handleQuit}>退出</span>
</div>
</div>
</AntdHeader>
);
}
}
export default Header;
.logo {
width:250px;
font-size: 18px;
color: #fff;
float: left;
cursor: pointer;
span{
padding-left:15px;
border-left:1px solid #fff
}
.img_wid{
margin-right:10px;
width:76px;
height:34px;
}
}
.header {
padding: 0 20px!important;
}
.header_wrap {
display: flex;
justify-content: space-between;
align-items: center;
width: calc(100% - 250px);
height: 100%;
padding: 0 4px 0 24px;
float:left;
}
.user_info_wrap {
span {
padding: 5px 10px;
color: #fff;
&:first-child {
border-right: 1px solid rgba(255,255,255,.45);
}
&:last-child {
cursor: pointer;
}
}
}
/**
* 数据加载提示框
*/
import styles from './index.less';
let loadingNum = 0;
const Loading = (function() {
return {
open(text = '正在处理,请稍等...') {
loadingNum++;
if (loadingNum > 1) {
return;
}
// 生成dom
const doc = window.document;
this.node = doc.createElement('div');
this.node.className = styles.my_loading;
let node2 = doc.createElement('div');
node2.className = styles.my_loading_wrap;
this.node.appendChild(node2);
let node3 = doc.createElement('section');
node3.className = styles.my_loading_content;
node2.appendChild(node3);
let node4 = doc.createElement('i');
node4.className = styles.my_loading_img;
let node5 = doc.createElement('span');
node5.className = styles.my_loading_text;
node5.innerHTML = text;
node3.appendChild(node4);
node3.appendChild(node5);
doc.body.appendChild(this.node);
},
close() {
loadingNum--;
if (loadingNum > 0) {
return;
}
this.node && window.document.body.removeChild(this.node);
}
};
})();
export default Loading;
.my_loading
{
position: fixed;
z-index: 9999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .8);
.my_loading_wrap
{
position: relative;
top: 50%;
left: 50%;
overflow: hidden;
width: 290px;
height: 108px;
margin-top: -54px;
margin-left: -145px;
border-radius: 10px;
background-color: #fff;
.my_loading_content
{
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
.my_loading_img
{
width: 28px;
height: 28px;
background-image: data-uri('./loading.gif');
background-size: 100% 100%;
}
.my_loading_text
{
margin-left: 5px;
font-size: 16px;
font-weight: bold;
color: #091929;
}
}
}
}
\ No newline at end of file
import React from 'react';
import { Link } from 'react-router';
import PermissionTool from 'src/lib/permissionTools';
import {
Layout,
Menu as AntdMenu,
Icon
} from 'antd';
import MENU from './menuData';
import styles from './index.less';
const { SubMenu } = AntdMenu;
const { Sider } = Layout;
class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
collapsed: false
};
}
// 菜单伸缩
_toggle = () => {
this.setState((preState, props) => ({
collapsed: !preState.collapsed
}));
}
// 生成一级菜单
_createSubMenu = () => {
return MENU.map((item) => {
const { icon, title, key, auth } = item;
const subMenuTitle = (
<span>
<Icon type={icon} />
<span>{title}</span>
</span>
);
return PermissionTool.ifRender(auth) ? (
<SubMenu
key={key}
title={subMenuTitle}
>
{ this._createItemMenu(item) }
</SubMenu>
) : null;
});
}
// 生成二级菜单
_createItemMenu = (subMenuData) => {
const { children } = subMenuData;
return children.map((subItem) => {
const { auth, key, route, title } = subItem;
return PermissionTool.ifRender(auth) ? (
<AntdMenu.Item key={key}>
<Link to={route}>{title}</Link>
</AntdMenu.Item>
) : null;
});
}
// 获取当前路由
getCurrentPaths = () => {
const { currentLocation = {} } = this.props;
const { pathname = '' } = currentLocation;
let paths = pathname.split('/');
paths.shift();
if (paths.length === 1 && paths[0] === '') {
paths = ['riskmng', 'auditsys', 'ruleEngine'];
}
return paths;
}
render() {
const currentPaths = this.getCurrentPaths();
const defaultOpenKeys = [currentPaths.shift()];
const selectedKeys = [currentPaths.shift()];
const { collapsed } = this.state;
return (
<Sider
width={150}
trigger={null}
className={styles.slider}
collapsible
collapsed={collapsed}
>
<div className={styles.menu_top} onClick={this._toggle}>
<Icon
className="trigger"
type={collapsed ? 'menu-unfold' : 'menu-fold'}
/>
</div>
<AntdMenu
mode="inline"
selectedKeys={selectedKeys}
defaultOpenKeys={defaultOpenKeys}
className={styles.menu}
>
{this._createSubMenu()}
</AntdMenu>
</Sider>
);
}
}
export default Menu;
.menu_top {
width: 100%;
height: 40px;
line-height: 40px;
text-align: center;
cursor: pointer;
}
.slider {
background: #fff!important;
overflow-y: auto;
}
.menu {
border-right: 0;
}
\ No newline at end of file
const MENU = [
{
title: '风险控制',
icon: 'appstore-o',
key: 'riskmng',
auth: 'riskmng',
route: 'riskmng/auditsys',
children: [
{
title: '风控操作台',
key: 'auditsys',
auth: 'riskmng/auditsys',
route: 'riskmng/auditsys'
},
{
title: '案例库',
key: 'auditcase',
auth: 'riskmng/auditcase',
route: 'riskmng/auditcase'
},
{
title: '内控审核',
key: 'innercheck',
auth: 'riskmng/innercheck',
route: 'riskmng/innercheck'
}
]
},
{
title: '名单管控',
icon: 'user',
key: 'nameFilter',
auth: 'nameFilter',
children: [
{
title: '黑名单',
key: 'black',
auth: 'nameFilter/black',
route: 'nameFilter/black'
},
{
title: '白名单',
key: 'white',
auth: 'nameFilter/white',
route: 'nameFilter/white'
}
]
},
{
title: '规则引擎',
icon: 'setting',
key: 'ruleEngine',
auth: 'ruleEngine',
children: [
{
title: '场景管理',
key: 'scence',
auth: 'ruleEngine/scence',
route: 'ruleEngine/scence'
},
{
title: '策略管理',
key: 'strategy',
auth: 'ruleEngine/strategy',
route: 'ruleEngine/strategy'
},
// {
// title: '规则管理',
// key: 'rule',
// auth: 'ruleEngine/rule',
// route: 'ruleEngine/rule'
// },
// {
// title: '风控报告',
// key: 'report',
// auth: 'ruleEngine/report',
// route: 'ruleEngine/report'
// },
{
title: '字段管理',
key: 'field',
auth: 'ruleEngine/field',
route: 'ruleEngine/field'
}
]
}
];
export default MENU;
import React from 'react';
class Child extends React.Component {
render() {
return (
<div>
You got lv3 child!
</div>
);
}
}
export default Child;
.test{
color: red;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { Link } from 'react-router';
import { Button } from 'antd';
import store from './store';
import styles from './example.less';
// 修饰器函数注入store
@observer
class Example extends React.Component {
componentDidMount() {
store.fetch();
}
render() {
// 从store里获取计算属性 data 以及action
const {data, addNum, isMoreThanFive} = store;
return (
<div>
Example! <span className={styles.test}>CSS Modules Go</span>
<br />
<Button><Link to="example/lv3">route to example/lv3</Link></Button>
<span>{data.num}</span>
<span>数字是否大于5{isMoreThanFive}</span>
<Button onClick={ addNum }>点击增加数字</Button>
{this.props.children}
</div>
);
}
}
export default Example;
import { observable, action, computed } from 'mobx';
import common from 'src/lib/common';
class State {
// 默认data
@observable data = {
num: 1
};
// 计算属性
@computed
get isMoreThanFive() {
if (this.data.num > 5) {
return 'true';
} else {
return 'false';
}
}
// 拉取数据action
@action
fetch = () => {
common.fetch('example/getNum').then((res) => {
this.data = res.data;
});
}
// 修改action
@action
addNum = () => {
this.data.num++;
}
}
// 实例化store
const store = new State();
export default store;
import React from 'react';
class Home extends React.Component {
render() {
return (
<div>
You had match Home
</div>
);
}
}
export default Home;
import React from 'react';
import { observer } from 'mobx-react';
import { withRouter } from 'react-router';
import PageSearch from './search';
import Table from './table';
@observer
class NameFilter extends React.Component {
render() {
return (
<div>
<PageSearch/>
<Table/>
</div>
);
}
};
export default withRouter(NameFilter);
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import {
Form,
Input,
Modal,
Select
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
let TextArea = Input.TextArea;
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const dimension = [
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const riskRankArr = [
{ value: 2, text: '高风险' },
{ value: 1, text: '中风险' },
{ value: 0, text: '低风险' }
];
const stat = [
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
@observer
class Edit extends React.Component {
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { blacklistUpdate, blacklistSave } = store;
const { getFieldValue } = this.props.form;
let params = {
dimension: getFieldValue('dimension'),
stat: getFieldValue('stat'),
src: getFieldValue('src'),
memo: getFieldValue('memo'),
val: getFieldValue('val'),
riskRank: getFieldValue('riskRank'),
gmtCreate: this.props.editObj.gmtCreate || '',
creator: this.props.editObj.creator || '',
id: this.props.editObj.id
};
this.props.isEdit ? blacklistUpdate(params) : blacklistSave(params);
this.props.closeModal();
}
});
};
handleCancel = () => {
this.props.closeModal();
};
render() {
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const { getFieldDecorator } = this.props.form;
// 名单维度
let dimensionProps = getFieldDecorator('dimension', {
initialValue: this.props.editObj.dimension || 0
});
let valProps = getFieldDecorator('val', {
initialValue: this.props.editObj.val || '',
rules: [{
required: true, message: '请输入!'
}]
});
// 风险等级
let riskRankProps = getFieldDecorator('riskRank', {
initialValue: typeof this.props.editObj.riskRank === 'undefined' ? 2 : this.props.editObj.riskRank
});
// 状态
let statProps = getFieldDecorator('stat', {
initialValue: this.props.editObj.stat || 0
});
// 来源
let srcProps = getFieldDecorator('src', {
initialValue: this.props.editObj.src || ''
});
// 备注
let memoProps = getFieldDecorator('memo', {
initialValue: this.props.editObj.memo || '',
rules: [{
max: 64, message: '最多输入64个字符!'
}]
});
return (
<div>
<Modal
title={ this.props.isEdit ? '修改黑名单' : '添加黑名单'}
width={400}
visible={true}
maskClosable={false}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="确认"
cancelText="取消"
>
<Form>
<FormItem
{...formItemLayout}
label="名单维度"
>
{
dimensionProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
disabled={this.props.isEdit}
>
{dimension && dimension.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="名单值"
>
{valProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="风险等级"
>
{
riskRankProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
>
{riskRankArr && riskRankArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="来源"
>
{srcProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="状态"
>
{
statProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
>
{stat && stat.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="备注:"
>
{memoProps(
<TextArea rows={3} />
)}
</FormItem>
{this.props.isEdit ? <FormItem
{...formItemLayout}
label="更新人:"
>
<div>{this.props.editObj.mender}</div>
</FormItem> : null }
{this.props.isEdit ? <FormItem
{...formItemLayout}
label="更新时间:"
>
<div>{this.props.editObj.gmtModified ? moment(this.props.editObj.gmtModified).format(dateFormat) : ''}</div>
</FormItem> : null }
</Form>
</Modal>
</div>
);
}
}
const EditModal = Form.create({})(Edit);
export default EditModal;
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import styles from './index.less';
import {
DatePicker,
Form,
Input,
Button,
Select
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
const dimension = [
{ value: '', text: '全部' },
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const stat = [
{ value: '', text: '全部' },
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
this.search();
}
// 查询
search = () => {
const { updateParams, getDataList } = store;
const { getFieldValue } = this.props.form;
let timeRange = getFieldValue('time');
let params = {
'dateRange.from': (timeRange && timeRange[0] && timeRange[0].format(dateFormat)) || '',
'dateRange.to': (timeRange && timeRange[1] && timeRange[1].format(dateFormat)) || '',
dimension: getFieldValue('dimension'),
stat: getFieldValue('stat'),
src: getFieldValue('src') || '',
currentPage: 1
};
updateParams(params);
getDataList();
}
// 重置
reset = () => {
const { resetFields } = this.props.form;
resetFields();
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
// 名单维度
let dimensionProps = getFieldDecorator('dimension', {
initialValue: ''
});
// 状态
let statProps = getFieldDecorator('stat', {
initialValue: 0
});
// 来源
let srcProps = getFieldDecorator('src');
// 日期选择器
let timeProps = getFieldDecorator('time', {
initialValue: this.state.time
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem>
{timeProps(
<RangePicker
format={dateFormat}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="名单维度:"
>
{
dimensionProps(
<Select
style={{ width: '140px' }}
placeholder="Tags Mode"
>
{dimension && dimension.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="状态:"
>
{
statProps(
<Select
style={{ width: '80px' }}
placeholder="Tags Mode"
>
{stat && stat.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="来源"
>
{srcProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.reset}
>
重置
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.ant-form-item-label {
width: 65px;
}
.ant-form-item {
width: 200px;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import { message } from 'antd';
import common from 'src/lib/common';
class State {
// loading
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
'dateRange.from': '',
'dateRange.to': '',
dimension: '',
stat: '',
src: '',
currentPage: 1,
pageSize: 6
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
common.fetch('/blacklist/list', this.params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || [];
});
}
// 启用禁用
@action
changeSatus = (params) => {
common.fetch('/blacklist/enordis', params, 'post', {isJson: false})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// 添加黑名单
@action
changeSatus = (params) => {
common.fetch('/blacklist/enordis', params, 'post', {isJson: false})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// 更新数据状态
@action
blacklistSave = (params) => {
common.fetch('/blacklist/save', params, 'post', {isJson: false})
.then(res => {
if (res.code === 'E1000006') {
message.warning(res.desc);
} else {
this.getDataList();
}
});
}
// 更新
@action
blacklistUpdate = (params) => {
common.fetch('/blacklist/update', params, 'post', {isJson: false})
.then(res => {
this.getDataList();
});
}
// 导出
@action
downLoadTable = (ids) => {
let params = Object.assign({}, ids, this.params);
window.open('/blacklist/export?' + common.concatUrl(params));
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Button, Row, Col, Modal } from 'antd';
import { observer } from 'mobx-react';
import store from '../store';
import EditModal from '../modals/editModal';
import styles from './index.less';
import moment from 'moment';
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const confirm = Modal.confirm;
const dimension = [
{ value: '', text: '全部' },
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const stat = [
{ value: '', text: '全部' },
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
function getDimension(key) {
let title = '';
dimension.forEach(item => {
if (item.value === key) {
title = item.text;
}
});
return title;
}
function getStat(key) {
let title = '';
stat.forEach(item => {
if (item.value === key) {
title = item.text;
}
});
return title;
}
@observer
class BlackTable extends React.Component {
constructor(props) {
super(props);
this.state = {
// 储存当前选中的行
selectedRows: [],
editObj: [],
isEdit: false,
show: false
};
}
showModal = (isEdit, obj) => {
this.setState({
isEdit: isEdit,
show: true,
editObj: obj
});
}
closeModal = () => {
this.setState({
show: false
});
}
check(status) {
if (this.state.selectedRows.length === 0) {
confirm({
title: '提示',
content: '请勾选相应黑名单数据!',
okText: '确定',
okType: 'danger',
cancelText: '取消'
});
return;
}
let _this = this;
confirm({
title: '提示',
content: '是否启用/禁用该黑名单?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
_this.changeSatus(status);
}
});
}
changeSatus = (status) => {
const { changeSatus } = store;
let id = [];
this.state.selectedRows.forEach(item => {
id.push(item.id);
});
let params = {
stat: status,
id: id.join(',')
};
changeSatus(params);
}
// 下载
downLoadTable = () => {
const { downLoadTable } = store;
let id = [];
this.state.selectedRows.forEach(item => {
id.push(item.id);
});
downLoadTable({ids: id});
}
render() {
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const rowSelection = {
onChange: (selectedRowKeys = [], selectedRows = []) => {
this.setState({
selectedRows
});
}
};
const columns = [{
title: '名单维度',
dataIndex: 'dimension',
render: (text, record, index) => {
return (
getDimension(text)
);
}
}, {
title: '名单值',
dataIndex: 'val'
}, {
title: '风险等级',
dataIndex: 'riskRank',
render: (text, record, index) => {
const content = text === 0 ? '低风险' : text === 1 ? '中风险' : '高风险';
return content;
}
}, {
title: '状态',
dataIndex: 'stat',
render: (text, record, index) => {
return (
getStat(text)
);
}
}, {
title: '来源',
dataIndex: 'src'
}, {
title: '备注',
dataIndex: 'memo'
}, {
title: '创建时间',
dataIndex: 'gmtCreate',
render: (text, record, index) => {
if (text === null) {
return '';
} else {
return moment(text).format(dateFormat);
}
}
}, {
title: '创建人',
dataIndex: 'creator'
}, {
title: '更新时间',
dataIndex: 'gmtModified',
render: (text, record, index) => {
if (text === null) {
return '';
} else {
return moment(text).format(dateFormat);
}
}
}, {
title: '更新人',
dataIndex: 'mender'
}, {
title: '操作',
key: 'operates',
fixed: 'right',
width: 150,
render: (text, record, index) => (
<div>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record); }}>编辑</a>
</div>
)
}];
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
return (
<div>
<div className={styles.row_warp}>
<Row>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.showModal(false, {})}
>
添加
</Button>
</Col>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={this.downLoadTable}
>
下载
</Button>
</Col>
<Col span={2} offset={16}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.check(0)}
>
启用
</Button>
</Col>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.check(1)}
>
禁用
</Button>
</Col>
</Row>
</div>
<Table
rowKey="id"
rowSelection={rowSelection}
columns={columns}
loading={dataIsLoading}
pagination={paganationOpts}
locale={{ emptyText: '暂无数据' }}
dataSource={_dataSource} />
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default BlackTable;
.row_warp {
margin-bottom: 10px;
}
.link {
color:#1890ff;
}
\ No newline at end of file
import React from 'react';
class NameFilter extends React.Component {
render() {
return (
<div>{ this.props.children }</div>
);
};
};
export default NameFilter;
import React from 'react';
import { observer } from 'mobx-react';
import { withRouter } from 'react-router';
import PageSearch from './search';
import Table from './table';
@observer
class NameFilter extends React.Component {
render() {
return (
<div>
<PageSearch/>
<Table/>
</div>
);
}
};
export default withRouter(NameFilter);
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import {
Form,
Input,
Modal,
Select
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
let TextArea = Input.TextArea;
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const dimension = [
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const stat = [
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
@observer
class Edit extends React.Component {
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { whitelistUpdate, whitelistSave } = store;
const { getFieldValue } = this.props.form;
let params = {
dimension: getFieldValue('dimension'),
stat: getFieldValue('stat'),
src: getFieldValue('src'),
memo: getFieldValue('memo'),
val: getFieldValue('val'),
gmtCreate: this.props.editObj.gmtCreate || '',
creator: this.props.editObj.creator || '',
id: this.props.editObj.id
};
this.props.isEdit ? whitelistUpdate(params) : whitelistSave(params);
this.props.closeModal();
}
});
};
handleCancel = () => {
this.props.closeModal();
};
render() {
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const { getFieldDecorator } = this.props.form;
// 名单维度
let dimensionProps = getFieldDecorator('dimension', {
initialValue: this.props.editObj.dimension || 0
});
let valProps = getFieldDecorator('val', {
initialValue: this.props.editObj.val || '',
rules: [{
required: true, message: '请输入!'
}]
});
// 状态
let statProps = getFieldDecorator('stat', {
initialValue: this.props.editObj.stat || 0
});
// 来源
let srcProps = getFieldDecorator('src', {
initialValue: this.props.editObj.src || ''
});
// 备注
let memoProps = getFieldDecorator('memo', {
initialValue: this.props.editObj.memo || '',
rules: [{
max: 64, message: '最多输入64个字符!'
}]
});
return (
<div>
<Modal
title={ this.props.isEdit ? '修改白名单' : '添加白名单'}
width={400}
visible={true}
onOk={this.handleOk}
maskClosable={false}
onCancel={this.handleCancel}
okText="确认"
cancelText="取消"
>
<Form>
<FormItem
{...formItemLayout}
label="名单维度"
>
{
dimensionProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
disabled={this.props.isEdit}
>
{dimension && dimension.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="名单值"
>
{valProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="来源"
>
{srcProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="状态"
>
{
statProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
>
{stat && stat.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="备注:"
>
{memoProps(
<TextArea rows={3} />
)}
</FormItem>
{this.props.isEdit ? <FormItem
{...formItemLayout}
label="更新人:"
>
<div>{this.props.editObj.mender}</div>
</FormItem> : null }
{this.props.isEdit ? <FormItem
{...formItemLayout}
label="更新时间:"
>
<div>{this.props.editObj.gmtModified ? moment(this.props.editObj.gmtModified).format(dateFormat) : ''}</div>
</FormItem> : null }
</Form>
</Modal>
</div>
);
}
}
const EditModal = Form.create({})(Edit);
export default EditModal;
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import styles from './index.less';
import {
DatePicker,
Form,
Input,
Button,
Select
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
const dimension = [
{ value: '', text: '全部' },
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const stat = [
{ value: '', text: '全部' },
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
this.search();
}
// 查询
search = () => {
const { updateParams, getDataList } = store;
const { getFieldValue } = this.props.form;
let timeRange = getFieldValue('time');
let params = {
'dateRange.from': (timeRange && timeRange[0] && timeRange[0].format(dateFormat)) || '',
'dateRange.to': (timeRange && timeRange[1] && timeRange[1].format(dateFormat)) || '',
dimension: getFieldValue('dimension'),
stat: getFieldValue('stat'),
src: getFieldValue('src') || '',
currentPage: 1
};
updateParams(params);
getDataList();
}
// 重置
reset = () => {
const { resetFields } = this.props.form;
resetFields();
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
// 名单维度
let dimensionProps = getFieldDecorator('dimension', {
initialValue: ''
});
// 状态
let statProps = getFieldDecorator('stat', {
initialValue: 0
});
// 来源
let srcProps = getFieldDecorator('src');
// 日期选择器
let timeProps = getFieldDecorator('time', {
initialValue: this.state.time
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem>
{timeProps(
<RangePicker
format={dateFormat}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="名单维度"
>
{
dimensionProps(
<Select
style={{ width: '140px' }}
placeholder="Tags Mode"
>
{dimension && dimension.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="状态"
>
{
statProps(
<Select
style={{ width: '80px' }}
placeholder="Tags Mode"
>
{stat && stat.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="来源"
>
{srcProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.reset}
>
重置
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
class State {
// loading
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
'dateRange.from': '',
'dateRange.to': '',
dimension: '',
stat: '',
src: '',
currentPage: 1,
pageSize: 6
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
common.fetch('/whitelist/list', this.params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || [];
});
}
// 启用禁用
@action
changeSatus = (params) => {
common.fetch('/whitelist/enordis', params, 'post', {isJson: false})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// 添加黑名单
@action
changeSatus = (params) => {
common.fetch('/whitelist/enordis', params, 'post', {isJson: false})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// 更新数据状态
@action
whitelistSave = (params) => {
common.fetch('/whitelist/save', params, 'post', {isJson: false})
.then(res => {
this.getDataList();
});
}
// 更新
@action
whitelistUpdate = (params) => {
common.fetch('/whitelist/update', params, 'post', {isJson: false})
.then(res => {
this.getDataList();
});
}
// 导出
@action
downLoadTable = (ids) => {
let params = Object.assign({}, ids, this.params);
window.open('/whitelist/export?' + common.concatUrl(params));
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Button, Row, Col, Modal } from 'antd';
import { observer } from 'mobx-react';
import store from '../store';
import EditModal from '../modals/editModal';
import styles from './index.less';
import moment from 'moment';
const dateFormat = 'YYYY-MM-DD HH:mm:ss';
const confirm = Modal.confirm;
const dimension = [
{ value: '', text: '全部' },
{ value: 0, text: 'ip' },
{ value: 1, text: 'device_id' },
{ value: 2, text: 'consumer_id' }
];
const stat = [
{ value: '', text: '全部' },
{ value: 0, text: '启用' },
{ value: 1, text: '禁用' }
];
function getDimension(key) {
let title = '';
dimension.forEach(item => {
if (item.value === key) {
title = item.text;
}
});
return title;
}
function getStat(key) {
let title = '';
stat.forEach(item => {
if (item.value === key) {
title = item.text;
}
});
return title;
}
@observer
class BlackTable extends React.Component {
constructor(props) {
super(props);
this.state = {
// 储存当前选中的行
selectedRows: [],
editObj: [],
isEdit: false,
show: false
};
}
showModal = (isEdit, obj) => {
this.setState({
isEdit: isEdit,
show: true,
editObj: obj
});
}
closeModal = () => {
this.setState({
show: false
});
}
// 二次确认
check(status) {
if (this.state.selectedRows.length === 0) {
confirm({
title: '提示',
content: '请勾选相应白名单数据!',
okText: '确定',
okType: 'danger',
cancelText: '取消'
});
return;
}
let _this = this;
confirm({
title: '提示',
content: '是否启用/禁用该白名单?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
_this.changeSatus(status);
}
});
}
changeSatus = (status) => {
if (this.state.selectedRows.length === 0) {
return;
}
const { changeSatus } = store;
let id = [];
this.state.selectedRows.forEach(item => {
id.push(item.id);
});
let params = {
stat: status,
id: id.join(',')
};
changeSatus(params);
}
// 下载
downLoadTable = () => {
const { downLoadTable } = store;
let id = [];
this.state.selectedRows.forEach(item => {
id.push(item.id);
});
downLoadTable({ids: id});
}
render() {
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const rowSelection = {
onChange: (selectedRowKeys = [], selectedRows = []) => {
this.setState({
selectedRows
});
}
};
const columns = [{
title: '名单维度',
dataIndex: 'dimension',
render: (text, record, index) => {
return (
getDimension(text)
);
}
}, {
title: '名单值',
dataIndex: 'val'
}, {
title: '状态',
dataIndex: 'stat',
render: (text, record, index) => {
return (
getStat(text)
);
}
}, {
title: '来源',
dataIndex: 'src'
}, {
title: '备注',
dataIndex: 'memo'
}, {
title: '创建时间',
dataIndex: 'gmtCreate',
render: (text, record, index) => {
if (text === null) {
return '';
} else {
return moment(text).format(dateFormat);
}
}
}, {
title: '创建人',
dataIndex: 'creator'
}, {
title: '更新时间',
dataIndex: 'gmtModified',
render: (text, record, index) => {
if (text === null) {
return '';
} else {
return moment(text).format(dateFormat);
}
}
}, {
title: '更新人',
dataIndex: 'mender'
}, {
title: '操作',
key: 'operates',
fixed: 'right',
width: 150,
render: (text, record, index) => (
<div>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record); }}>编辑</a>
</div>
)
}];
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
return (
<div>
<div className={styles.row_warp}>
<Row>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.showModal(false, {})}
>
添加
</Button>
</Col>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={this.downLoadTable}
>
下载
</Button>
</Col>
<Col span={2} offset={16}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.check(0)}
>
启用
</Button>
</Col>
<Col span={2}>
<Button
type="primary"
htmlType="submit"
onClick={() => this.check(1)}
>
禁用
</Button>
</Col>
</Row>
</div>
<Table
rowKey="id"
rowSelection={rowSelection}
columns={columns}
loading={dataIsLoading}
pagination={paganationOpts}
locale={{ emptyText: '暂无数据' }}
dataSource={_dataSource} />
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default BlackTable;
.row_warp {
margin-bottom: 10px;
}
.link {
color:#1890ff;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Input, DatePicker } from 'antd';
import UploadImage from 'src/formElements/uploadImage';
import store from '../../store';
import styles from './index.less';
import moment from 'moment';
const dateFormat = 'YYYY-MM-DD';
const FormItem = Form.Item;
let TextArea = Input.TextArea;
@observer
class AddAndEditForm extends React.Component {
// 生成表单元素
createFormItems = (items) => {
const { getFieldDecorator } = this.props.form;
return items.map(item => {
const {
hidden = false,
label = '',
id, option,
item: itemComponent
} = item;
return (
<FormItem
className={ hidden ? styles.hidden : ''}
label={ label }
key={ id }
>
{getFieldDecorator(id, option)(itemComponent)}
</FormItem>
);
});
}
// 生成表格配置参数
createColumns = () => {
const { record, fileArr } = store;
let imgList = [];
let formobj = {};
if (record) {
fileArr.imgs && fileArr.imgs.forEach(item => {
let obj = {};
obj.uid = item.id;
obj.name = item.url;
obj.url = item.url;
obj.status = 'done';
imgList.push(obj);
});
formobj.slotId = record.slotId;
formobj.curDate = moment(record.curDate);
formobj.exampleFeatures = record.exampleFeatures;
formobj.url2Add = record.imgs;
formobj.exampleDemand = record.exampleDemand;
formobj.exampleResult = record.exampleResult;
}
// 处理元素为null的情况
const fileList = record ? imgList : [];
// 表单配置项
const options = [
{
id: 'slotId',
option: {
initialValue: formobj.slotId,
rules: [
{required: true, message: '广告位id不能为空'}
]
},
item: <Input />,
label: '广告位id:'
},
{
id: 'curDate',
option: {
initialValue: formobj.curDate,
rules: [
{required: true, message: '异常时间点不能为空'}
]
},
item: <DatePicker format={dateFormat} />,
label: '异常时间点:'
},
{
id: 'url2Add',
option: {
valuePropName: 'fileList',
getValueFromEvent: (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
},
initialValue: fileList
},
item: <UploadImage uploadButtonText='上传图片'/>,
label: '图片上传:'
},
{
id: 'exampleFeatures',
option: {
initialValue: formobj.exampleFeatures,
rules: [
{required: true, message: '案例特征不能为空', whitespace: true}
]
},
item: <TextArea rows={3} />,
label: '案例特征:'
},
{
id: 'exampleDemand',
option: {
initialValue: formobj.exampleDemand,
rules: [
{required: true, message: '案例需求不能为空'}
]
},
item: <TextArea rows={3} />,
label: '案例需求:'
},
{
id: 'exampleResult',
option: {
initialValue: formobj.exampleResult
},
item: <TextArea rows={3} />,
label: '案例结果:'
}
];
return options;
}
render() {
const options = this.createColumns();
return (
<Form
layout='horizontal'
autoComplete="off"
>
{ this.createFormItems(options) }
</Form>
);
}
}
export default Form.create({})(AddAndEditForm);
.hidden {
display: none;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { withRouter } from 'react-router';
import PageSearch from './search';
import AuditCaseTable from './table';
@observer
class auditcase extends React.Component {
render() {
return (
<div>
<PageSearch/>
<AuditCaseTable/>
</div>
);
}
};
export default withRouter(auditcase);
import React from 'react';
import { observer } from 'mobx-react';
import { transaction } from 'mobx';
import {
Modal,
Button
} from 'antd';
import AddAndEditForm from '../../forms/addAndEditForm';
import store from '../../store';
const titles = ['编辑案例', '添加案例'];
@observer
class AddAndEditModal extends React.Component {
handleOk = () => {
const {
saveStickItem,
showOrHiddenAddAndEditModal,
setContentChanged,
formRef,
record
} = store;
const { form } = formRef.props;
const { validateFields } = form;
validateFields((errors, values) => {
if (errors) {
console.log(errors);
} else {
const { url2Add, ...rest } = values;
let imgChangeArr = [];
url2Add.map(item => {
if (item.response) {
imgChangeArr.push(item.response.data.url);
}
});
let params = {
id: record && record.id ? record.id : '',
exceptionDate: rest.curDate,
exampleDemand: rest.exampleDemand,
exampleFeatures: rest.exampleFeatures,
exampleResult: rest.exampleResult,
slotId: parseInt(rest.slotId)
};
transaction(() => {
// 保存数据,设置内容为已改变并且隐藏弹窗
saveStickItem({
...params,
// 本地开发阶段临时判断是否为空
// imgIds: imgIds.length ? (imgIds[0].url || imgIds[0].response.data.url) : []
url2Add: imgChangeArr
});
setContentChanged(true);
showOrHiddenAddAndEditModal(0);
});
}
});
}
handleCancel = () => {
const { showOrHiddenAddAndEditModal } = store;
// 隐藏弹窗
showOrHiddenAddAndEditModal(0);
}
render() {
const { showAddAndEditModal, record, saveFormRef } = store;
const title = record && record.slotId ? titles[0] : titles[1];
return (
<Modal
visible={showAddAndEditModal}
title={title}
maskClosable={false}
footer={[
<Button key="back" onClick={this.handleCancel}>取消</Button>,
<Button key="submit" type="primary" onClick={this.handleOk}>确定</Button>
]}
onCancel={this.handleCancel}
destroyOnClose={true}
>
<AddAndEditForm wrappedComponentRef={saveFormRef}/>
</Modal>
);
}
}
export default AddAndEditModal;
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../../store';
import moment from 'moment';
import {
Table,
Icon,
Modal,
Button,
DatePicker
} from 'antd';
const dateFormat = 'YYYY-MM-DD';
const { RangePicker } = DatePicker;
// 处理状态枚举
const reviewResultArr = [
{ value: 0, label: '待处理' },
{ value: 1, label: '调分成' },
{ value: 2, label: '下线' },
{ value: 3, label: '暂不处理' },
{ value: 4, label: '暂不处理,加入限流包' },
{ value: 5, label: '调分成,加入限流包' },
{ value: 6, label: '下线,加入限流包' }
];
const cheatGradeArr = [
{ value: '0', label: '0级作弊' },
{ value: '1', label: '1级作弊' },
{ value: '2', label: '2级作弊' },
{ value: '3', label: '3级作弊' },
{ value: '4', label: '4级作弊' },
{ value: '5', label: '5级作弊' },
{ value: '6', label: '6级作弊' }
];
// 获取 作弊等级
function getCheatGradeArr(value) {
let label = '';
cheatGradeArr.forEach((item) => {
if (item.value === value) {
label = item.label;
}
});
return label;
}
// 获取 处理状态
function getReviewResult(value) {
let label = '';
reviewResultArr.forEach((item) => {
if (item.value === value) {
label = item.label;
}
});
return label;
}
const columns = [{
title: '日期',
dataIndex: 'curDate',
key: 'curDate'
}, {
title: '作弊等级',
dataIndex: 'cheatGrade',
key: 'cheatGrade',
render: (text, record, index) => {
return (<div>{getCheatGradeArr(text)}</div>);
}
}, {
title: '初步处理结果',
dataIndex: 'preResult',
key: 'preResult',
render: (text, record, index) => {
return (<div>{getReviewResult(text)}</div>);
}
}, {
title: '初步处理人',
dataIndex: 'preRiskReviewer',
key: 'preRiskReviewer'
}, {
title: '最终处理结果',
dataIndex: 'reviewResult',
key: 'reviewResult',
render: (text, record, index) => {
return (<div>{getReviewResult(text)}</div>);
}
}, {
title: '最终处理人',
dataIndex: 'riskReviewer',
key: 'riskReviewer'
}, {
title: '备注',
dataIndex: 'reviewRemarks',
key: 'reviewRemarks'
}];
@observer
class ReviewResult extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
this.search(1);
};
search = (currentPage) => {
const { getReviewResultModal, updateReviewResultModalObj } = store;
let params = {
slotId: this.props.reviewResultModalObj.record.slotId,
appId: this.props.reviewResultModalObj.record.appId,
startTime: this.state.time[0].format(dateFormat),
endTime: this.state.time[1].format(dateFormat),
currentPage: currentPage,
pageSize: 6
};
updateReviewResultModalObj({currentPage: currentPage});
getReviewResultModal(params);
};
// 时间变了重新拉数据
timeChange = (date, dateString) => {
this.setState({
time: date
}, () => {
this.search(1);
});
}
// 近30天
nearSearch = () => {
this.setState({
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
}, () => {
this.search(1);
});
}
handleCancel = () => {
const { updateReviewResultModalObj } = store;
updateReviewResultModalObj({show: false});
}
downTable = () => {
const { downReviewResultTable } = store;
let params = {
slotId: this.props.reviewResultModalObj.record.slotId,
appId: this.props.reviewResultModalObj.record.appId,
startTime: this.state.time[0].format(dateFormat),
endTime: this.state.time[1].format(dateFormat)
};
downReviewResultTable(params);
}
render() {
const { dataIsLoading, reviewResultModalObj } = store;
let _dataSource = reviewResultModalObj.list.slice();
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.reviewResultModalObj.currentPage,
onChange: page => {
this.search(page);
}
};
return (
<Modal
title="处理进度"
width={1000}
visible={true}
onCancel={this.handleCancel}
footer={<div></div>}
>
<div className={styles.info}>
<p>广告位id:{this.props.reviewResultModalObj.record.slotId}</p>
<p>广告位名称:{this.props.reviewResultModalObj.record.slotName}</p>
</div>
<RangePicker
onChange={this.timeChange}
defaultValue={this.state.time}
format={dateFormat}
/>
<Button
type="primary"
htmlType="submit"
className={styles.near}
onClick={this.nearSearch}
>
近30天
</Button>
<Icon type="download" className={styles.down} onClick={this.downTable}/>
<Table
scroll={{ x: 900 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
loading={dataIsLoading}
pagination={paganationOpts}
/>
</Modal>
);
}
}
export default ReviewResult;
.info {
font-weight: 700;
font-size: 16px;
color: #444;
margin-bottom: 10px;
p:last-child {
margin: 10px 0;
}
}
.near {
margin-left: 10px;
}
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: block;
text-align: left;
cursor: pointer;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import styles from './index.less';
import {
DatePicker,
Form,
Input,
Button
} from 'antd';
const FormItem = Form.Item;
const RangePicker = DatePicker.RangePicker;
const dateFormat = 'YYYY-MM-DD';
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
this.search();
}
// 查询
search = () => {
this.props.form.validateFields((errors, values) => {
if (!!errors) {
return;
}
const { updateParams, getDataList } = store;
let timeRange = values.time || [];
let params = {
startTime: (timeRange[0] && timeRange[0].format(dateFormat)) || '',
endTime: (timeRange[1] && timeRange[1].format(dateFormat)) || '',
slotId: values.slotId || '',
appId: values.appId || '',
currentPage: 1
};
updateParams(params);
getDataList();
});
}
updateTime = (times) => {
const startTime = times[0];
const endTime = times[1];
store.updateParams({startTime, endTime});
}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
let slotIdProps = getFieldDecorator('slotId');
let appIdProps = getFieldDecorator('appId');
// 日期选择器
let timeProps = getFieldDecorator('time', {
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem>
{timeProps(
<RangePicker
className={styles.search}
showTime
format={dateFormat}
placeholder={['Start Time', 'End Time']}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="广告位id"
>
{slotIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="媒体id"
>
{appIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
class State {
@observable
fileArr = [];
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
startTime: '',
endTime: '',
slotId: '',
appId: '',
pageSize: 6,
currentPage: 1
};
@observable
showAddAndEditModal = false;
@observable
record = {};
// 新增编辑表单ref
@observable
formRef = {};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
let params = Object.assign({}, this.params);
params.startTime = params.startTime;
params.endTime = params.endTime;
common.fetch('riskExample/queryPage', params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
// 删除案例
@action
delCase = (id) => {
common.fetch('riskExample/deleExample', {id: id}, 'post', {isJson: true})
.then(res => {
common.handleSuccess('删除成功!');
this.getDataList();
});
}
// 更新添加操作
@action
addOrUpdate = (params) => {
common.fetch('/riskExample/addOrUpdate', params, 'post', {isJson: true})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// 更新图片
@action
updatePhoto= (fileArr = []) => {
this.fileArr = fileArr;
}
// 获得图片
@action
getPhoto = (id) => {
common.fetch(`/riskExample/${id}`, {}, 'get')
.then(res => {
this.fileArr = res.data || [];
});
}
// 保存图片
@action
savePhoto = (params) => {
common.fetch('/riskExample/imgs', params, 'post', {isJson: true})
.then(res => {
if (res.data === false) {
common.handleSuccess('添加成功!');
this.showAddPhotoModalObj({show: false});
} else if (res.code === '0100008') {
common.handleWarn('案例图片最多为四张!');
}
this.getDataList();
});
}
// 删除图片
@action
deletePhoto = (id) => {
const promise = new Promise((resolve, reject) => {
common.fetch(`/riskExample/img/${id}`, {}, 'delete', {isJson: false})
.then(res => {
resolve(res);
common.handleSuccess('删除成功!');
});
});
return promise;
}
// addCaseModal 添加案例弹框
@observable
addCaseModalObj = {
show: false,
record: {}
}
// 更新addCaseModal状态
@action
updateAddCaseModalObj = (arg) => {
this.addCaseModalObj = Object.assign({}, this.addCaseModalObj, arg);
}
// 保持addCaseModal状态
@action
addCase = (params) => {
this.addCaseModalObj.show = false;
common.fetch('riskExample/addOrUpdate', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// addPhotoModal 添加案例弹框
@observable
addPhotoModalObj = {
show: false,
record: {},
title: ''
}
// 判断是否有未保存的内容
@observable
hasContentChanged = false;
// 修改内容修改状态
@action
setContentChanged = (status) => {
this.hasContentChanged = status;
}
// 更新addPhotoModal状态
@action
showAddPhotoModalObj = (arg) => {
this.addPhotoModalObj = Object.assign({}, this.addPhotoModalObj, arg);
}
// 保存添加编辑弹窗form数据
@action
saveStickItem = (data) => {
common.fetch('riskExample/addOrUpdate', data, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 保持addPhotoModal状态
@action
getaddPhotoModal = (params) => {
this.addPhotoModalObj.show = false;
common.fetch('riskExample/addOrUpdate', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 处理结果弹框
@observable
reviewResultModalObj = {
show: false,
record: {},
list: [],
totalCount: 0,
currentPage: 1
}
// 更新reviewResultModal状态
@action
updateReviewResultModalObj = (arg) => {
this.reviewResultModalObj = Object.assign({}, this.reviewResultModalObj, arg);
}
// 保持reviewResultModal状态
@action
getReviewResultModal = (params) => {
common.fetch('/riskReview/handleRecord', params, 'get')
.then(res => {
this.reviewResultModalObj.list = res.data.list;
this.reviewResultModalObj.totalCount = res.data.totalCount;
});
}
// 弹框导出
@action
downReviewResultTable = (params) => {
window.open('/riskReview/exportHandleRecords?' + common.concatUrl(params));
}
// 导出
@action
downLoadTable = () => {
window.open('/riskExample/exportExampleData?' + common.concatUrl(this.params));
}
@action
showOrHiddenAddAndEditModal = (type = 1, record) => {
this.showAddAndEditModal = type === 1;
this.record = record;
}
// 保存新增编辑表单ref
@action
saveFormRef = (formRef) => {
this.formRef = formRef;
}
}
const store = new State();
export default store;
import React from 'react';
import {Upload, Modal} from 'antd';
export default function change(key, params, record) {
return function(Wapper) {
class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
previewVisible: false,
previewImage: props.value,
imgs: record.imgs
};
}
// 处理预览框取消事件
handleCancel = () => this.setState({ previewVisible: false })
// 处理预览按钮点击事件
handlePreview = (file) => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true
});
}
render() {
const { previewVisible, previewImage } = this.state;
let imgList = this.state.imgs && this.state.imgs.length && this.state.imgs.slice();
let fileList = [];
imgList && imgList.length && imgList.forEach(item => {
let obj = {};
obj.uid = item;
obj.name = item;
obj.url = item;
obj.status = 'done';
fileList.push(obj);
});
return (
<div className="clearfix">
<Upload
className="uploadStyle"
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
showUploadList={{showRemoveIcon: false}}
>
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel} className="modalStyle">
<img alt="图片" className="width_100_percent" src={previewImage} />
</Modal>
</div>
);
}
}
return <NewComponent/>;
};
}
import React from 'react';
import { Table, Select, Button, Modal, Icon } from 'antd';
import fixNum from 'src/lib/dataFormate';
import { observer } from 'mobx-react';
import tableHoc from './tableHoc';
import textAreahoc from './textAreahoc';
import imgView from './imgView';
import store from '../store';
import AddAndEditModal from '../modals/addAndEditModals';
import ReviewResultModal from '../modals/reviewResult';
import styles from './index.less';
const Option = Select.Option;
const confirm = Modal.confirm;
// 状态枚举
const statusArr = [{
value: 0,
text: '待研究'
}, {
value: 1,
text: '研究完成'
}];
function formatNum(type, num) {
if (isNaN(parseInt(num))) {
return '-';
}
// null
if (type === null) {
return '-';
}
// 浮点数
if (type === 'float') {
return fixNum(num, 2);
}
// 整数
if (type === 'int') {
return fixNum(num, 0);
}
// 百分比
if (type === '%') {
return parseFloat((num * 100).toPrecision(12)) + '%';
}
// app-ad-consume 除以100
if (type === '100') {
let nums = num / 100;
return fixNum(nums, 2);
}
return num;
}
@observer
class AuditCaseTable extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
pageChange = (page, pageSize) => {
const { updateParams, getDataList } = store;
updateParams({
currentPage: page
});
getDataList();
}
// 新增按钮点击事件
handleAddBtn = () => {
const { showOrHiddenAddAndEditModal } = store;
showOrHiddenAddAndEditModal(1);
}
// 编辑按钮点击事件
handleEditBtn = (record) => {
const { showOrHiddenAddAndEditModal, getPhoto } = store;
showOrHiddenAddAndEditModal(1, record);
let params = {
id: record.exampleId
};
getPhoto(params.id);
}
delCase = (id) => {
const { delCase } = store;
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
delCase(id);
},
onCancel() {
console.log('you chose close!');
}
});
}
render() {
const { dataIsLoading, dataList, addCaseModalObj, reviewResultModalObj } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const columns = [{
title: '添加时间',
dataIndex: 'gmtCreate',
key: 'gmtCreate',
fixed: 'left',
width: 120
}, {
title: '问题时间点',
dataIndex: 'curDate',
key: 'curDate',
fixed: 'left',
width: 120
}, {
title: '广告位id',
dataIndex: 'slotId',
key: 'slotId',
fixed: 'left',
width: 150,
render: (text, record, index) => {
let href = '';
if (record.dHour === '1') href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/119/${record.slotId}/${record.curDate}`;
if (record.dHour !== '' && record.dHour !== '1') href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/330/${record.slotId}/${record.curDate}`;
return (
<a target="_blank" href={href}>
<p>{ record.slotId }</p>
<p>{ record.slotName }</p>
</a>
);
}
}, {
title: '媒体id',
dataIndex: 'appId',
key: 'appId',
fixed: 'left',
width: 100,
render: (text, record, index) => {
return (
<div>
<p>{ record.appId }</p>
<p>{ record.appName }</p>
</div>
);
}
}, {
title: '运营',
dataIndex: 'mediaName',
key: 'mediaName',
render: (text, record, index) => {
return (
<div>
<p> 媒体运营:{ record.mediaName }</p>
<p> 媒介运营:{ record.agentName }</p>
</div>
);
}
}, {
title: '处理状态',
dataIndex: 'exampleStatus',
key: 'exampleStatus',
render: (text, record, index) => {
return (
tableHoc('exampleStatus', {exampleStatus: record.exampleStatus, id: record.id})(
<Select
placeholder="处理状态"
defaultValue={text}
>
{statusArr && statusArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
);
}
}, {
title: '综合信用分',
dataIndex: 'creditsScore',
key: 'creditsScore',
render: (text, record, index) => {
return text || '-';
}
}, {
title: '处理人',
dataIndex: 'preRiskReviewer',
key: 'preRiskReviewer',
render: (text, record, index) => {
return record.preRiskReviewer || record.riskReviewer;
}
}, {
title: '作弊消耗',
dataIndex: 'cheatFee',
key: 'cheatFee',
render: (text, record, index) => {
return formatNum('100', text);
}
}, {
title: '作弊消耗占比',
dataIndex: 'cheatFeeRate',
key: 'cheatFeeRate',
render: (text, record, index) => {
return formatNum('%', text);
}
}, {
title: '广告位消耗',
dataIndex: 'adConsume',
key: 'adConsume',
render: (text, record, index) => {
return formatNum('100', text);
}
}, {
title: '分成比例',
dataIndex: 'divideRate',
key: 'divideRate',
render: (text, record, index) => {
return formatNum('%', text);
}
}, {
title: '命中规则',
dataIndex: 'rules',
key: 'rules',
render: (text, record, index) => {
let href = '';
if (record.dHour === '1') href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/118/${record.slotId}/${record.curDate}`;
if (record.dHour !== '' && record.dHour !== '1') href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/329/${record.slotId}/${record.curDate}`;
return <a target="_blank" href={href}>{text}</a>;
}
}, {
title: '累计处理次数',
dataIndex: 'reviewCount',
key: 'reviewCount',
render: (text, record, index) => {
const { updateReviewResultModalObj } = store;
const showReviewResultModal = () => {
updateReviewResultModalObj({record: record, show: true});
};
return <a onClick={showReviewResultModal}>{text}</a>;
}
}, {
title: '案例特征',
dataIndex: 'exampleFeatures',
key: 'exampleFeatures',
width: 200,
render: (text, record, index) => {
return textAreahoc('exampleFeatures', { exampleFeatures: record.exampleFeatures, id: record.id }, Object.assign({}, record, {tableTitle: '案例特征'}))(
<span className={styles.limit}>{text}</span>
);
}
}, {
title: '案例需求',
dataIndex: 'exampleDemand',
key: 'exampleDemand',
width: 200,
render: (text, record, index) => {
return textAreahoc('exampleDemand', { exampleDemand: record.exampleDemand, id: record.id }, Object.assign({}, record, {tableTitle: '案例需求'}))(
<span className={styles.limit}>{text}</span>
);
}
}, {
title: '案例结果',
dataIndex: 'exampleResult',
key: 'exampleResult',
width: 200,
render: (text, record, index) => {
return textAreahoc('exampleResult', { exampleResult: record.exampleResult, id: record.id }, Object.assign({}, record, {tableTitle: '案例结果'}))(
<span className={styles.limit}>{text}</span>
);
}
}, {
title: '图片附件',
key: 'imgs',
render: (text, record, index) => {
return imgView('imgs', { imgs: record.imgs, id: record.id }, Object.assign({}, record, {tableTitle: '图片附件'}))(
<div>{text}</div>
);
}
}, {
title: '操作',
key: 'operates',
render: (text, record, index) => (
<div>
<a className={styles.link} onClick= {() => this.handleEditBtn(record)}>编辑</a>
<a className={styles.link} onClick= {() => this.delCase(record.id)}>删除</a>
</div>
)
}
];
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
const { downLoadTable } = store;
return (
<div>
<Button type="primary" htmlType="submit" onClick={this.handleAddBtn} >添加</Button>
<Icon type="download" className={styles.down} onClick={downLoadTable}/>
<Table
className="tableStyle"
scroll={{ x: 2900 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
<AddAndEditModal addCaseModalObj={addCaseModalObj}/>
{reviewResultModalObj.show ? <ReviewResultModal reviewResultModalObj={reviewResultModalObj}/> : null }
</div>
);
}
}
export default AuditCaseTable;
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: block;
width: 30px;
text-align: left;
cursor: pointer;
width: 20px;
}
.link {
color:#1890ff;
margin:0px 3px
}
.limit{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
:global{
.tableStyle{
.ant-table-thead > tr > th, .ant-table-tbody > tr > td{
padding: 10px 10px
}
}
}
import React from 'react';
import store from '../store';
import { Modal } from 'antd';
const confirm = Modal.confirm;
export default function change(key, params, record) {
return function(Wapper) {
const { addOrUpdate, getDataList } = store;
class NewComponent extends React.Component {
onChange = (value) => {
params[key] = value;
this.showConfirm(params);
}
// 二次确认框
showConfirm = (params) => {
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
addOrUpdate(params);
},
onCancel() {
getDataList();
}
});
}
render() {
return (
React.cloneElement(
Wapper,
{
onChange: this.onChange
}
)
);
}
}
return <NewComponent/>;
};
}
import React from 'react';
import {Popover} from 'antd';
import styles from './textAreahoc.less';
export default function change(key, params, record) {
return function(Wapper) {
class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: record[key]
};
}
render() {
const content = (
<div className={styles.popover}>
<p>{this.state.value}</p>
</div>
);
let CopyWapper = React.cloneElement(
Wapper,
{
value: this.state.value
}
);
return (
<Popover title={record.tableTitle} placement = "top" content={content}>
{CopyWapper}
</Popover>
);
}
}
return <NewComponent/>;
};
}
.popover{
width: 200px;
word-break:normal;
white-space:pre-warp;
word-wrap:break-word;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { withRouter } from 'react-router';
import PageSearch from './search';
import RiskTable from './table';
@observer
class Auditsys extends React.Component {
render() {
return (
<div>
<PageSearch/>
<RiskTable/>
</div>
);
}
};
export default withRouter(Auditsys);
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../../store';
import UploadImage from 'src/formElements/uploadImage';
import {
Form,
Input,
Modal
} from 'antd';
const FormItem = Form.Item;
let TextArea = Input.TextArea;
@observer
class AddCase extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { addCase } = store;
const { getFieldValue } = this.props.form;
let imgChangeArr = [];
getFieldValue('imgIds') && getFieldValue('imgIds').map(item => {
if (item.response) {
imgChangeArr.push(item.response.data.url);
}
});
let params = {
exampleDemand: getFieldValue('exampleDemand'),
url2Add: imgChangeArr,
exampleFeatures: getFieldValue('exampleFeatures'),
slotId: this.props.addCaseModalObj.record.slotId,
slotName: this.props.addCaseModalObj.record.slotName,
date: this.props.addCaseModalObj.record.curDate,
riskAllId: this.props.addCaseModalObj.record.id,
// 后端应不去读id
id: this.props.addCaseModalObj.record.riskReviewId
};
addCase(params);
}
});
};
handleCancel = () => {
const { updateAddCaseModalObj } = store;
updateAddCaseModalObj({show: false});
};
render() {
const { getFieldDecorator } = this.props.form;
// 案例特征
let exampleFeaturesProps = getFieldDecorator('exampleFeatures', {
rules: [{
required: true, message: '请输入!'
}]
});
// 图片上传
let imgIdsProps = getFieldDecorator('imgIds', {
valuePropName: 'fileList',
getValueFromEvent: (e) => {
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
}
// rules: [
// { type: 'array', required: true, message: '缩略图不能为空' }
// ]
});
// 案例需求
let exampleDemandProps = getFieldDecorator('exampleDemand', {
rules: [{
required: true, message: '请输入!'
}]
});
return (
<div>
<Modal
title="添加案例"
width={400}
visible={this.props.addCaseModalObj.show}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="确认"
cancelText="取消"
>
<div className={styles.info}>
<p>广告位id:{this.props.addCaseModalObj.record.slotId}</p>
<p>广告位名称:{this.props.addCaseModalObj.record.slotName}</p>
<p>日期:{this.props.addCaseModalObj.record.curDate}</p>
</div>
<Form>
<FormItem
label="案例特征:"
>
{exampleFeaturesProps(
<TextArea rows={3} />
)}
</FormItem>
<FormItem
label="图片上传:"
>
{imgIdsProps(
<UploadImage uploadButtonText='上传图片' onChange={this.handleChange} />
)}
</FormItem>
<FormItem
label="案例需求:"
>
{exampleDemandProps(
<TextArea rows={3} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const AddCaseModal = Form.create({})(AddCase);
export default AddCaseModal;
.info {
font-weight: 700;
font-size: 16px;
color: #444;
p {
padding: 4px 6px;
}
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../../store';
import {
Modal
} from 'antd';
// 处理状态枚举
const reviewResultArr = [
{ value: 0, text: '待处理' },
{ value: 1, text: '调分成' },
{ value: 2, text: '下线' },
{ value: 3, text: '暂不处理' },
{ value: 4, text: '暂不处理,加入限流包' },
{ value: 5, text: '调分成,加入限流包' },
{ value: 6, text: '下线,加入限流包' },
{ value: null, text: '全部' }
];
@observer
class Progress extends React.Component {
componentDidMount() {
}
handleOk = () => {
};
handleCancel = () => {
const { updateProcessModalObj } = store;
updateProcessModalObj({show: false});
}
getReviewResult = (value) => {
let label = '';
reviewResultArr.forEach((item) => {
if (item.value === value) {
label = item.text;
}
});
return label;
}
render() {
return (
<Modal
title="处理进度"
width={400}
visible={this.props.processModalObj.show}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="确认"
cancelText="取消"
footer={<div></div>}
>
<div className={styles.info}>
<p>广告位id:{this.props.processModalObj.record.slotId}</p>
<p>广告位名称:{this.props.processModalObj.record.slotName}</p>
<p>日期:{this.props.processModalObj.record.curDate}</p>
</div>
{this.props.processModalObj && this.props.processModalObj.list.map((item, index) => {
return (
<div className={styles.item_log} key={index}>
<div className={styles.title}>{item.reviewAction}</div>
<div className={styles.list_info}>
{item.reviewTime ? <p className={styles.item_info}>时间:{item.reviewTime}</p> : null}
{item.reviewAction === '初步处理结果' || item.reviewAction === '最终处理结果' ? <p className={styles.item_info}>处理人:{item.riskReviewer}</p> : item.reviewAction === '通知媒体运营' || item.reviewAction === '媒体运营反馈' ? <p className={styles.item_info}>媒体运营:{item.riskReviewer}</p> : null}
{item.reviewResult ? <p className={styles.item_info}>处理结果:{this.getReviewResult(item.reviewResult)}</p> : null}
{item.reviewAction === '通知媒体运营' ? <p className={styles.item_info}>建议分成比例:{(item.rate / 100).toFixed(2) + '%'}</p> : item.reviewAction === '媒体运营反馈' ? <p className={styles.item_info}>最终分成比例:{(item.rate / 100).toFixed(2) + '%'}</p> : null}
{item.mediaMemo ? <p className={styles.item_info}>备注:{item.mediaMemo}</p> : null}
</div>
</div>
);
})}
</Modal>
);
}
}
export default Progress;
.info {
font-weight: 700;
font-size: 16px;
color: #444;
}
.item_log {
padding-top: 40px;
.title {
display: inline-block;
width: 100px;
height: 80px;
text-align: center;
line-height: 80px;
background-color: #F6B4A0;
vertical-align: middle;
}
.list_info {
display: inline-block;
vertical-align: middle;
padding-left: 10px;
}
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../../store';
import moment from 'moment';
import {
Table,
Icon,
Modal,
Button,
DatePicker
} from 'antd';
const dateFormat = 'YYYY-MM-DD';
const { RangePicker } = DatePicker;
// 处理状态枚举
const reviewResultArr = [
{ value: 0, label: '待处理' },
{ value: 1, label: '调分成' },
{ value: 2, label: '下线' },
{ value: 3, label: '暂不处理' },
{ value: 4, label: '暂不处理,加入限流包' },
{ value: 5, label: '调分成,加入限流包' },
{ value: 6, label: '下线,加入限流包' }
];
const cheatGradeArr = [
{ value: '0', label: '0级作弊' },
{ value: '1', label: '1级作弊' },
{ value: '2', label: '2级作弊' },
{ value: '3', label: '3级作弊' },
{ value: '4', label: '4级作弊' },
{ value: '5', label: '5级作弊' },
{ value: '6', label: '6级作弊' }
];
// 获取 作弊等级
function getCheatGradeArr(value) {
let label = '';
cheatGradeArr.forEach((item) => {
if (item.value === value) {
label = item.label;
}
});
return label;
}
// 获取 处理状态
function getReviewResult(value) {
let label = '';
reviewResultArr.forEach((item) => {
if (item.value === value) {
label = item.label;
}
});
return label;
}
const columns = [{
title: '日期',
dataIndex: 'curDate',
key: 'curDate'
}, {
title: '作弊等级',
dataIndex: 'cheatGrade',
key: 'cheatGrade',
render: (text, record, index) => {
return (<div>{getCheatGradeArr(text)}</div>);
}
}, {
title: '初步处理结果',
dataIndex: 'preResult',
key: 'preResult',
render: (text, record, index) => {
return (<div>{getReviewResult(text)}</div>);
}
}, {
title: '初步处理人',
dataIndex: 'preRiskReviewer',
key: 'preRiskReviewer'
}, {
title: '最终处理结果',
dataIndex: 'reviewResult',
key: 'reviewResult',
render: (text, record, index) => {
return (<div>{getReviewResult(text)}</div>);
}
}, {
title: '最终处理人',
dataIndex: 'riskReviewer',
key: 'riskReviewer'
}, {
title: '备注',
dataIndex: 'reviewRemarks',
key: 'reviewRemarks'
}];
@observer
class ReviewResult extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
this.search(1);
};
search = (currentPage) => {
const { getReviewResultModal, updateReviewResultModalObj } = store;
let params = {
slotId: this.props.reviewResultModalObj.record.slotId,
appId: this.props.reviewResultModalObj.record.appId,
startTime: this.state.time[0].format(dateFormat),
endTime: this.state.time[1].format(dateFormat),
currentPage: currentPage,
pageSize: 6
};
updateReviewResultModalObj({currentPage: currentPage});
getReviewResultModal(params);
};
// 时间变了重新拉数据
timeChange = (date, dateString) => {
this.setState({
time: date
}, () => {
this.search(1);
});
}
// 近30天
nearSearch = () => {
this.setState({
time: [moment().subtract(30, 'days'), moment().subtract(0, 'days')]
}, () => {
this.search(1);
});
}
handleCancel = () => {
const { updateReviewResultModalObj } = store;
updateReviewResultModalObj({show: false});
}
downTable = () => {
const { downReviewResultTable } = store;
let params = {
slotId: this.props.reviewResultModalObj.record.slotId,
appId: this.props.reviewResultModalObj.record.appId,
startTime: this.state.time[0].format(dateFormat),
endTime: this.state.time[1].format(dateFormat)
};
downReviewResultTable(params);
}
render() {
const { dataIsLoading, reviewResultModalObj } = store;
let _dataSource = reviewResultModalObj.list.slice();
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.reviewResultModalObj.currentPage,
onChange: page => {
this.search(page);
}
};
return (
<Modal
title="处理记录"
width={1000}
visible={true}
onCancel={this.handleCancel}
footer={<div></div>}
>
<div className={styles.info}>
<p>广告位id:{this.props.reviewResultModalObj.record.slotId}</p>
<p>广告位名称:{this.props.reviewResultModalObj.record.slotName}</p>
</div>
<RangePicker
onChange={this.timeChange}
defaultValue={this.state.time}
format={dateFormat}
/>
<Button
type="primary"
htmlType="submit"
className={styles.near}
onClick={this.nearSearch}
>
近30天
</Button>
<Icon type="download" className={styles.down} onClick={this.downTable}/>
<Table
scroll={{ x: 900 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
loading={dataIsLoading}
pagination={paganationOpts}
/>
</Modal>
);
}
}
export default ReviewResult;
.info {
font-weight: 700;
font-size: 16px;
color: #444;
margin-bottom: 10px;
p:last-child {
margin: 10px 0;
}
}
.near {
margin-left: 10px;
}
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: block;
width: 40px;
text-align: left;
cursor: pointer;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import Type from '../type/index';
import styles from './index.less';
import {
DatePicker,
Form,
Input,
Select,
Radio,
Button
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
const RadioGroup = Radio.Group;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
// 风险等级枚举
const cheatGradeArr = [
{ value: '', text: '全部' },
{ value: '0', text: '0级作弊' },
{ value: '1', text: '1级作弊' },
{ value: '2', text: '2级作弊' },
{ value: '3', text: '3级作弊' },
{ value: '4', text: '4级作弊' },
{ value: '5', text: '5级作弊' },
{ value: '6', text: '6级作弊' }
];
// 处理状态枚举 全部改为-1
const reviewResultArr = [
{ value: null, text: '待处理' },
{ value: 1, text: '调分成' },
{ value: 2, text: '下线' },
{ value: 3, text: '暂不处理' },
// { value: 4, text: '暂不处理,加入限流包' },
// { value: 5, text: '调分成,加入限流包' },
// { value: 6, text: '下线,加入限流包' },
{ value: -1, text: '全部' }
];
// 意见枚举 全部改为-1
const mediaDealOpinionArr = [
{ value: 1, text: '同意' },
{ value: 0, text: '不同意' },
{ value: -1, text: '全部' }
];
// 处理时间枚举 全部改为-1
const dealDateArr = [
{ value: 1, text: '上午11:30' },
{ value: 2, text: '下午14:00' },
{ value: -1, text: '全部' }
];
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(1, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
const { getRiskReviewer } = store;
getRiskReviewer();
this.search();
}
// 设置查询作弊等级
chageCheatGrade = (type) => {
const { setFieldsValue } = this.props.form;
setFieldsValue({
cheatGrade: type
});
this.search();
}
// 查询
search = () => {
const { updateParams, getDataList, getcheatGrade, getFinalDealMoney } = store;
const { getFieldValue } = this.props.form;
let timeRange = getFieldValue('time');
let params = {
startTime: timeRange[0].format(dateFormat),
endTime: timeRange[1].format(dateFormat),
slotId: getFieldValue('slotId') || '',
appId: getFieldValue('appId') || '',
riskReviewer: getFieldValue('riskReviewer'),
cheatGrade: getFieldValue('cheatGrade'),
// reviewResult: getFieldValue('reviewResult') || '',
preResult: getFieldValue('preResult') || '',
mediaDealOpinion: getFieldValue('mediaDealOpinion'),
dealDate: getFieldValue('dealDate') || '',
currentPage: 1
};
updateParams(params);
getDataList();
// 获取各作弊条数
getcheatGrade();
getFinalDealMoney();
}
// radio框 类型切换
typeSearch = (e) => {
const { updateParams } = store;
updateParams({type: e.target.value});
this.search();
}
render() {
const { getFieldDecorator } = this.props.form;
const { riskReviewer } = store;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
let slotIdProps = getFieldDecorator('slotId');
let appIdProps = getFieldDecorator('appId');
// 日期选择器
let timeProps = getFieldDecorator('time', {
initialValue: this.state.time
});
// 处理人
let riskReviewerProps = getFieldDecorator('riskReviewer', {
initialValue: ''
});
// 作弊等级
let cheatGradeProps = getFieldDecorator('cheatGrade', {
initialValue: ''
});
// 初步处理结果
let preResultProps = getFieldDecorator('preResult', {
initialValue: -1
});
// 媒体意见
let mediaDealOpinionProps = getFieldDecorator('mediaDealOpinion', {
initialValue: -1
});
// 媒体意见
let dealDateProps = getFieldDecorator('dealDate', {
initialValue: -1
});
// 最终处理结果
// let reviewResultProps = getFieldDecorator('reviewResult', {
// initialValue: -1
// });
// 实时 离线 全部
let typeProps = getFieldDecorator('type', {
initialValue: 3
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem>
{timeProps(
<RangePicker
format={dateFormat}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="广告位id"
>
{slotIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="媒体id"
>
{appIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="处理人"
>
{riskReviewerProps(
<Select
style={{ width: '100px' }}
placeholder="Tags Mode"
>
{riskReviewer && riskReviewer.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="作弊等级"
>
{cheatGradeProps(
<Select
style={{ width: '120px' }}
placeholder="Tags Mode"
>
{cheatGradeArr && cheatGradeArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="初步处理结果"
>
{preResultProps(
<Select
style={{ width: '180px' }}
placeholder="Tags Mode"
>
{reviewResultArr && reviewResultArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="媒体处理意见"
>
{mediaDealOpinionProps(
<Select
style={{ width: '180px' }}
placeholder="Tags Mode"
>
{mediaDealOpinionArr && mediaDealOpinionArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="处理时间"
>
{dealDateProps(
<Select
style={{ width: '120px' }}
placeholder="Tags Mode"
>
{dealDateArr && dealDateArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
{/* <FormItem
{...formItemLayout}
label="最终处理结果"
>
{reviewResultProps(
<Select
style={{ width: '180px' }}
placeholder="Tags Mode"
>
{reviewResultArr && reviewResultArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem> */}
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
<br/>
<FormItem>
{typeProps(
<RadioGroup onChange={this.typeSearch}>
<Radio value={1}>只看实时</Radio>
<Radio value={2}>只看离线</Radio>
<Radio value={3}>查看全部</Radio>
</RadioGroup>
)}
</FormItem>
</Form>
<Type chageCheatGrade={this.chageCheatGrade}/>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
import moment from 'moment';
class State {
// loading
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
time: [moment().subtract(1, 'days'), moment().subtract(0, 'days')],
startTime: '',
endTime: '',
slotId: '',
appId: '',
riskReviewer: '',
cheatGrade: '',
// reviewResult: '',
preResult: '',
type: '3',
pageSize: 6,
currentPage: 1
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// 处理人search用
@observable
riskReviewer = []
// 处理人table用
@observable
_riskReviewer = []
// 请求处理人
@action
getRiskReviewer = () => {
// 获取处理人
common.fetch('/riskReview/findAdminsReview').then(res => {
this.dataSource = (res.data && res.data.stickContentVoList) || [];
let riskReviewer = [{value: '', text: '全部'}];
let _riskReviewer = [{value: null, text: '待定'}];
res.data.forEach((item) => {
riskReviewer.push({
value: item.name,
text: item.name
});
_riskReviewer.push({
value: item.name,
text: item.name
});
});
this.riskReviewer = riskReviewer;
this._riskReviewer = _riskReviewer;
});
}
// cheatGrade作弊等级条数
@observable
cheatGrade = {};
// getcheatGrade 获取作弊等级条数
@action
getcheatGrade = () => {
common.fetch('/riskReview/queryCountShow', this.params, 'get')
.then(res => {
this.dataIsLoading = false;
this.cheatGrade = res.data || {};
});
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
common.fetch('/riskReview/queryPage', this.params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
@observable
configValue = '0'
// 查询是否批量调分成
@action
getConfigValue = () => {
let params = {
configKey: 'batch.partition.switch'
};
common.fetch('/systemConfig/getConfigValue', params, 'get')
.then(res => {
this.configValue = res.data || '';
});
}
// 确认是否批量调分成
@action
getUpdateOrInsert = (params) => {
common.fetch('/systemConfig/updateOrInsert', params, 'post', {isJson: true})
.then(res => {
this.getConfigValue();
});
}
// 查询最终处理金额
@observable
finalDealMoney = 0.00
@action
getFinalDealMoney = () => {
common.fetch('/riskReview/getFinalDealMoney', this.params, 'get')
.then(res => {
this.finalDealMoney = res.data || '';
});
}
// 更新添加操作.
@action
addOrUpdate = (params) => {
common.fetch('/riskReview/addOrUpdate', params, 'post', {isJson: true})
.then(res => {
common.handleSuccess('修改成功!');
this.getDataList();
});
}
// addCaseModal 添加案例弹框
@observable
addCaseModalObj = {
show: false,
record: {}
}
// 更新addCaseModal状态
@action
updateAddCaseModalObj = (arg) => {
this.addCaseModalObj = Object.assign({}, this.addCaseModalObj, arg);
}
// 保持addCaseModal状态
@action
addCase = (params) => {
this.addCaseModalObj.show = false;
let id = params.id;
params.id = null;
common.fetch('/riskExample/addOrUpdate', params, 'post', {isJson: true})
.then(res => {
this.addOrUpdate({
id: id,
isInExample: 1,
riskAllId: params.riskAllId
});
});
}
// processModal 添加案例弹框
@observable
processModalObj = {
show: false,
record: {},
list: []
}
// 更新processModal状态
@action
updateProcessModalObj = (arg) => {
this.processModalObj = Object.assign({}, this.processModalObj, arg);
}
// 保持processModalObj状态
@action
getProcessModal = (params) => {
common.fetch('/riskReview/queryReviewHisList', params, 'get')
.then(res => {
this.processModalObj.list = res.data;
this.processModalObj.show = true;
});
}
// 处理结果弹框
@observable
reviewResultModalObj = {
show: false,
record: {},
list: [],
totalCount: 0,
currentPage: 1
}
// 更新reviewResultModal状态
@action
updateReviewResultModalObj = (arg) => {
this.reviewResultModalObj = Object.assign({}, this.reviewResultModalObj, arg);
}
// 保持reviewResultModal状态
@action
getReviewResultModal = (params) => {
common.fetch('/riskReview/handleRecord', params, 'get')
.then(res => {
this.reviewResultModalObj.list = res.data.list;
this.reviewResultModalObj.totalCount = res.data.totalCount;
});
}
// downReviewResultTable
// 导出
@action
downReviewResultTable = (params) => {
window.open('/riskReview/exportHandleRecords?' + common.concatUrl(params));
}
// 导出 风控
@action
downReviewDataTable = () => {
window.open('riskReview/exportReviewData?' + common.concatUrl(this.params));
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Select, Switch, Input, Icon, Button, Modal } from 'antd';
import fixNum from 'src/lib/dataFormate';
import { observer } from 'mobx-react';
import tableHoc from './tableHoc';
import textAreahoc from './textAreahoc';
import AddCaseModal from '../modals/addCase';
import ProgressModal from '../modals/progress';
import ReviewResultModal from '../modals/reviewResult';
import store from '../store';
import styles from './index.less';
const Option = Select.Option;
const TextArea = Input.TextArea;
const confirm = Modal.confirm;
// table处理状态枚举
const reviewResultArrItem = [
{ value: null, text: '待处理' },
{ value: 1, text: '调分成' },
{ value: 2, text: '下线' },
{ value: 3, text: '暂不处理' }
// { value: 4, text: '暂不处理,加入限流包' },
// { value: 5, text: '调分成,加入限流包' },
// { value: 6, text: '下线,加入限流包' }
];
function formatNum(type, num) {
if (isNaN(parseInt(num))) {
return '-';
}
// null
if (type === null) {
return '-';
}
// 浮点数
if (type === 'float') {
return fixNum(num, 2);
}
// 整数
if (type === 'int') {
return fixNum(num, 0);
}
// 百分比
if (type === '%') {
return parseFloat((num * 100).toPrecision(12)) + '%';
}
// app-ad-consume 除以100
if (type === '100') {
let nums = num / 100;
return fixNum(nums, 2);
}
return num;
}
const columns = [{
title: '时间',
dataIndex: 'curDate',
key: 'curDate',
fixed: 'left',
width: 120
}, {
title: '异常时间点',
dataIndex: 'dHour',
key: 'dHour',
fixed: 'left',
width: 100,
render: (text, record, index) => { return text === '1' ? '1天' : text + '点'; }
}, {
title: '广告位id *',
dataIndex: 'slotId',
key: 'slotId',
fixed: 'left',
width: 150,
render: (text, record, index) => {
const isOffline = record.dHour === '1';
let href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/119/${record.slotId}/${record.curDate}`;
if (!isOffline) href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/330/${record.slotId}/${record.curDate}`;
return (
<a target="_blank" href={href}>
<p>{ record.slotId }</p>
<p>{ record.slotName }</p>
</a>
);
}
}, {
title: '媒体id',
dataIndex: 'appId',
fixed: 'left',
width: 100,
render: (text, record, index) => {
return (
<div>
<p>{ record.appId }</p>
<p>{ record.appName }</p>
</div>
);
}
}, {
title: '运营',
dataIndex: 'mediaName',
key: 'mediaName',
render: (text, record, index) => {
return (
<div>
<p> 媒体运营:{ record.mediaName }</p>
<p> 媒介运营:{ record.agentName }</p>
</div>
);
}
}, {
title: '综合信用分',
dataIndex: 'creditsScore',
key: 'creditsScore',
render: (text, record, index) => {
return text || '-';
}
},
// {
// title: '处理人',
// dataIndex: 'preRiskReviewer',
// key: 'preRiskReviewer',
// render: (text, record, index) => {
// const { _riskReviewer } = store;
// return (
// tableHoc('preRiskReviewer', {preRiskReviewer: record.preRiskReviewer, riskAllId: record.id, id: record.riskReviewId})(
// <Select
// style={{ width: '100%' }}
// placeholder="处理人"
// defaultValue={text}
// >
// {_riskReviewer && _riskReviewer.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
// </Select>
// )
// );
// }
// },
{
title: '作弊消耗',
dataIndex: 'cheatFee',
key: 'cheatFee',
render: (text, record, index) => {
return formatNum('100', text);
}
}, {
title: '作弊消耗占比',
dataIndex: 'cheatFeeRate',
key: 'cheatFeeRate',
render: (text, record, index) => {
return formatNum('%', text);
}
}, {
title: '广告位消耗',
dataIndex: 'adConsume',
key: 'adConsume',
render: (text, record, index) => {
return formatNum('100', text);
}
}, {
title: '媒体消耗',
dataIndex: 'appAdConsume',
key: 'appAdConsume',
render: (text, record, index) => {
return formatNum('100', text);
}
}, {
title: '分成比例',
dataIndex: 'divideRate',
key: 'divideRate',
render: (text, record, index) => {
return formatNum('%', text);
}
}, {
title: '命中规则 *',
dataIndex: 'rules',
key: 'rules',
render: (text, record, index) => {
const isOffline = record.dHour === '1';
let href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/118/${record.slotId}/${record.curDate}`;
if (!isOffline) href = `http://eye.dui88.com/tuia#!/tuiachartcenter/tuiatableview/329/${record.slotId}/${record.curDate}`;
return <a target="_blank" href={href}>{text}</a>;
}
}, {
title: '累计处理次数 *',
dataIndex: 'reviewCount',
key: 'reviewCount',
render: (text, record, index) => {
const { updateReviewResultModalObj } = store;
const showReviewResultModal = () => {
updateReviewResultModalObj({record: record, show: true});
};
return <a onClick={showReviewResultModal}>{text}</a>;
}
}, {
title: '作弊等级',
dataIndex: 'cheatGrade',
key: 'cheatGrade',
render: (text, record, index) => {
return `${text}级作弊` || '-';
}
}, {
title: '初步处理结果',
dataIndex: 'preResult',
key: 'preResult',
render: (text, record, index) => {
const date = new Date();
let disabled = date.getHours() >= 14 && date.getHours() <= 23;
return (
tableHoc('preResult', {preResult: record.preResult, riskAllId: record.id, id: record.riskReviewId})(
<Select
style={{ width: '100%' }}
placeholder="初步处理结果"
defaultValue={text}
disabled={disabled}
>
{reviewResultArrItem && reviewResultArrItem.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
);
}
}, {
title: '媒体处理意见',
dataIndex: 'mediaDealOpinion',
key: 'mediaDealOpinion',
render: (text, record, index) => {
let opinion = text === 1 ? '同意' : text === 0 ? '不同意' : '-';
return opinion || '-';
}
}, {
title: '最终处理金额',
dataIndex: 'finalDealMoney',
key: 'finalDealMoney',
render: (text, record, index) => {
return ((text) / 100).toFixed(2) || '-';
}
},
// {
// title: '是否上级复审',
// dataIndex: 'isSuperiorReview',
// key: 'isSuperiorReview',
// render: (text, record, index) => {
// let disabled = !(record.preResult !== null && record.reviewResult === null);
// // 兼容antd Switch
// if (text === 1) {
// text = true;
// } else {
// text = false;
// }
// return (
// tableHoc('isSuperiorReview', {preResult: record.isSuperiorReview, riskAllId: record.id, id: record.riskReviewId})(
// <Switch defaultChecked={text} disabled={disabled}/>
// )
// );
// }
// }, {
// title: '最终处理结果',
// dataIndex: 'reviewResult',
// render: (text, record, index) => {
// let disabled = record.isSuperiorReview === null || record.isSuperiorReview !== 1;
// return (
// tableHoc('reviewResult', {reviewResult: record.reviewResult, riskAllId: record.id, id: record.riskReviewId})(
// <Select
// style={{ width: '100%' }}
// placeholder="最终处理结果"
// // 0还是null处理转化
// // defaultValue={text === 0 ? null : text}
// defaultValue={text}
// disabled={disabled}
// >
// {reviewResultArrItem && reviewResultArrItem.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
// </Select>
// )
// );
// }
// }, {
// title: '通知媒体运营',
// dataIndex: 'needNotify',
// key: 'needNotify',
// render: (text, record, index) => {
// const date = new Date();
// let disabled = date.getHours() >= 14 && date.getHours() <= 23;
// return (
// tableHoc('needNotify', {riskAllId: record.id, id: record.riskReviewId})(
// <Switch defaultChecked={text} disabled={disabled}/>
// )
// )
// ;
// }
// },
{
title: '是否进入案列库',
dataIndex: 'isInExample',
key: 'isInExample',
render: (text, record, index) => {
if (text === 1) {
text = true;
} else {
text = false;
}
return tableHoc('isInExample', {isInExample: record.isInExample, riskAllId: record.id, id: record.riskReviewId}, record)(
<Switch
defaultChecked={text}
disabled={text}
/>
);
}
}, {
title: '查看进度',
dataIndex: 'currentProgress',
key: 'currentProgress',
render: (text, record, index) => {
const { updateProcessModalObj, getProcessModal } = store;
const showProcessModal = (params) => {
updateProcessModalObj({record: record});
getProcessModal({riskAllId: record.id});
};
return <a className={styles.link} onClick={showProcessModal}>{ record.currentProgress }</a>;
}
}, {
title: '备注',
dataIndex: 'reviewRemarks',
key: 'reviewRemarks',
render: (text, record, index) => {
return textAreahoc('reviewRemarks', {reviewRemarks: record.reviewRemarks, riskAllId: record.id, id: record.riskReviewId}, Object.assign({}, record, {tableTitle: '备注'}))(
<TextArea rows={1}/>
);
}
}
];
@observer
class CaseTable extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
handlePartition() {
const { configValue, getUpdateOrInsert } = store;
let content = '';
let params = {
configKey: 'batch.partition.switch'
};
if (configValue === '0') {
content = '确认后,系统将会在11:30、14:00对作弊媒体的分成自动调整';
params.configValue = '1';
}
if (configValue === '1') {
content = '取消后,系统将不会在11:30、14:00对作弊媒体的分成自动调整';
params.configValue = '0';
}
confirm({
title: '提示',
content: content,
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
getUpdateOrInsert(params);
},
onCancel() {
console.log('you chose close!');
}
});
}
componentDidMount() {
const { getConfigValue } = store;
getConfigValue();
}
render() {
const { dataIsLoading, dataList, addCaseModalObj, processModalObj, reviewResultModalObj } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
const { downReviewDataTable, params, configValue, finalDealMoney } = store;
let isBatchPartition = '';
isBatchPartition = configValue === '0' ? '确认批量调分成' : '取消批量调分成';
const buttonType = configValue === '0' ? 'primary' : '';
const date = new Date();
let disabled = date.getHours() >= 14 && date.getHours() <= 23;
return (
<div>
<Icon type="download" className={styles.down} onClick={downReviewDataTable}/>
<Button
disabled={disabled}
className={styles.buttonClick}
type={buttonType}
htmlType="submit"
onClick={this.handlePartition}
>
{isBatchPartition}
</Button>
{params.type === 2 ? <span>统计项:最终处理金额:{(finalDealMoney / 100).toFixed(2)}</span> : null}
<Table
className="audiTableStyle"
scroll={{ x: 2900 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
{addCaseModalObj.show ? <AddCaseModal addCaseModalObj={addCaseModalObj}/> : null }
{processModalObj.show ? <ProgressModal processModalObj={processModalObj}/> : null }
{reviewResultModalObj.show ? <ReviewResultModal reviewResultModalObj={reviewResultModalObj}/> : null }
</div>
);
}
}
export default CaseTable;
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: inline-block;
text-align: left;
cursor: pointer;
width: 20px;
}
.link {
color:#1890ff;
}
.buttonClick{
margin: 0 20px
}
:global{
.audiTableStyle{
.ant-table-thead > tr > th, .ant-table-tbody > tr > td{
padding: 21px 10px
}
}
}
\ No newline at end of file
import React from 'react';
import store from '../store';
import { Modal } from 'antd';
const confirm = Modal.confirm;
export default function change(key, params, record) {
return function(Wapper) {
const { addOrUpdate, getDataList } = store;
class NewComponent extends React.Component {
onChange = (value) => {
const { updateAddCaseModalObj } = store;
if (key === 'isInExample') {
updateAddCaseModalObj({
show: true,
record: record
});
return;
}
// switch 兼容后端
if (key === 'isSuperiorReview' || key === 'isInExample') {
if (value === true) {
value = 1;
} else {
value = 0;
}
}
params[key] = value;
this.showConfirm(params);
}
// 二次确认框
showConfirm = (params) => {
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
addOrUpdate(params);
},
onCancel() {
getDataList();
}
});
}
render() {
return (
React.cloneElement(
Wapper,
{
onChange: this.onChange
}
)
);
}
}
return <NewComponent/>;
};
}
import React from 'react';
import store from '../store';
import { Modal, Popover } from 'antd';
const confirm = Modal.confirm;
export default function change(key, params, record) {
return function(Wapper) {
const { addOrUpdate, getDataList } = store;
class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: record[key]
};
}
onBlur = (value) => {
params[key] = this.state.value;
this.showConfirm(params);
}
onChange = (evt) => {
this.setState({
value: evt.target.value
});
}
// 二次确认框
showConfirm = (params) => {
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
addOrUpdate(params);
},
onCancel() {
getDataList();
}
});
}
render() {
let CopyWapper = React.cloneElement(
Wapper,
{
value: this.state.value,
onBlur: this.onBlur,
onChange: this.onChange
}
);
return (
<Popover overlaystyle = {{maxWidth: '200px', wordWrap: 'break-word'}} title={record.tableTitle} placement = "left" content={this.state.value ? this.state.value : '暂无'}>
{CopyWapper}
</Popover>
);
}
}
return <NewComponent/>;
};
}
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import styles from './index.less';
@observer
class TypeSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
cheatGradeChange(type) {
this.props.chageCheatGrade(type);
}
render() {
const { cheatGrade } = store;
return (
<div className={styles.list_type}>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('6'); }}>
<p>6级作弊</p>
<p>{cheatGrade.cheatGradeSix}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('5'); }}>
<p>5级作弊</p>
<p>{cheatGrade.cheatGradeFive}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('4'); }}>
<p>4级作弊</p>
<p>{cheatGrade.cheatGradeFour}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('3'); }}>
<p>3级作弊</p>
<p>{cheatGrade.cheatGradeThree}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('2'); }}>
<p>2级作弊</p>
<p>{cheatGrade.cheatGradeTwo}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('1'); }}>
<p>1级作弊</p>
<p>{cheatGrade.cheatGradeOne}</p>
</div>
<div className={styles.item_type} onClick={() => { this.cheatGradeChange('0'); }}>
<p>0级作弊</p>
<p>{cheatGrade.cheatGradeZero}</p>
</div>
</div>
);
}
}
export default TypeSelect;
.list_type {
padding-top: 10px;
.item_type {
display: inline-block;
width: 80px;
height: 80px;
text-align: center;
font-size: 14px;
color: #fff;
border-radius: 2px;
margin: 0 2px;
cursor: pointer;
transition: all 0.1s cubic-bezier(0.165, 0.84, 0.44, 1);
p {
height: 40px;
&:nth-child(1) {
line-height: 60px;
}
&:nth-child(2) {
line-height: 30px;
}
}
&:nth-child(1) {
background-color: #f8696b;
}
&:nth-child(2) {
background-color: #fb9d75;
}
&:nth-child(3) {
background-color: #fed280;
}
&:nth-child(4) {
background-color: #dfe282;
}
&:nth-child(5) {
background-color: #a1d07e;
}
&:nth-child(6) {
background-color: #63be7b;
}
&:nth-child(7) {
background-color: #50a265;
}
&:hover {
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
transform: translate3d(0, -2px, 0);
}
}
}
\ No newline at end of file
import React from 'react';
class Auditsys extends React.Component {
render() {
return (
<div>{ this.props.children }</div>
);
};
};
export default Auditsys;
import React from 'react';
import { observer } from 'mobx-react';
import { withRouter } from 'react-router';
import styles from './index.less';
import Recheck from './recheck/index';
import Inspect from './inspect/index';
@observer
class Innercheck extends React.Component {
state = {
show: false
}
changeComponent = (type) => {
if (type === 1) {
this.setState({
show: false
});
} else {
this.setState({
show: true
});
}
}
render() {
return (
<div className = { styles.pagead }>
<div className = {styles.tablechange }>
<span onClick = {() => this.changeComponent(1)} className = {!this.state.show ? styles.active : '' }>广告计划复审</span>
<span onClick = {() => this.changeComponent(2)} className = {this.state.show ? styles.active : ''} >广告计划巡检</span>
</div>
{this.state.show ? <Inspect /> : <Recheck /> }
</div>
);
}
};
export default withRouter(Innercheck);
.pagead {
overflow: auto;
min-height: 800px;
.tablechange{
border-bottom:1px solid #eee;
font-size:0px;
.active{
background: #409EFF;
color:#fff;
}
span{
display: inline-block;
font-size:16px;
line-height: 40px;
padding-left:20px;
padding-right:20px;
cursor:pointer;
font-weight: 600;
&:nth-of-type(1) {
border:1px solid #eee;
border-bottom:none
}
&:nth-of-type(2) {
border:1px solid #eee;
border-bottom:none ;
border-left:none;
}
}
}
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Input, Button, DatePicker, Select } from 'antd';
import moment from 'moment';
import store from '../store';
import styles from './index.less';
const dateFormat = 'YYYY-MM-DD';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const Option = Select.Option;
@observer
class Formchild extends React.Component {
constructor(props) {
super(props);
this.state = {
// 巡检状态
inspectStatus: [
{
label: '全部',
id: ''
},
{
label: '待巡检',
id: 0
},
{
label: '已巡检',
id: 1
}
],
// 巡检结果
inspectResult: [
{
id: '',
label: '全部'
},
{
id: 1,
label: '巡检通过'
},
{
id: 2,
label: '巡检拒绝'
},
{
id: 3,
label: '巡检拒绝且下线'
}
]
};
}
componentDidMount() {
const { getadvertIndustryTags, getadvertPromoteTags } = store;
getadvertIndustryTags();
getadvertPromoteTags();
this.handleSubmit();
}
handleSubmit = () => {
const { getsecondReviewLists, changeParams } = store;
const { getFieldsValue } = this.props.form;
let params = getFieldsValue();
params = Object.assign(params, {
'dateRange.from': params['time'][0].format(dateFormat),
'dateRange.to': params['time'][1].format(dateFormat),
pageSize: 6,
currentPage: 1 // 每次提交的时候页码重置
});
delete params.time;
changeParams(params);
getsecondReviewLists(params);
}
// 参数重置
handleReset = () => {
const { getsecondReviewLists, changeParams } = store;
this.props.form.resetFields();
const { getFieldsValue } = this.props.form;
let _params = getFieldsValue();
changeParams(_params);
const {params} = store;
_params = Object.assign(params, {
'dateRange.from': params['time'][0].format(dateFormat),
'dateRange.to': params['time'][1].format(dateFormat),
pageSize: 6,
currentPage: 1 // 每次提交的时候页码重置
});
delete _params.time;
getsecondReviewLists(_params);
}
render() {
const { advertIndustryTags, advertPromoteTags } = store;
let _advertIndustryTags = [{tagNum: '', tagName: '全部'}, ...(advertIndustryTags.slice())];
let _advertPromoteTags = [{tagNum: '', tagName: '全部'}, ...(advertPromoteTags.slice())];
const { getFieldDecorator } = this.props.form;
// 时间
return (
<div>
<Form layout="inline">
<FormItem label="时间">
{getFieldDecorator('time', {
initialValue: [moment().subtract(1, 'days'), moment().subtract(0, 'days')]
})(
<RangePicker format={dateFormat}/>
)}
</FormItem>
<FormItem
label="广告ID"
>
{getFieldDecorator('advertId', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="广告名称"
>
{getFieldDecorator('advertName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="商品名称"
>
{getFieldDecorator('goodsName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="巡检状态"
>
{getFieldDecorator('inspectStatus', {
initialValue: ''
})(
<Select style={{ width: 120 }}>
{
this.state.inspectStatus.map((ele) => {
return (<Option key={ele.id} value={ele.id}>{ele.label}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="巡检结果"
>
{getFieldDecorator('inspectResult', {
initialValue: ''
})(
<Select style={{ width: 150 }}>
{
this.state.inspectResult.map((ele) => {
return (<Option key={ele.id} value={ele.id}>{ele.label}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="复审"
>
{getFieldDecorator('secondReviewer', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="初审"
>
{getFieldDecorator('firstReviewer', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="AE"
>
{getFieldDecorator('ae', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="销售"
>
{getFieldDecorator('sale', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="代理商名称"
>
{getFieldDecorator('agentName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="广告主名称"
>
{getFieldDecorator('advertMaster', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="行业"
>
{getFieldDecorator('industryTag', {
initialValue: ''
})(
<Select style={{ width: 150 }}>
{
_advertIndustryTags.map((ele, index) => {
return (<Option key={ index } value={ele.tagNum}>{ele.tagName}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="落地页标签"
>
{getFieldDecorator('promoteTag', {
initialValue: ''
})(
<Select style={{ width: 150 }}>
{
_advertPromoteTags.map((ele, index) => {
return (<Option key={ index } value={ele.tagNum}>{ele.tagName}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem>
<Button
type="primary"
className = {styles.sum_btn}
onClick = { this.handleSubmit }
>
查询
</Button>
<Button
onClick={this.handleReset}
>
重置
</Button>
</FormItem>
</Form>
</div>
);
}
}
const Innercheckform = Form.create({})(Formchild);
export default Innercheckform;
.sum_btn{
margin-right: 10px;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import Innercheckform from './form/index';
import Innertable from './table/index';
@observer
class Recheck extends React.Component {
render() {
return (
<div>
<Innercheckform />
<Innertable />
</div>
);
}
};
export default Recheck;
import React from 'react';
import { Modal, Radio, Form, Input, message } from 'antd';
import { observer } from 'mobx-react';
import store from '../store';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const { TextArea } = Input;
@observer
class RecheckModals extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
confirmLoading: false,
needmemo: false
};
}
afterClose = () => {
this.setState({
needmemo: false
});
}
showModal = () => {
this.setState({
visible: true
});
}
handleOk = () => {
this.handleSearch();
}
handleCancel = () => {
// 取消传值
this.props.changestate({
status: false,
type: 'cancle'
});
}
// 表单提交
handleSearch = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.setState({
confirmLoading: true
});
const { inspect, ids } = store;
inspect({
ids: ids,
memo: this.props.form.getFieldValue('memo') || '',
result: this.props.form.getFieldValue('result')
}).then((res) => {
// 更新列表
if (res.success) {
this.setState({
confirmLoading: false
});
const { getsecondReviewLists, params } = store;
getsecondReviewLists(params);
this.props.changestate({
status: false,
type: 'ok'
});
} else {
message.error(res.desc);
}
});
};
});
}
// 自定规则
validatorRule = (rule, value, calls) => {
let type = this.props.form.getFieldValue('result');
if (type === 1) {
calls();
} else {
if (!value) {
calls('巡检拒绝,请输入备注');
} else if (value.length > 64) {
calls('最多输入64个字');
} else {
calls();
}
}
}
// 类型改变
onChangetype = (e) => {
let val = e.target.value;
if (val === 1) {
this.setState({
needmemo: false
});
// 重置
this.props.form.resetFields();
} else {
this.setState({
needmemo: true
});
}
}
textchange = (e) => {
}
render() {
const { confirmLoading } = this.state;
const { getFieldDecorator } = this.props.form;
return (
<div>
<Modal title="巡检"
visible={this.props.show}
onOk={this.handleOk}
confirmLoading={confirmLoading}
onCancel={this.handleCancel}
okText = '确定'
cancelText = '取消'
afterClose = {this.afterClose}
destroyOnClose
>
<Form
className="ant-advanced-search-form"
onSubmit={this.handleSearch}
>
<FormItem label='巡检结果'>
{getFieldDecorator('result', {
initialValue: 1
})(
<RadioGroup onChange={this.onChangetype} >
<Radio value={1}>巡检通过</Radio>
<Radio value={2}>巡检拒绝</Radio>
</RadioGroup>
)}
</FormItem>
<FormItem label='备注'>
{getFieldDecorator('memo', {
rules: [
{
required: this.state.needmemo,
validator: this.validatorRule
}
]
})(
<TextArea rows={4} onChange = {this.textchange} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const RecheckModal = Form.create({})(RecheckModals);
export default RecheckModal;
import {observable, action} from 'mobx';
import common from 'src/lib/common';
class State {
@observable
params = {
pageSize: 6,
currentPage: 1
};
@action
changeParams = (params = this.params) => {
this.params = params;
}
@observable
pagesize = 1;
@action
changepage = (page) => {
this.pagesize = page;
}
@observable
advertIndustryTags = []; // 行业标签
@observable
advertPromoteTags = []; // 落地页标签
// loading
@observable
dataIsLoading = false;
// 请求参数
@observable
innertablelist = [];
@observable
innertotal = {};
@action
getsecondReviewLists = (params = this.params) => {
// 巡检列表
this.dataIsLoading = true;
common.fetch('/plan/inspectList', params, 'get').then(res => {
this.innertotal = res.data;
this.dataIsLoading = false;
this.innertablelist = res.data.list && res.data.list.map((ele, index) => {
return Object.assign(ele, {key: `${ele.advertId} + ${Date.parse(new Date())}`});
});
;
});
}
// 行业标签
@action
getadvertIndustryTags = () => {
common
.fetch('/plan/advertIndustryTags', '', 'get')
.then(res => {
this.advertIndustryTags = res.data || [];
});
}
// 落地页标签
@action
getadvertPromoteTags = () => {
common
.fetch('/plan/advertPromoteTags', '', 'get')
.then(res => {
this.advertPromoteTags = res.data || [];
});
}
// 巡检
@observable
ids = [];
@observable
checkres = {}
@action
changeids = (ids) => {
this.ids = ids;
}
@action
inspect = (params) => {
const promise = new Promise((resolve, reject) => {
common.fetch('/plan/inspect', params, 'post', {isJson: true}).then(res => {
resolve(res);
this.checkres = res;
});
});
return promise;
}
// 下线
@action
offlines = (params) => {
this.dataIsLoading = true;
const promise = new Promise((resolve, reject) => {
common.fetch('/plan/inspectDown', params, 'post', {isJson: true}).then(res => {
resolve(res);
this.checkres = res;
this.dataIsLoading = false;
});
});
return promise;
}
@observable
hasPermission = true;
// 权限验证
@action
checkPermission = (params) => {
const promise = new Promise((resolve, reject) => {
common.fetch('/auth/getAuthList', params, 'get').then(res => {
resolve(res);
res.authList.includes('/plan/canAdvertReview') ? (this.hasPermission = true) : (this.hasPermission = false);
});
});
return promise;
}
// 导出
@action
downLoadInspectTable = () => {
window.open('/plan/inspectExport?' + common.concatUrl(this.params));
}
}
// 下线
const store = new State();
export default store;
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import { Table, Button, message, Modal, Icon } from 'antd';
import RecheckModal from '../modal';
import { formatDateTime } from '../../../../../lib/dataFormate';
import styles from './index.less';
import moment from 'moment';
const dateFormat = 'YYYY-MM-DD';
const confirm = Modal.confirm;
@observer
class Innertable extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: '',
tabledata: [],
show: false,
checkData: []
};
}
// 巡检
inspect = () => {
if (this.state.checkData.length === 0) {
message.warning('请勾选相应的广告计划数据');
return false;
} else {
this.setState({
show: true
});
}
}
// 下线
offline = () => {
const _this = this;
if (this.state.checkData.length === 0) {
message.warning('请勾选相应的广告计划数据');
return false;
} else {
// 只有巡检的才可以下线
const hasinepect = this.state.checkData.some((ele) => {
return ele.inspectStatus === 0;
});
if (hasinepect) {
message.warning('只有巡检过的广告计划才可以下线!');
return false;
}
let _data = this.state.checkData;
confirm({
title: '是否确定下线该广告计划?',
content: '',
okText: '确定',
cancelText: '取消',
onOk() {
let idparams = _data.map((ele) => ele.advertId);
// 请求下线接口
const { offlines, params, getsecondReviewLists } = store;
offlines({ids: idparams}).then((res) => {
if (res.success) {
message.success('已下线');
getsecondReviewLists(params);
_this.setState({
checkData: []
});
}
});
},
onCancel() {
}
});
}
}
componentDidMount() {
const { getsecondReviewLists, checkPermission } = store;
// 参数重置
const _params = {
'dateRange.from': moment().subtract(1, 'days').format(dateFormat),
'dateRange.to': moment().subtract(0, 'days').format(dateFormat),
advertId: '',
advertMaster: '',
advertName: '',
ae: '',
agentName: '',
firstReviewer: '',
goodsName: '',
industryTag: '',
promoteTag: '',
sale: '',
secondReviewStatus: 0,
pageSize: 6,
currentPage: 1
};
getsecondReviewLists(_params);
checkPermission();
}
changestate(msg) {
if (msg.type === 'ok') {
this.setState({
show: msg.status,
checkData: []
});
} else {
this.setState({
show: msg.status
});
}
}
render() {
// checkPermission
const { innertablelist, innertotal, hasPermission, dataIsLoading } = store;
let _innertablelist = innertablelist.slice();
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: innertotal.totalCount,
showTotal: (total) => (`共${total}条`),
onChange: page => {
const { changeParams, getsecondReviewLists, params } = store;
let _params = Object.assign(params, {
currentPage: page
});
changeParams(_params);
getsecondReviewLists(_params);
}
};
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
// 需核查数据
this.setState({
checkData: selectedRows
});
const { changeids } = store;
let _ids = selectedRows.map((ele) => ele.advertId);
// 跟新id
changeids(_ids);
},
selections: false,
hideDefaultSelections: true,
getCheckboxProps: (record) => {
const _reject = record.inspectStatus === 3 || record.advertStatus === 1;
return {
disabled: _reject
};
}
};
const columns = [{
title: '广告ID',
dataIndex: 'advertId',
width: 100,
fixed: 'left',
render: (text, record, index) => (
<div>
<a onClick={() => {
const id = _innertablelist[index].advertId;
window.open(`http://manager.tuia.cn/#/fastAuditAdvert/${id}`);
}}>{text}</a>
</div>
)
}, {
title: '广告名称',
dataIndex: 'advertName',
width: 120,
fixed: 'left',
render: (text, record, index) => (
<div>
<a onClick={() => {
const id = _innertablelist[index].advertId;
window.open(`http://manager.tuia.cn/#/fastAuditAdvert/${id}`);
}}>{text}</a>
</div>
)
}, {
title: '广告主名称',
dataIndex: 'advertMaster'
}, {
title: '代理商名称',
dataIndex: 'agentName'
}, {
title: '广告计划状态',
dataIndex: 'advertStatusShow'
},
// {
// title: '来源',
// dataIndex: 'source',
// render: (text, record, index) => {
// switch (text) {
// case 0:
// text = '广告平台';
// break;
// case 1:
// text = '兑吧商品';
// break;
// default:
// text = '券库';
// break;
// }
// return (<span>{text}</span>);
// }
// },
{
title: '巡检状态',
dataIndex: 'inspectStatus',
render: (text, record, index) => {
switch (text) {
case 0:
text = '待巡检';
break;
default:
text = '已巡检';
break;
}
return (<span>{text}</span>);
}
}, {
title: '最近巡检结果',
dataIndex: 'inspectResult',
render: (text, record, index) => {
switch (text) {
case 0:
text = '待巡检';
break;
case 1:
text = '巡检通过';
break;
case 2:
text = '巡检拒绝';
break;
default:
text = '巡检拒绝且下线';
break;
}
return (<span>{text}</span>);
}
}, {
title: '巡检累计次数',
dataIndex: 'inspectCount',
render: (text, record, index) => {
return (<span>{text}</span>);
}
}, {
title: '巡检备注',
dataIndex: 'inspectMemo'
}, {
title: '最近巡检时间',
dataIndex: 'inspectTime',
render: (text, record, index) => {
if (!text) {
return '暂无';
}
return formatDateTime(text);
}
}, {
title: '最近审核时间',
dataIndex: 'lastReviewTime',
render: (text, record, index) => {
if (!text) {
return '暂无';
}
return formatDateTime(text);
}
}, {
title: '初审',
dataIndex: 'firstReviewer'
}, {
title: 'AE',
dataIndex: 'ae'
}, {
title: '销售',
dataIndex: 'sale'
}, {
title: '复审',
dataIndex: 'secondReviewer'
}];
const { downLoadInspectTable } = store;
return (
<div>
<div className = { styles.table_options }>
{ hasPermission ? <Button type="primary" onClick = {this.inspect}>巡检</Button> : '' }
<Button type="primary" onClick = {this.offline}>下线</Button>
<Icon type="download" className={styles.down} onClick={downLoadInspectTable}/>
</div>
<Table
rowSelection= { rowSelection }
columns={columns}
pagination={true}
pagination={paganationOpts}
scroll={{ x: 2000 }}
locale={{ emptyText: '暂无数据' }}
loading={ dataIsLoading }
dataSource={ _innertablelist } />
<RecheckModal ref = 'RecheckModal' changestate={ msg => this.changestate(msg) } show={this.state.show} />
</div>
);
}
}
export default Innertable;
.table_options{
margin-top: 20px;
margin-bottom: 20px;
button {
margin-right:10px;
}
}
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: block;
text-align: left;
cursor: pointer;
width: 20px
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import { Form, Input, Button, DatePicker, Select } from 'antd';
import moment from 'moment';
import store from '../store';
import styles from './index.less';
const dateFormat = 'YYYY-MM-DD';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
const Option = Select.Option;
@observer
class Formchild extends React.Component {
constructor(props) {
super(props);
this.state = {
// 复审状态
secondReviewStatus: [
{
id: '',
label: '全部'
},
{
id: 0,
label: '待复审'
},
{
id: 1,
label: '已复审'
}
],
// 审核结果
reviewResult: [
{
id: '',
label: '全部'
},
{
id: 1,
label: '初审通过'
},
{
id: 3,
label: '复审通过'
},
{
id: 4,
label: '复审拒绝'
}
]
};
}
componentDidMount() {
const { getadvertIndustryTags, getadvertPromoteTags } = store;
getadvertIndustryTags();
getadvertPromoteTags();
this.handleSubmit();
}
handleSubmit = () => {
const { getsecondReviewLists, changeParams } = store;
const { getFieldsValue } = this.props.form;
let params = getFieldsValue();
params = Object.assign(params, {
'dateRange.from': params['time'][0].format(dateFormat),
'dateRange.to': params['time'][1].format(dateFormat),
pageSize: 6,
currentPage: 1 // 每次提交的时候页码重置
});
delete params.time;
changeParams(params);
getsecondReviewLists(params);
}
// 参数重置
handleReset = () => {
const { getsecondReviewLists, changeParams } = store;
this.props.form.resetFields();
const { getFieldsValue } = this.props.form;
let _params = getFieldsValue();
changeParams(_params);
const {params} = store;
_params = Object.assign(params, {
'dateRange.from': params['time'][0].format(dateFormat),
'dateRange.to': params['time'][1].format(dateFormat),
pageSize: 6,
currentPage: 1 // 每次提交的时候页码重置
});
delete _params.time;
getsecondReviewLists(_params);
}
render() {
const { advertIndustryTags, advertPromoteTags } = store;
let _advertIndustryTags = [{tagNum: '', tagName: '全部'}, ...(advertIndustryTags.slice())];
let _advertPromoteTags = [{tagNum: '', tagName: '全部'}, ...(advertPromoteTags.slice())];
const { getFieldDecorator } = this.props.form;
// 时间
return (
<div>
<Form layout="inline">
<FormItem
className = {styles.formBlock}
label="时间">
{getFieldDecorator('time', {
initialValue: [moment().subtract(1, 'days'), moment().subtract(0, 'days')]
})(
<RangePicker format={dateFormat}/>
)}
</FormItem>
<FormItem
label="广告ID"
>
{getFieldDecorator('advertId', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="广告名称"
>
{getFieldDecorator('advertName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="商品名称"
>
{getFieldDecorator('goodsName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="复审状态"
>
{getFieldDecorator('secondReviewStatus', {
initialValue: 0
})(
<Select style={{ width: 120 }}>
{
this.state.secondReviewStatus.map((ele) => {
return (<Option key={ele.id} value={ele.id}>{ele.label}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="审核结果"
>
{getFieldDecorator('reviewResult', {
initialValue: ''
})(
<Select style={{ width: 120 }}>
{
this.state.reviewResult.map((ele) => {
return (<Option key={ele.id} value={ele.id}>{ele.label}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="初审"
>
{getFieldDecorator('firstReviewer', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="AE"
>
{getFieldDecorator('ae', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="销售"
>
{getFieldDecorator('sale', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="代理商名称"
>
{getFieldDecorator('agentName', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="广告主名称"
>
{getFieldDecorator('advertMaster', {
initialValue: ''
})(
<Input />
)}
</FormItem>
<FormItem
label="行业"
>
{getFieldDecorator('industryTag', {
initialValue: ''
})(
<Select style={{ width: 150 }}>
{
_advertIndustryTags.map((ele, index) => {
return (<Option key={ index } value={ele.tagNum}>{ele.tagName}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem
label="落地页标签"
>
{getFieldDecorator('promoteTag', {
initialValue: ''
})(
<Select style={{ width: 150 }}>
{
_advertPromoteTags.map((ele, index) => {
return (<Option key={ index } value={ele.tagNum}>{ele.tagName}</Option>);
})
}
</Select>
)}
</FormItem>
<FormItem>
<Button
type="primary"
className = { styles.sum_btn }
onClick = { this.handleSubmit }
>
查询
</Button>
<Button
onClick={this.handleReset}
>
重置
</Button>
</FormItem>
</Form>
</div>
);
}
}
const Innercheckform = Form.create({})(Formchild);
export default Innercheckform;
.sum_btn{
margin-right: 10px;
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import Innercheckform from './form/index';
import Innertable from './table/index';
@observer
class Recheck extends React.Component {
render() {
return (
<div>
<Innercheckform />
<Innertable />
</div>
);
}
};
export default Recheck;
import React from 'react';
import { Modal, Radio, Form, Input, message } from 'antd';
import { observer } from 'mobx-react';
import store from '../store';
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const { TextArea } = Input;
@observer
class RecheckModals extends React.Component {
constructor(props) {
super(props);
this.state = {
visible: false,
confirmLoading: false,
needmemo: false
};
}
afterClose = () => {
this.setState({
needmemo: false
});
}
showModal = () => {
this.setState({
visible: true
});
}
handleOk = () => {
this.setState({
ModalText: 'The modal will be closed after two seconds',
confirmLoading: false
});
this.handleSearch();
}
handleCancel = () => {
// 传值
this.props.changestate({
status: false,
type: 'cancle'
});
}
// 表单提交
handleSearch = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
this.setState({
confirmLoading: true
});
const { reCheck, ids } = store;
reCheck({
ids: ids,
memo: this.props.form.getFieldValue('memo') || '',
result: this.props.form.getFieldValue('result')
}).then((res) => {
// 更新列表
if (res.success) {
this.setState({
confirmLoading: false
});
const { getsecondReviewLists, params } = store;
getsecondReviewLists(params);
this.props.changestate({
status: false,
type: 'ok'
});
} else {
message.error(res.desc);
}
});
};
});
}
// 自定规则
validatorRule = (rule, value, calls) => {
let type = this.props.form.getFieldValue('result');
if (type === 1) {
calls();
} else {
if (!value) {
calls('审核拒绝,请输入备注');
} else if (value.length > 64) {
calls('最多输入64个字');
} else {
calls();
}
}
}
// 类型改变
onChangetype = (e) => {
let val = e.target.value;
if (val === 1) {
this.setState({
needmemo: false
});
// 重置
this.props.form.resetFields();
} else {
this.setState({
needmemo: true
});
}
}
textchange = (e) => {
}
render() {
const { confirmLoading } = this.state;
const { getFieldDecorator } = this.props.form;
return (
<div>
<Modal title="复审"
visible={this.props.show}
onOk={this.handleOk}
confirmLoading={confirmLoading}
onCancel={this.handleCancel}
okText = '确定'
cancelText = '取消'
afterClose = {this.afterClose}
destroyOnClose
>
<Form
className="ant-advanced-search-form"
onSubmit={this.handleSearch}
>
<FormItem label='复审结果'>
{getFieldDecorator('result', {
initialValue: 1
})(
<RadioGroup onChange={this.onChangetype} >
<Radio value={1}>复审通过</Radio>
<Radio value={2}>复审拒绝</Radio>
</RadioGroup>
)}
</FormItem>
<FormItem label='备注'>
{getFieldDecorator('memo', {
rules: [
{
required: this.state.needmemo,
validator: this.validatorRule
}
]
})(
<TextArea rows={4} onChange = {this.textchange} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const RecheckModal = Form.create({})(RecheckModals);
export default RecheckModal;
import {observable, action} from 'mobx';
import common from 'src/lib/common';
class State {
@observable
dataIsLoading = false;
@observable
params = {
pageSize: 6,
currentPage: 1
};
@action
changeParams = (params = this.params) => {
this.params = params;
}
@observable
pagesize = 1;
@action
changepage = (page) => {
this.pagesize = page;
}
@observable
advertIndustryTags = []; // 行业标签
@observable
advertPromoteTags = []; // 落地页标签
// 请求参数 @observable params = { };
@observable
innertablelist = [];
@observable
innertotal = {};
@action
getsecondReviewLists = (params = this.params) => {
// 复审列表
this.dataIsLoading = true;
common.fetch('/plan/secondReviewList', params, 'get').then(res => {
this.innertotal = res.data || {};
this.dataIsLoading = false;
this.innertablelist = res.data.list && res.data.list.map((ele, index) => {
return Object.assign(ele, {key: `${ele.advertId} + ${Date.parse(new Date())}`});
});
});
}
// 行业标签
@action
getadvertIndustryTags = () => {
common
.fetch('/plan/advertIndustryTags', '', 'get')
.then(res => {
this.advertIndustryTags = res.data || [];
});
}
// 落地页标签
@action
getadvertPromoteTags = () => {
common
.fetch('/plan/advertPromoteTags', '', 'get')
.then(res => {
this.advertPromoteTags = res.data || [];
});
}
// 复审
@observable
ids = [];
@observable
checkres = {}
@action
changeids = (ids) => {
this.ids = ids;
}
@action
reCheck = (params) => {
const promise = new Promise((resolve, reject) => {
common.fetch('/plan/secondReview', params, 'post', {isJson: true}).then(res => {
resolve(res);
this.checkres = res;
});
});
return promise;
}
@observable
hasPermission = true;
// 权限验证
@action
checkPermission = (params) => {
const promise = new Promise((resolve, reject) => {
common.fetch('/auth/getAuthList', params, 'get').then(res => {
resolve(res);
res.authList.includes('/plan/canAdvertReview') ? (this.hasPermission = true) : (this.hasPermission = false);
});
});
return promise;
}
// 导出
@action
downLoadChecksTable = () => {
window.open('/plan/secondReviewExport?' + common.concatUrl(this.params));
}
}
const store = new State();
export default store;
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import { Table, Button, message, Icon } from 'antd';
import RecheckModal from '../modal';
import { formatDateTime } from '../../../../../lib/dataFormate';
import textAreaHoc from './textAreaHoc';
import styles from './index.less';
import moment from 'moment';
const dateFormat = 'YYYY-MM-DD';
message.config({
maxCount: 1,
duration: 2
});
@observer
class Innertable extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: '',
tabledata: [],
show: false,
checkData: []
};
}
// 复审
checks = () => {
if (this.state.checkData.length === 0) {
message.warning('请勾选相应的广告计划数据');
return false;
} else {
const hascheck = this.state.checkData.some((ele) => {
return ele.reviewStatus === 1 || ele.reviewStatus === 2;
});
if (hascheck) {
message.warning('所选项目有项目已复审完毕,请核查后重新选择!');
} else {
this.setState({
show: true
});
}
}
}
componentDidMount() {
const { getsecondReviewLists, checkPermission } = store;
// 参数重置
const _params = {
'dateRange.from': moment().subtract(1, 'days').format(dateFormat),
'dateRange.to': moment().subtract(0, 'days').format(dateFormat),
advertId: '',
advertMaster: '',
advertName: '',
ae: '',
agentName: '',
firstReviewer: '',
goodsName: '',
industryTag: '',
promoteTag: '',
sale: '',
secondReviewStatus: 0,
pageSize: 6,
currentPage: 1
};
getsecondReviewLists(_params);
checkPermission();
}
changestate(msg) {
if (msg.type === 'ok') {
this.setState({
show: msg.status,
checkData: []
});
} else {
this.setState({
show: msg.status
});
}
}
render() {
const { innertablelist, innertotal, hasPermission, dataIsLoading } = store;
let _innertablelist = innertablelist.slice();
// 分页配置信息
const paganationOpts = {
defaultPageSize: 6,
current: store.params.currentPage,
total: innertotal.totalCount,
showTotal: (total) => (`共${total}条`),
onChange: page => {
const { changeParams, getsecondReviewLists, params } = store;
let _params = Object.assign(params, {
currentPage: page
});
changeParams(_params);
getsecondReviewLists(_params);
}
};
// 跳转
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
// 需核查数据
this.setState({
checkData: selectedRows
});
const { changeids } = store;
let _ids = selectedRows.map((ele) => ele.advertId);
// 跟新id
changeids(_ids);
}
};
const columns = [{
title: '广告ID',
dataIndex: 'advertId',
fixed: 'left',
width: 100,
render: (text, record, index) => (
<div>
<a onClick={() => {
const id = _innertablelist[index].advertId;
window.open(`http://manager.tuia.cn/#/fastAuditAdvert/${id}`);
}}>{text}</a>
</div>
)
}, {
title: '广告名称',
dataIndex: 'advertName',
fixed: 'left',
width: 120,
render: (text, record, index) => (
<div>
<a onClick={() => {
const id = _innertablelist[index].advertId;
window.open(`http://manager.tuia.cn/#/fastAuditAdvert/${id}`);
}}>{text}</a>
</div>
)
}, {
title: '广告主名称',
dataIndex: 'advertMaster'
}, {
title: '代理商名称',
dataIndex: 'agentName'
}, {
title: '标签',
dataIndex: 'labels',
key: 'labels',
width: 200,
render: (text, record, index) => {
let textArr = [];
let textStr = '';
text && text.forEach(item => {
item.child && item.child.forEach(subItem => {
subItem.child && subItem.child.forEach(subsubItem => {
textArr.push(subsubItem.tagName);
textStr = textArr.join(', ');
});
});
});
return textAreaHoc('labels', { labels: record.labels, id: record.id }, Object.assign({}, record, {tableTitle: '标签'}))(
<span className={styles.limit}>{textStr}</span>
);
}
},
// {
// title: '来源',
// dataIndex: 'source',
// render: (text, record, index) => {
// switch (text) {
// case 0:
// text = '广告平台';
// break;
// case 1:
// text = '兑吧商品';
// break;
// default:
// text = '券库';
// break;
// }
// return (<span>{text}</span>);
// }
// },
{
title: '复审状态',
dataIndex: 'reviewStatus',
render: (text, record, index) => {
switch (text) {
case 0:
text = '待复审';
break;
default:
text = '已复审';
break;
}
return (<span>{text}</span>);
}
}, {
title: '审核结果',
dataIndex: 'secondResult',
render: (text, record, index) => {
if (record.reviewStatus === 0) {
if (record.firstResult === 1) {
text = '初审通过';
} else {
text = '初审拒绝';
}
} else {
if (record.secondResult === 1) {
text = '复审通过';
} else {
text = '复审拒绝';
}
}
return (<span>{text}</span>);
}
}, {
title: '审核备注',
dataIndex: 'secondMemo'
}, {
title: '最近审核时间',
dataIndex: 'lastReviewTime',
render: (text, record, index) => {
return formatDateTime(text);
}
}, {
title: '初审',
dataIndex: 'firstReviewer'
}, {
title: 'AE',
dataIndex: 'ae'
}, {
title: '销售',
dataIndex: 'sale'
}, {
title: '复审',
dataIndex: 'secondReviewer'
}];
const { downLoadChecksTable } = store;
return (
<div>
<div className = { styles.table_options }>
{ hasPermission ? <Button type="primary" onClick = {this.checks}>复审</Button> : '' }
<Icon type="download" className={styles.down} onClick={downLoadChecksTable}/>
</div>
<Table
rowSelection= { rowSelection }
columns={columns}
pagination={true}
pagination={paganationOpts}
scroll={{ x: 2000 }}
loading = { dataIsLoading }
locale={{ emptyText: '暂无数据' }}
dataSource={ _innertablelist } />
<RecheckModal ref = 'RecheckModal' changestate={ msg => this.changestate(msg) } show={this.state.show} />
</div>
);
}
}
export default Innertable;
.table_options{
margin-top: 20px;
margin-bottom: 20px;
button {
margin-right:10px;
}
}
.down {
font-size: 20px;
color: #2c3e50;
margin: 20px 0;
display: block;
text-align: left;
cursor: pointer;
width: 20px
}
.limit{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
\ No newline at end of file
import React from 'react';
import {Popover} from 'antd';
import styles from './textAreaHoc.less';
export default function change(key, params, record) {
return function(Wapper) {
class NewComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: record
};
}
render() {
// 递归生成菜单
const generateMenu = (menuObj, treeLevel = 0, index) => {
let dom = [];
if (menuObj instanceof Array) {
let list = [];
menuObj && menuObj.length && menuObj.forEach((item, index) => {
list.push(generateMenu(item, treeLevel + 1, index));
});
dom.push(
<ul key={'uu' + treeLevel + index}>
{ list.map(function(item, index) {
return (
<div className={styles.menuRoot} key={'div' + treeLevel + index}>
{item}
</div>
);
}) }
</ul>
);
} else {
let itemName = menuObj ? menuObj.tagName : false;
dom.push(
<span key={'span' + treeLevel + index}>
<li className={styles.myLi}>
{itemName}
</li>
</span>
);
let next = menuObj ? menuObj.child : false;
if (next) {
let list = [];
next.forEach((item, index) => {
list.push(generateMenu(item, treeLevel + 1, index));
});
dom.push(
<ul key={'ul' + treeLevel + index}>
{list}
</ul>
);
}
}
return dom;
};
let CopyWapper = React.cloneElement(
Wapper,
{}
);
return (
<Popover title={record.tableTitle} placement="top" content={generateMenu(record.labels)}>
{CopyWapper}
</Popover>
);
}
}
return <NewComponent/>;
};
}
.popover{
width: 200px;
word-break:normal;
white-space:pre-warp;
word-wrap:break-word;
}
.myLi{
list-style: initial
}
ul{
padding-left: 15px
}
.menuRoot:nth-child(n+2){
margin-top: 10px;
}
\ No newline at end of file
import React from 'react';
import {withRouter} from 'react-router';
import PageSearch from './search';
import ScenceTable from './table';
class ruleEngine extends React.Component {
render() {
return (
<div>
<PageSearch />
<ScenceTable />
</div>
);
}
};
export default withRouter(ruleEngine);
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import {
Form,
Input,
Modal,
Select
} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
let TextArea = Input.TextArea;
const typeArr = [
{ value: '0', text: '数值' },
{ value: '1', text: '字符串' }];
const tableNameArr = [
{ value: '1', text: '用户' },
{ value: '2', text: '设备' },
{ value: '3', text: 'ip' },
{ value: '4', text: 'ip前三段' },
{ value: '5', text: 'UA' }];
@observer
class Edit extends React.Component {
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { checkFieldName, updateFieldList } = store;
const { getFieldValue } = this.props.form;
let params = {
name: getFieldValue('name'),
type: getFieldValue('type'),
tableName: getFieldValue('tableName'),
tableColumn: getFieldValue('tableColumn'),
sceneIds: getFieldValue('sceneIds'),
description: getFieldValue('description'),
gmtCreate: this.props.editObj.gmtCreate || '',
creator: this.props.editObj.creator || '',
id: this.props.editObj.id
};
let isEdit = this.props.isEdit;
if ((getFieldValue('name') !== this.props.editObj.name) && this.props.isEdit) {
checkFieldName(params, isEdit, values.name).then(this.props.closeModal);
} else if (this.props.isEdit) {
updateFieldList(params).then(this.props.closeModal);
}
if (!this.props.isEdit) {
checkFieldName(params, isEdit, values.name).then(this.props.closeModal);
}
}
});
};
handleCancel = () => {
this.props.closeModal();
};
render() {
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const { sceneIdsArr, isFieldArr } = store;
const { getFieldDecorator } = this.props.form;
let sceneArr = [];
this.props.editObj.sceneNames && this.props.editObj.sceneNames.forEach(item => {
sceneArr.push(item.sceneId);
});
// 字段名称
let nameProps = getFieldDecorator('name', {
initialValue: this.props.editObj.name || '',
rules: [{
required: true, message: '请输入!'
}, {
max: 30, message: '最多输入30个字符!'
}]
});
// 字段类型
let typeProps = getFieldDecorator('type', {
initialValue: this.props.editObj.type || '0'
});
// 维度
let tableNameProps = getFieldDecorator('tableName', {
initialValue: this.props.editObj.tableName || '1'
});
// 表字段
let tableColumnProps = getFieldDecorator('tableColumn', {
initialValue: this.props.editObj.tableColumn,
rules: [{
required: true, message: '请输入!'
}]
});
// 所属场景
let sceneIdsProps = getFieldDecorator('sceneIds', {
initialValue: sceneArr || '',
rules: [{
required: true, message: '请选择!'
}]
});
// 描述
let descriptionProps = getFieldDecorator('description', {
initialValue: this.props.editObj.description || '',
rules: [{
max: 64, message: '最多输入64个字符!'
}]
});
return (
<div>
<Modal
title={ this.props.isEdit ? '编辑字段' : '新建字段'}
width={400}
visible={true}
maskClosable={false}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="保存"
cancelText="取消"
>
<Form>
<FormItem
{...formItemLayout}
label="字段名称"
>
{nameProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="字段类型"
>
{typeProps(
<Select
style={{ width: '100%' }}
placeholder="请选择"
>
{typeArr && typeArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="维度"
>
{
tableNameProps(
<Select
style={{ width: '100%' }}
placeholder="请选择"
>
{tableNameArr && tableNameArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="表字段"
>
{
tableColumnProps(
<Input type="text" />
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="所属场景"
>
{
sceneIdsProps(
<Select
mode="multiple"
style={{ width: '100%' }}
placeholder="请选择"
// onDeselect={this.handleDel}
>
{sceneIdsArr && sceneIdsArr.map((d, index) => <Option disabled={isFieldArr.indexOf(d.id) !== -1} key={index} value={d.id}>{d.sceneName}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="描述:"
>
{descriptionProps(
<TextArea rows={3} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const EditModal = Form.create({})(Edit);
export default EditModal;
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../store';
import {
Form,
Input,
Button
} from 'antd';
const FormItem = Form.Item;
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
const { getAllScence } = store;
this.search();
getAllScence();
}
// 查询
search = () => {
this.props.form.validateFields((errors, values) => {
if (!!errors) {
return;
}
const { updateParams, getDataList } = store;
let params = {
name: values.name || '',
currentPage: 1
};
updateParams(params);
getDataList();
});
}
render() {
const { getFieldDecorator } = this.props.form;
let nameProps = getFieldDecorator('name');
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem
label="字段名称"
>
{nameProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
import { Modal, message } from 'antd';
const confirm = Modal.confirm;
class State {
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
pageSize: 10,
name: '',
currentPage: 1
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
let params = Object.assign({}, this.params);
common.fetch('/engineField/queryPage', params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
// 获取所有场景
@observable
sceneIdsArr = [];
// 获取table数据
@action
getAllScence = () => {
common.fetch('/engineScene/queryAllScene', {}, 'get')
.then(res => {
this.sceneIdsArr = res.data;
});
}
// 校验字段名称是否重复
@action
checkFieldName = (params, isEdit, name) => {
return new Promise((resolve) => {
common.fetch('/engineField/checkFieldByScene', {name: name}, 'post', {isJson: true})
.then(res => {
if (res.data === false) {
resolve();
isEdit ? this.updateFieldList(params) : this.addFieldList(params);
} else {
message.warning('字段名称已存在!');
}
});
});
}
// 添加字段
@action
addFieldList = (params) => {
common.fetch('/engineField/add', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 更新字段
@action
updateFieldList = (params) => {
return new Promise((resolve) => {
common.fetch('/engineField/update', params, 'post', {isJson: true})
.then(res => {
resolve();
this.getDataList();
});
});
}
// 删除字段
@action
deleteField = (name) => {
common.fetch('/engineField/delete', {name: name}, 'post', {isJson: true})
.then(res => {
common.handleSuccess('删除成功!');
this.getDataList();
});
}
// 校验该字段下有无关联规则
@action
checkIsRule = (id, name) => {
common.fetch('engineField/existCdt', {fieldId: id}, 'get')
.then(res => {
if (res.data === false) {
confirm({
title: '提示',
content: '确认删除?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
this.deleteField(name);
},
onCancel() {
console.log('you chose close!');
}
});
} else {
message.warning('字段已关联规则,无法删除!');
}
});
}
// 判断字段是否在用
@observable
isFieldArr = [];
@action
checkField = (params) => {
common.fetch('/engineField/getFieldUsed', params, 'get')
.then(res => {
this.isFieldArr = res.data;
});
}
@action
clearFieldArr = () => {
this.isFieldArr = [];
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Button } from 'antd';
import styles from './index.less';
import { observer } from 'mobx-react';
import store from '../store';
import EditModal from '../modals/editModal';
@observer
class ScenceTable extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRows: [],
editObj: [],
isEdit: false,
show: false
};
}
showModal = (isEdit, obj) => {
if (isEdit && obj.sceneNames !== null) {
const { checkField } = store;
let ids = [];
obj.sceneNames && obj.sceneNames.forEach(item => {
ids.push(item.id);
});
let params = {
fieldIds: ids
};
checkField(params);
}
this.setState({
isEdit: isEdit,
show: true,
editObj: obj
});
}
closeModal = () => {
store.clearFieldArr();
this.setState({
show: false
});
}
render() {
const columns = [{
title: '字段名称',
dataIndex: 'name',
key: 'name',
width: 150
}, {
title: '字段类型',
dataIndex: 'type',
key: 'type',
width: 150,
render: (text, record, index) => {
const type = text === '0' ? '数值' : '字符串';
return type || '-';
}
}, {
title: '场景',
dataIndex: 'sceneNames',
key: 'sceneNames',
width: 150,
render: (text, record, index) => {
let sceneArr = [];
let sceneNames = '';
record.sceneNames && record.sceneNames.forEach(item => {
sceneArr.push(item.sceneName);
});
sceneNames = sceneArr.join(', ');
return sceneNames || '-';
}
}, {
title: '描述',
dataIndex: 'description',
key: 'description',
width: 150
}, {
title: '最近更新人',
dataIndex: 'editor',
key: 'editor',
width: 150
}, {
title: '更新时间',
dataIndex: 'gmtModifiedView',
key: 'gmtModifiedView',
width: 150
}, {
title: '操作',
key: 'operates',
width: 150,
render: (text, record, index) => {
const { checkIsRule } = store;
return (
<div>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record); }}>编辑</a>
<a className={styles.link} onClick= {() => checkIsRule(record.id, record.name)}>删除</a>
</div>
);
}
}];
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const paganationOpts = {
defaultPageSize: 10,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
return (
<div>
<Button className={styles.newBotton} type="primary" htmlType="submit" onClick={() => this.showModal(false, {})}>新建字段</Button>
<Table
// scroll={{ x: 2900 }}
scroll={{ y: 500 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default ScenceTable;
.link {
color:#1890ff;
margin:0px 3px
}
.newBotton {
margin-bottom: 20px
}
\ No newline at end of file
import React from 'react';
class RuleEngine extends React.Component {
render() {
return (
<div>{ this.props.children }</div>
);
};
};
export default RuleEngine;
import React from 'react';
import {withRouter} from 'react-router';
import PageSearch from './search';
import ReportTable from './table';
class ruleEngine extends React.Component {
render() {
return (
<div>
<PageSearch />
<ReportTable />
</div>
);
}
};
export default withRouter(ruleEngine);
import React from 'react';
// import { observer } from 'mobx-react';
import styles from './index.less';
import {
DatePicker,
Form,
Input,
Select,
Button
} from 'antd';
import moment from 'moment';
const FormItem = Form.Item;
const Option = Select.Option;
const { RangePicker } = DatePicker;
const dateFormat = 'YYYY-MM-DD';
// 风险等级枚举
const cheatGradeArr = [];
const riskReviewerArr = [];
// @observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
time: [moment().subtract(1, 'days'), moment().subtract(0, 'days')]
};
}
componentDidMount() {
this.search();
}
// 查询
search = () => {}
render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
let orderProps = getFieldDecorator('slotId');
let userIdProps = getFieldDecorator('appId');
// 日期选择器
let timeProps = getFieldDecorator('time', {
initialValue: this.state.time
});
// 处理人
let scnceProps = getFieldDecorator('riskReviewer', {
initialValue: ''
});
// 作弊等级
let resultProps = getFieldDecorator('cheatGrade', {
initialValue: ''
});
// 初步处理结果
let equipmentIdProps = getFieldDecorator('preResult', {
initialValue: ''
});
// 媒体意见
let ipProps = getFieldDecorator('mediaDealOpinion', {
initialValue: ''
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem>
{timeProps(
<RangePicker
format={dateFormat}
/>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="场景"
>
{scnceProps(
<Select
style={{ width: '100px' }}
placeholder="Tags Mode"
>
{riskReviewerArr && riskReviewerArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="审核结果"
>
{resultProps(
<Select
style={{ width: '120px' }}
placeholder="Tags Mode"
>
{cheatGradeArr && cheatGradeArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem
{...formItemLayout}
label="订单号"
>
{orderProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="用户ID"
>
{userIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="设备ID"
>
{equipmentIdProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="IP地址"
>
{ipProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
\ No newline at end of file
import React from 'react';
import { Table } from 'antd';
class ReportTable extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const columns = [{
title: '订单号',
dataIndex: 'gmtCreate'
}, {
title: '场景',
dataIndex: 'curDate'
}, {
title: '用户ID',
dataIndex: 'appId'
}, {
title: '设备ID',
dataIndex: 'creditsScore',
render: (text, record, index) => {
return text || '-';
}
}, {
title: 'IP地址',
dataIndex: 'preRiskReviewer',
render: (text, record, index) => {
return record.preRiskReviewer || record.riskReviewer;
}
}, {
title: '审核结果'
}, {
title: '审批时间'
}];
let _dataSource;
const paganationOpts = {};
return (
<div>
<Table
// scroll={{ x: 2900 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
// loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
</div>
);
}
}
export default ReportTable;
import React from 'react';
import { observer } from 'mobx-react';
import common from 'src/lib/common';
import { Form, Input, Icon, Button, Select, Radio, Modal } from 'antd';
import store from '../store';
import styles from './flowAndScore.less';
const confirm = Modal.confirm;
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const Option = Select.Option;
const operationArr = [
{ value: 0, text: '>' },
{ value: 1, text: '<' },
{ value: 2, text: '=' },
{ value: 3, text: '>=' },
{ value: 4, text: '<=' },
{ value: 5, text: '≠' },
{ value: 6, text: '>and<=' },
{ value: 7, text: '>and<' },
{ value: 8, text: '>=and<' },
{ value: 9, text: '>=and<=' },
{ value: 10, text: '包含' },
{ value: 11, text: '不包含' }
];
let uuid = 1;
@observer
class FlowScoreForm extends React.Component {
remove = (k) => {
const { form } = this.props;
const conditions = form.getFieldValue('conditions');
if (conditions.length === 1) {
return;
}
if (k.threshold) {
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
form.setFieldsValue({
conditions: conditions.filter(key => key !== k)
});
},
onCancel() {
console.log('you chose close!');
}
});
} else {
form.setFieldsValue({
conditions: conditions.filter(key => key !== k)
});
}
}
add = () => {
const { form } = this.props;
const conditions = form.getFieldValue('conditions');
const nextConditions = conditions.concat(uuid);
++uuid;
form.setFieldsValue({
conditions: nextConditions
});
}
componentDidMount = () => {
if (this.props.editObj.id) {
let conditionsArr = [];
common.fetch(`/rules/${this.props.editObj.id}/conditions`, {}, 'get')
.then(res => {
conditionsArr = res.data;
this.props.form.setFieldsValue({
conditions: conditionsArr
});
});
}
}
render() {
const { fieldArr } = store;
const { getFieldDecorator, getFieldValue } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
}
};
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 4 }
}
};
const formExpressionLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const formThresholdLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 }
}
};
getFieldDecorator('conditions', { initialValue: getFieldValue('conditions') && getFieldValue('conditions').length > 0 ? getFieldValue('conditions') : [0] });
const conditions = getFieldValue('conditions');
const formItems = conditions.map((k, index) => {
if (typeof k === 'object') {
return (
<div key={k.id ? k.id : 'new' + k} className={styles.conditions}>
<FormItem className={styles.condition} style={{ width: '25%' }}>
{getFieldDecorator(`fieldId[${index}]`, {
initialValue: k.fieldId || fieldArr ? fieldArr[0].id : '',
rules: [{
required: true,
message: '请选择'
}]
})(
<Select
placeholder="请选择"
>
{fieldArr && fieldArr.map((d, index) => <Option key={index} value={d.id}>{d.name}</Option>)}
</Select>
)}
</FormItem>
<FormItem className={styles.condition}
style={{ width: '35%' }}
{...formExpressionLayout}
label="表达式:">
{getFieldDecorator(`operation[${index}]`, {
initialValue: k.operation || 0
})(
<Select
placeholder="请选择"
>
{operationArr && operationArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem className={styles.condition}
style={{ width: '30%' }}
{...formThresholdLayout}
label="值:">
{getFieldDecorator(`threshold[${index}]`, {
initialValue: k.threshold || '',
rules: [{
required: true,
message: '请选择'
}]
})(
<Input
className={styles.add_condition}
placeholder="请输入" />
)}
</FormItem>
<Icon
className={styles.dynamic_delete_button}
type="minus-circle-o"
disabled={conditions.length === 1}
onClick={() => this.remove(k)}
/>
</div>
);
}
return (
<div key={k.id ? k.id : 'new' + (k)} className={styles.conditions}>
<FormItem className={styles.condition} style={{ width: '25%' }}>
{getFieldDecorator(`new_fieldId[${k}]`, {
initialValue: k.fieldId || fieldArr ? fieldArr[0].id : '',
rules: [{
required: true,
message: '请选择'
}]
})(
<Select
placeholder="请选择"
>
{fieldArr && fieldArr.map((d, index) => <Option key={index} value={d.id}>{d.name}</Option>)}
</Select>
)}
</FormItem>
<FormItem className={styles.condition}
style={{ width: '35%' }}
{...formExpressionLayout}
label="表达式:">
{getFieldDecorator(`new_operation[${k}]`, {
initialValue: k.operation || 0
})(
<Select
placeholder="请选择"
>
{operationArr && operationArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)}
</FormItem>
<FormItem className={styles.condition}
style={{ width: '30%' }}
{...formThresholdLayout}
label="值:">
{getFieldDecorator(`new_threshold[${k}]`, {
initialValue: k.new_threshold || '',
rules: [{
required: true,
message: '请选择'
}]
})(
<Input
className={styles.add_condition}
placeholder="请输入" />
)}
</FormItem>
<Icon
className={styles.dynamic_delete_button}
type="minus-circle-o"
disabled={conditions.length === 1}
onClick={() => this.remove(k)}
/>
</div>
);
});
let nameProps = getFieldDecorator('name', {
initialValue: this.props.editObj.name || '',
rules: [{
required: true, message: '请输入!'
}, {
max: 30, message: '最多输入30个字符!'
}]
});
let decisionProps = this.props.type === '1' ? getFieldDecorator('decision', {
initialValue: this.props.editObj.decision || '',
rules: [{
required: true, pattern: /^[0-9]+$/, message: '请输入数字!'
}]
}) : null;
let modeProps = getFieldDecorator('mode', {
initialValue: this.props.editObj.mode || 0
});
return (
<Form>
<p className={styles.modalTitle}>基础属性</p>
<FormItem
{...formItemLayout}
label="规则名称"
>
{nameProps(
<Input type="text" style={{ width: '60%' }}/>
)}
</FormItem>
{this.props.type === '1' ? <FormItem
{...formItemLayout}
label="风险决策"
>
<div>{decisionProps(
<Input type="text" style={{ width: '40%', marginRight: 8 }}/>
)}</div>
</FormItem> : null}
<p className={styles.modalTitle}>条件配置</p>
<FormItem
{...formItemLayout}
label="命中模式"
>
{modeProps(
<RadioGroup>
<Radio value={0}>全部满足</Radio>
<Radio value={1}>满足任一</Radio>
</RadioGroup>
)}
</FormItem>
{formItems}
<FormItem {...formItemLayoutWithOutLabel}>
<Button
className={styles.addbutton}
onClick={this.add}
style={{ marginRight: 8 }}
type="dashed"
>新增</Button>
</FormItem>
</Form>
);
}
}
export default Form.create({})(FlowScoreForm);
.dynamic_delete_button {
cursor: pointer;
position: relative;
top: 9px;
left:-20px;
color: #999;
transition: all .3s;
}
.dynamic_delete_button:hover {
color: #777;
}
.dynamic_delete_button[disabled] {
cursor: not-allowed;
opacity: 0.5;
}
.add_condition {
margin-right: 10px!important
}
.conditions {
margin-left: 16%;
.condition{
display: inline-block;
margin-right: 8px
}
}
.addbutton {
height: 25px!important;
font-size: 12px!important;
}
.modalTitle {
font-weight: bold
}
\ No newline at end of file
import React from 'react';
import {withRouter} from 'react-router';
import PageSearch from './search';
import RuleTable from './table';
class ruleEngine extends React.Component {
render() {
return (
<div>
<PageSearch />
<RuleTable />
</div>
);
}
};
export default withRouter(ruleEngine);
import React from 'react';
import { observer } from 'mobx-react';
import { transaction } from 'mobx';
import {
Modal,
Button
} from 'antd';
import FlowScoreForm from '../forms/flowAndScore';
import store from '../store';
@observer
class EditModal extends React.Component {
trans2arr(arr) {
return arr && arr.filter(item => item !== undefined || item !== null);
}
handleOk = () => {
const {
checkRuleName,
formRef
} = store;
const { form } = formRef.props;
const { validateFields } = form;
validateFields((errors, values) => {
if (errors) {
console.log(errors);
} else {
const fieldIdArr = values.fieldId ? values.fieldId.concat(this.trans2arr(values.new_fieldId)) : this.trans2arr(values.new_fieldId);
const operationArr = values.operation ? values.operation.concat(this.trans2arr(values.new_operation)) : this.trans2arr(values.new_operation);
const thresholdArr = values.threshold ? values.threshold.concat(this.trans2arr(values.new_threshold)) : this.trans2arr(values.new_threshold);
const conditionsArr = [];
for (let i = 0; i < values.conditions.length; i++) {
conditionsArr.push({fieldId: fieldIdArr[i], operation: operationArr[i], threshold: thresholdArr[i]});
}
let params = {
id: this.props.editObj.id ? this.props.editObj.id : '',
name: values.name,
decision: values.decision ? values.decision : '',
mode: values.mode,
status: 0,
type: parseInt(this.props.type),
conditions: conditionsArr.slice()
};
let isEdit = this.props.isEdit;
transaction(() => {
// 保存数据,设置内容为已改变并且隐藏弹窗
checkRuleName(params, isEdit).then(this.props.closeModal);
});
}
});
}
handleCancel = () => {
this.props.closeModal();
};
render() {
const { saveFormRef } = store;
return (
<Modal
title={ this.props.isEdit ? '编辑规则' : '新建规则'}
width={700}
visible={true}
maskClosable={false}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="保存"
cancelText="取消"
footer={[
<Button key="back" onClick={this.handleCancel}>取消</Button>,
<Button key="submit" type="primary" onClick={this.handleOk}>保存</Button>
]}
>
<FlowScoreForm editObj={this.props.editObj} type={this.props.type} wrappedComponentRef={saveFormRef}/>
</Modal>
);
}
}
export default EditModal;
import React from 'react';
// import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../store';
import {
Form,
Input,
Button,
Icon
} from 'antd';
const FormItem = Form.Item;
// @observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
const { getFieldList } = store;
this.search();
getFieldList();
}
// 查询
search = () => {
this.props.form.validateFields((errors, values) => {
if (!!errors) {
return;
}
const { updateParams, getDataList } = store;
let params = {
ruleName: values.ruleName || '',
currentPage: 1
};
updateParams(params);
getDataList();
});
}
render() {
const { getFieldDecorator } = this.props.form;
let ruleNameProps = getFieldDecorator('ruleName');
return (
<div className={styles.search_warp}>
<h2 className={styles.search_header}><a href={`#/ruleEngine/strategy`} className={styles.goback}><Icon type="left" /></a><span>规则管理</span></h2>
<Form layout="inline" >
<FormItem
label="规则名"
>
{ruleNameProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
.search_header {
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #ccc
}
.goback {
margin-right: 10px
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
import utils from 'src/lib/utils';
import { message } from 'antd';
class State {
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
pageSize: 10,
ruleName: '',
strategyId: '',
currentPage: 1
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
let strategyId = utils.getURLParameter('strategyId');
let params = Object.assign({}, this.params);
params.strategyId = strategyId;
common.fetch('/rules', params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
// 字段数据
@observable
fieldArr = [];
// 获取字段数据
@action
getFieldList = () => {
let sceneId = utils.getURLParameter('sceneId');
common.fetch('/engineField/getFieldBySceneId', {sceneId: sceneId}, 'get')
.then(res => {
this.fieldArr = res.data;
});
}
// 规则名称在同一策略下是否重复
@action
checkRuleName = (params, isEdit) => {
let strategyId = utils.getURLParameter('strategyId');
params.strategyId = strategyId;
let params1 = {
ruleName: params.name,
strategyId: strategyId,
ruleId: params.id
};
return new Promise((resolve) => {
common.fetch('/rules/exist', params1, 'get')
.then(res => {
if (res.data === false) {
resolve(res);
isEdit ? this.updateRuleList(params) : this.addRuleList(params);
} else {
message.warning('规则名已存在!');
}
});
});
}
// 添加规则
@action
addRuleList = (params) => {
let strategyId = utils.getURLParameter('strategyId');
params.strategyId = strategyId;
common.fetch('/rules', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 编辑规则
@action
updateRuleList = (params) => {
let strategyId = utils.getURLParameter('strategyId');
params.strategyId = strategyId;
common.fetch('/rules', params, 'put', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 更新状态
@action
updateStatus = (params) => {
common.fetch(`/rules/${params.id}/${params.status}`, params, 'put', {isJson: false})
.then(res => {
this.getDataList();
});
}
// 删除规则
@action
deleteRule = (id) => {
common.fetch(`/rules/${id}`, {id: id}, 'delete', {isJson: true})
.then(res => {
common.handleSuccess('删除成功!');
this.getDataList();
});
}
// 新增/编辑表单ref
@observable
formRef = {};
// 保存新增编辑表单ref
@action
saveFormRef = (formRef) => {
this.formRef = formRef;
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Dropdown, Button, Modal, Icon, Menu } from 'antd';
import { observer } from 'mobx-react';
import EditModal from '../modals/editModal';
import store from '../store';
import styles from './index.less';
const confirm = Modal.confirm;
@observer
class RuleTable extends React.Component {
constructor(props) {
super(props);
this.state = {
editObj: [],
isEdit: false,
show: false,
type: 0
};
}
showModal = (isEdit, obj, type) => {
this.setState({
isEdit: isEdit,
show: true,
editObj: obj,
type: type
});
}
closeModal = () => {
this.setState({
show: false
});
}
delCase = (id) => {
const { deleteRule } = store;
confirm({
title: '提示',
content: '确认删除?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
deleteRule(id);
},
onCancel() {
console.log('you chose close!');
}
});
}
changeStatus(id, status) {
const { updateStatus } = store;
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
let params = {
id: id,
status: status
};
updateStatus(params);
},
onCancel() {
console.log('you chose close!');
}
});
}
render() {
const columns = [{
title: '规则名称',
dataIndex: 'name',
key: 'name',
width: 150,
render: (text, record, index) => {
const isIndent = record.parentRuleId ? <span className={styles.indent}>{text}</span> : text;
return isIndent;
}
}, {
title: '备注',
dataIndex: 'description',
key: 'description',
width: 150
}, {
title: '状态',
dataIndex: 'status',
key: 'status',
width: 150,
render: (text, record, index) => {
const status = text === 0 ? '启用' : text === 1 ? '禁用' : '试运行';
return status;
}
}, {
title: '操作',
key: 'operates',
width: 150,
render: (text, record, index) => {
const statusMenu = (
<Menu onClick= {(e) => { this.changeStatus(record.id, e.key); }}>
<Menu.Item key="0">启用</Menu.Item>
<Menu.Item key="1">禁用</Menu.Item>
<Menu.Item key="2">试运行</Menu.Item>
</Menu>
);
return (
<div>
{record.type === 0 && record.parentRuleId === null ? <a className={styles.link} onClick= {(e) => { this.showModal(false, {}, record.type); }}>+子规则</a> : <span className={styles.empty}></span>}
<Dropdown overlay={statusMenu} trigger={['click']}>
<a className={styles.link}>
状态 <Icon type="down" />
</a>
</Dropdown>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record, record.type.toString()); }}>编辑</a>
<a className={styles.link} onClick= {() => this.delCase(record.id)}>删除</a>
</div>
);
}
}];
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const paganationOpts = {
defaultPageSize: 10,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
const menu = (
<Menu onClick= {(e) => { this.showModal(false, {}, e.key); }}>
<Menu.Item key="0">流程规则</Menu.Item>
<Menu.Item key="1">评分规则</Menu.Item>
</Menu>
);
return (
<div>
<Dropdown className={styles.newBotton} overlay={menu} trigger={['click']}>
<Button style={{ marginLeft: 8 }}>
新建规则 <Icon type="down" />
</Button>
</Dropdown>
<Table
// scroll={{ x: 2900 }}
scroll={{ y: 500 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} type={this.state.type} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default RuleTable;
.link {
color:#1890ff;
margin:0px 3px
}
.indent {
padding-left: 40px
}
.empty {
padding: 0 29px;
}
.newBotton {
margin-bottom: 20px
}
\ No newline at end of file
import React from 'react';
import {withRouter} from 'react-router';
import PageSearch from './search';
import ScenceTable from './table';
class ruleEngine extends React.Component {
render() {
return (
<div>
<PageSearch />
<ScenceTable />
</div>
);
}
};
export default withRouter(ruleEngine);
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import {
Form,
Input,
Modal,
Select
} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
let TextArea = Input.TextArea;
const sceneTypeArr = [
{ value: 0, text: '实时场景' },
{ value: 1, text: '准实时场景' }
];
@observer
class Edit extends React.Component {
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { checkSceneName } = store;
const { getFieldValue } = this.props.form;
let params = {
sceneName: getFieldValue('sceneName'),
sceneKey: getFieldValue('sceneKey'),
sceneType: parseInt(getFieldValue('sceneType')),
description: getFieldValue('description'),
gmtCreate: this.props.editObj.gmtCreate || '',
creator: this.props.editObj.creator || '',
id: this.props.editObj.id
};
let isEdit = this.props.isEdit;
checkSceneName(params, isEdit).then(this.props.closeModal);
}
});
};
handleCancel = () => {
this.props.closeModal();
};
render() {
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const { getFieldDecorator } = this.props.form;
// 场景名称
let sceneNameProps = getFieldDecorator('sceneName', {
initialValue: this.props.editObj.sceneName || '',
rules: [{
required: true, message: '请输入!'
}, {
max: 30, message: '最多输入30个字符!'
}]
});
// 场景标识
let sceneKeyProps = getFieldDecorator('sceneKey', {
initialValue: this.props.editObj.sceneKey || '',
rules: [{
required: true, message: '请输入!'
}]
});
// 场景类型
let sceneTypeProps = getFieldDecorator('sceneType', {
initialValue: typeof this.props.editObj.sceneType === 'undefined' ? 0 : this.props.editObj.sceneType,
rules: [{
required: true, message: '请输入!'
}]
});
// 描述
let descriptionProps = getFieldDecorator('description', {
initialValue: this.props.editObj.description || '',
rules: [{
max: 64, message: '最多输入64个字符!'
}]
});
return (
<div>
<Modal
title={ this.props.isEdit ? '编辑场景' : '新建场景'}
width={400}
visible={true}
maskClosable={false}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="保存"
cancelText="取消"
>
<Form>
<FormItem
{...formItemLayout}
label="场景名称"
>
{sceneNameProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="场景标识"
>
{sceneKeyProps(
<Input disabled={this.props.isEdit} type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="场景类型"
>
{
sceneTypeProps(
<Select
style={{ width: '100%' }}
placeholder="Tags Mode"
>
{sceneTypeArr && sceneTypeArr.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
)
}
</FormItem>
<FormItem
{...formItemLayout}
label="描述:"
>
{descriptionProps(
<TextArea rows={3} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const EditModal = Form.create({})(Edit);
export default EditModal;
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import styles from './index.less';
import {
Form,
Input,
Button
} from 'antd';
const FormItem = Form.Item;
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
this.search();
}
// 查询
search = () => {
this.props.form.validateFields((errors, values) => {
if (!!errors) {
return;
}
const { updateParams, getDataList } = store;
let params = {
sceneName: values.sceneName || '',
currentPage: 1
};
updateParams(params);
getDataList();
});
}
render() {
const { getFieldDecorator } = this.props.form;
let sceneNameProps = getFieldDecorator('sceneName');
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem
label="场景"
>
{sceneNameProps(
<Input type="text" />
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
import { Modal, message } from 'antd';
const confirm = Modal.confirm;
class State {
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
pageSize: 10,
sceneName: '',
currentPage: 1
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
let params = Object.assign({}, this.params);
common.fetch('/engineScene/queryPage', params, 'get')
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
// 场景名称重复判断
@action
checkSceneName = (params, isEdit) => {
const name = params.sceneName;
const id = params.id ? params.id : '';
return new Promise((resolve) => {
common.fetch('/engineScene/checkSceneKeyOrName', {sceneName: name, id: id}, 'get')
.then(res => {
if (res.data === false) {
isEdit ? (resolve(res) || this.updateScenceList(params)) : this.checkSceneKey(params, isEdit).then(resolve);
} else {
message.warning('场景名称已存在!');
}
});
});
}
// 场景标识重复判断
@action
checkSceneKey = (params, isEdit) => {
const key = params.sceneKey;
return new Promise(resolve => {
common.fetch('/engineScene/checkSceneKeyOrName', {sceneKey: key}, 'get')
.then(res => {
if (res.data === false) {
resolve();
this.addScenceList(params);
} else {
message.warning('场景标识已存在!');
}
});
});
}
// 添加场景
@action
addScenceList = (params) => {
common.fetch('/engineScene/add', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 更新场景
@action
updateScenceList = (params) => {
common.fetch('/engineScene/update', params, 'post', {isJson: true})
.then(res => {
this.getDataList();
});
}
// 删除场景
@action
deleteScence = (id) => {
common.fetch('/engineScene/delete', {id: id}, 'post', {isJson: true})
.then(res => {
common.handleSuccess('删除成功!');
this.getDataList();
});
}
// 校验该场景下有无关联策略
@action
checkStrategy = (id) => {
common.fetch('/engineScene/checkStrategy', {id: id}, 'get')
.then(res => {
if (res.data === false) {
this.checkField(id);
// confirm({
// title: '提示',
// content: '确认修改?',
// okText: '确定',
// okType: 'danger',
// cancelText: '取消',
// onOk: () => {
// this.deleteScence(id);
// },
// onCancel() {
// console.log('you chose close!');
// }
// });
} else {
message.warning('场景下已关联策略,无法删除!');
}
});
}
// 校验该场景下有无关联字段
@action
checkField = (id) => {
common.fetch('/engineScene/checkField', {id: id}, 'get')
.then(res => {
if (res.data === false) {
confirm({
title: '提示',
content: '确认删除?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
this.deleteScence(id);
},
onCancel() {
console.log('you chose close!');
}
});
} else {
message.warning('场景下已关联字段,无法删除!');
}
});
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Button } from 'antd';
import { observer } from 'mobx-react';
import store from '../store';
import EditModal from '../modals/editModal';
import styles from './index.less';
@observer
class ScenceTable extends React.Component {
constructor(props) {
super(props);
this.state = {
// 储存当前选中的行
selectedRows: [],
editObj: [],
isEdit: false,
show: false
};
}
showModal = (isEdit, obj) => {
this.setState({
isEdit: isEdit,
show: true,
editObj: obj
});
}
closeModal = () => {
this.setState({
show: false
});
}
render() {
const columns = [{
title: '场景名称',
dataIndex: 'sceneName',
key: 'sceneName',
width: 150
}, {
title: '场景标识',
dataIndex: 'sceneKey',
key: 'sceneKey',
width: 150
}, {
title: '场景类型',
dataIndex: 'sceneType',
key: 'sceneType',
width: 150,
render: (text, record, index) => {
const sceneType = text === 0 ? '实时场景' : '准实时场景';
return sceneType || '-';
}
}, {
title: '描述',
dataIndex: 'description',
key: 'description',
width: 150
}, {
title: '创建人',
dataIndex: 'creator',
key: 'creator',
width: 150,
render: (text, record, index) => {
return text || '-';
}
}, {
title: '更新时间',
dataIndex: 'gmtModifiedView',
key: 'gmtModifiedView',
width: 150
}, {
title: '操作',
key: 'operates',
width: 150,
render: (text, record, index) => {
const { checkStrategy } = store;
return (
<div>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record); }}>编辑</a>
<a className={styles.link} onClick= {() => checkStrategy(record.id)}>删除</a>
</div>
);
}
}];
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const paganationOpts = {
defaultPageSize: 10,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
return (
<div>
<Button className={styles.newBotton} type="primary" htmlType="submit" onClick={() => this.showModal(false, {})}>新建场景</Button>
<Table
// scroll={{ x: 2900 }}
scroll={{ y: 500 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default ScenceTable;
.link {
color:#1890ff;
margin:0px 3px
}
.newBotton {
margin-bottom: 20px
}
\ No newline at end of file
import React from 'react';
import {withRouter} from 'react-router';
import PageSearch from './search';
import StrategyTable from './table';
class ruleEngine extends React.Component {
render() {
return (
<div>
{ this.props.children ? this.props.children : <div>
<PageSearch />
<StrategyTable /></div>
}
</div>
);
}
};
export default withRouter(ruleEngine);
import React from 'react';
import { observer } from 'mobx-react';
import store from '../store';
import {
Form,
Input,
Modal,
Select,
Slider
} from 'antd';
import styles from './editModal.less';
const FormItem = Form.Item;
const Option = Select.Option;
let TextArea = Input.TextArea;
@observer
class Edit extends React.Component {
handleOk = () => {
this.props.form.validateFields((err, values) => {
if (!err) {
const { checkStrategyKeyOrName, checkStrategyName, saveStrategyList } = store;
const { getFieldValue } = this.props.form;
let params = {
strategyName: getFieldValue('strategyName'),
strategyKey: getFieldValue('strategyKey'),
strategyType: 0,
sceneId: getFieldValue('sceneId'),
score1: parseInt(getFieldValue('score1')),
score2: parseInt(getFieldValue('score2')),
score3: parseInt(getFieldValue('score3')),
score4: parseInt(getFieldValue('score4')),
status: 1,
description: getFieldValue('description')
};
if ((getFieldValue('strategyName') !== this.props.editObj.strategyName) && this.props.isEdit) {
checkStrategyName(params, values.strategyName).then(this.props.closeModal);
} else if (this.props.isEdit) {
saveStrategyList(params).then(this.props.closeModal);
}
if (!this.props.isEdit) {
let addParams = {
strategyName: params.strategyName,
strategyKey: params.strategyKey
};
checkStrategyKeyOrName(params, addParams).then(this.props.closeModal);
}
}
});
};
handleCancel = () => {
this.props.closeModal();
};
// 自定义校验
checkConfirm = (rule, value, callback, i) => {
const { getFieldValue } = this.props.form;
if (getFieldValue(`score${i}`) > getFieldValue(`score${i + 1}`)) {
callback('输入了不合法的数值!');// eslint-disable-line
}
if (getFieldValue(`score${i}`) < getFieldValue(`score${i - 1}`)) {
callback('输入了不合法的数值!');// eslint-disable-line
}
callback();
}
render() {
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 }
}
};
const { getFieldDecorator } = this.props.form;
const { sceneIdsArr } = store;
// 策略名称
let strategyNameProps = getFieldDecorator('strategyName', {
initialValue: this.props.editObj.strategyName || '',
rules: [{
required: true, message: '请输入!'
}, {
max: 30, message: '最多输入30个字符!'
}]
});
// 策略标识
let strategyKeyProps = getFieldDecorator('strategyKey', {
initialValue: this.props.editObj.strategyKey || '',
rules: [{
required: true, message: '请输入!'
}]
});
// 关联场景
let sceneTypeProps = getFieldDecorator('sceneId', {
initialValue: this.props.editObj.sceneId || (sceneIdsArr.length ? sceneIdsArr[0].id : ''),
rules: [{
required: true, message: '请输入!'
}]
});
// 阈值
let score1Props = getFieldDecorator('score1', {
initialValue: this.props.editObj.score1,
rules: [{
required: true, pattern: /^[0-9]+$/, message: '请输入数字!'
}, { validator: (rule, value, callback) => { return this.checkConfirm(rule, value, callback, 1); } }]
});
let score2Props = getFieldDecorator('score2', {
initialValue: this.props.editObj.score2,
rules: [{
required: true, pattern: /^[0-9]+$/, message: '请输入数字!'
}, { validator: (rule, value, callback) => { return this.checkConfirm(rule, value, callback, 2); } }]
});
let score3Props = getFieldDecorator('score3', {
initialValue: this.props.editObj.score3,
rules: [{
required: true, pattern: /^[0-9]+$/, message: '请输入数字!'
}, { validator: (rule, value, callback) => { return this.checkConfirm(rule, value, callback, 3); } }]
});
let score4Props = getFieldDecorator('score4', {
initialValue: this.props.editObj.score4,
rules: [{
required: true, pattern: /^[0-9]+$/, message: '请输入数字!'
}, { validator: (rule, value, callback) => { return this.checkConfirm(rule, value, callback, 4); } }]
});
// 描述
let descriptionProps = getFieldDecorator('description', {
initialValue: this.props.editObj.description || '',
rules: [{
max: 64, message: '最多输入64个字符!'
}]
});
return (
<div>
<Modal
title={ this.props.isEdit ? '编辑策略' : '新建策略'}
width={450}
visible={true}
maskClosable={false}
onOk={this.handleOk}
onCancel={this.handleCancel}
okText="保存"
cancelText="取消"
>
<Form>
<FormItem
{...formItemLayout}
label="策略名称"
>
{strategyNameProps(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="策略标识"
>
{strategyKeyProps(
<Input disabled={this.props.isEdit} type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="关联场景"
>
{
sceneTypeProps(
<Select
style={{ width: '100%' }}
placeholder="请选择"
>
{sceneIdsArr && sceneIdsArr.map((d, index) => <Option key={index} value={d.id}>{d.sceneName}</Option>)}
</Select>
)
}
</FormItem>
<div className={styles.steps}>
<div className={styles.tips}><span>通过</span><span>人审</span><span>拒绝</span></div>
<Slider className={styles.step} step={5} range min={0} disabled={true} max={5} tipFormatter={null} defaultValue={[0, 5]} />
<Slider className={styles.step} step={5} min={0} disabled={true} max={5} tipFormatter={null} defaultValue={5} />
<Slider className={styles.step} step={5} min={0} disabled={true} max={5} tipFormatter={null} defaultValue={5} />
</div>
<FormItem className={`${styles.score_block} ${styles.fir_score_block}`}>
{score1Props(
<Input type="text" />
)}
</FormItem>
<FormItem className={styles.score_block}>
{score2Props(
<Input type="text" />
)}
</FormItem>
<FormItem className={styles.score_block}>
{score3Props(
<Input type="text" />
)}
</FormItem>
<FormItem className={styles.score_block}>
{score4Props(
<Input type="text" />
)}
</FormItem>
<FormItem
{...formItemLayout}
label="描述:"
>
{descriptionProps(
<TextArea rows={3} />
)}
</FormItem>
</Form>
</Modal>
</div>
);
}
}
const EditModal = Form.create({})(Edit);
export default EditModal;
.steps {
margin-left: 33%;
.tips {
margin-bottom: -10px;
span {
margin: 0 20px;
}
}
.step {
display: inline-block;
width: 24%;
margin-left: -1px;
margin-bottom: -1px
}
}
.score_block {
display:inline-block!important;
width: 15%;
margin-right: 8px
}
.fir_score_block {
margin-left: 25%
}
.ant-slider-disabled {
cursor: pointer!important
}
\ No newline at end of file
import React from 'react';
import { observer } from 'mobx-react';
import styles from './index.less';
import store from '../store';
import {
Form,
Button,
Select
} from 'antd';
const FormItem = Form.Item;
const Option = Select.Option;
@observer
class SearchFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount() {
const { getAllScence } = store;
this.search();
getAllScence();
}
// 查询
// 查询
search = () => {
const { updateParams, getDataList } = store;
const { getFieldValue } = this.props.form;
let params = {
sceneId: getFieldValue('sceneId'),
currentPage: 1
};
updateParams(params);
getDataList();
}
render() {
const { getFieldDecorator } = this.props.form;
const { sceneIdsArr } = store;
let arr = sceneIdsArr.slice();
arr.unshift({id: null, sceneName: '全部'});
// 场景类型
let sceneIdProps = getFieldDecorator('sceneId', {
initialValue: null
});
return (
<div className={styles.search_warp}>
<Form layout="inline" >
<FormItem
label="场景"
>
{sceneIdProps(
<Select
style={{ width: '120px' }}
placeholder="请选择"
>
{arr && arr.map((d, index) => <Option key={index} value={d.id}>{d.sceneName}</Option>)}
</Select>
)}
</FormItem>
<FormItem>
<Button
type="primary"
htmlType="submit"
onClick={this.search}
>
查询
</Button>
</FormItem>
</Form>
</div>
);
}
}
const PageSearch = Form.create({})(SearchFilter);
export default PageSearch;
.search_warp {
margin-bottom: 20px;
}
.search::placeholder{ /*WebKit browsers*/
text-align: center;
}
\ No newline at end of file
import { observable, action } from 'mobx';
import common from 'src/lib/common';
import { Modal, message } from 'antd';
const confirm = Modal.confirm;
class State {
@observable
dataIsLoading = false;
// 请求参数
@observable
params = {
pageSize: 10,
sceneId: '',
currentPage: 1
};
// 更新params
@action
updateParams = (params) => {
this.params = Object.assign({}, this.params, params);
}
// table数据
@observable
dataList = {
list: []
};
// 获取table数据
@action
getDataList = () => {
this.dataIsLoading = true;
let params = Object.assign({}, this.params);
common.fetch('/strategy/list', params, 'get', {content: {deleteNullAndUndefinedParams: true}})
.then(res => {
this.dataIsLoading = false;
this.dataList = res.data || ({
list: []
});
});
}
// 获取所有场景
@observable
sceneIdsArr = [];
// 获取table数据
@action
getAllScence = () => {
common.fetch('/engineScene/queryAllScene', {}, 'get')
.then(res => {
this.sceneIdsArr = res.data;
});
}
// 编辑 策略名称重复判断
@action
checkStrategyName = (params, strategyName) => {
return new Promise((resolve) => {
common.fetch('/strategy/exists', {strategyName: strategyName}, 'get')
.then(res => {
if (res.data === 'Not exists') {
resolve(res);
this.saveStrategyList(params);
} else {
message.warning(res.data);
}
});
});
}
// 新增 策略名称,策略标识重复判断
@action
checkStrategyKeyOrName = (params, addParams) => {
return new Promise((resolve) => {
common.fetch('/strategy/exists', addParams, 'get')
.then(res => {
if (res.data === 'Not exists') {
resolve(res);
this.saveStrategyList(params);
} else {
message.warning(res.data);
}
});
});
}
// 添加/更新策略
@action
saveStrategyList = (params) => {
return new Promise((resolve) => {
common.fetch('/strategy/save', params, 'post', {isJson: true})
.then(res => {
resolve(res);
this.getDataList();
});
});
}
// 删除策略
@action
deleteStrategy = (key) => {
common.fetch('/strategy/delete', {key: key}, 'post', {isJson: true})
.then(res => {
common.handleSuccess('删除成功!');
this.getDataList();
});
}
// 校验该策略下有无关联规则
@action
checkIsRule = (key) => {
common.fetch('/strategy/hasRule', {strategyKey: key}, 'get')
.then(res => {
if (res.data === false) {
confirm({
title: '提示',
content: '确认删除?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk: () => {
this.deleteStrategy(key);
},
onCancel() {
console.log('you chose close!');
}
});
} else {
message.warning('策略下已关联规则,无法删除!');
}
});
}
}
const store = new State();
export default store;
import React from 'react';
import { Table, Dropdown, Button, Modal, Menu, Icon } from 'antd';
import { observer } from 'mobx-react';
import EditModal from '../modals/editModal';
import moment from 'moment';
import store from '../store';
import styles from './index.less';
const confirm = Modal.confirm;
@observer
class StrategyTable extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRows: [],
editObj: [],
isEdit: false,
show: false
};
}
showModal = (isEdit, obj) => {
this.setState({
isEdit: isEdit,
show: true,
editObj: obj
});
}
closeModal = () => {
this.setState({
show: false
});
}
changeStatus(record, status) {
const { saveStrategyList } = store;
confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
let params = {
description: record.description,
sceneId: record.sceneId,
score1: record.score1,
score2: record.score2,
score3: record.score3,
score4: record.score4,
strategyKey: record.strategyKey,
strategyName: record.strategyName,
strategyType: record.strategyType,
status: parseInt(status)
};
saveStrategyList(params);
},
onCancel() {
console.log('you chose close!');
}
});
}
render() {
const columns = [{
title: '策略名称',
dataIndex: 'strategyName',
key: 'strategyName',
width: 150,
render: (text, record, index) => {
return (
<a href={`#/ruleEngine/strategy/rule?strategyId=${record.id}&sceneId=${record.sceneId}`}>
<p>{ text }</p>
</a>
);
}
}, {
title: '策略标识',
dataIndex: 'strategyKey',
key: 'strategyKey',
width: 150
}, {
title: '关联场景',
dataIndex: 'sceneName',
key: 'sceneName',
width: 150,
render: (text, record, index) => {
return text || '-';
}
}, {
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text, record, index) => {
const status = text === 1 ? '启用' : '禁用';
return status || '-';
}
}, {
title: '描述',
dataIndex: 'description',
key: 'description',
width: 150,
render: (text, record, index) => {
return text || '-';
}
}, {
title: '最近更新人',
dataIndex: 'editor',
key: 'editor',
width: 100
}, {
title: '更新时间',
dataIndex: 'gmtModified',
key: 'gmtModified',
width: 150,
render: (text, record, index) => {
const updateTime = moment(text).format('YYYY-MM-DD HH:mm:ss');
return updateTime || '-';
}
}, {
title: '操作',
key: 'operates',
width: 150,
render: (text, record, index) => {
const statusMenu = (
<Menu onClick={(e) => { this.changeStatus(record, e.key); }}>
<Menu.Item key="1">启用</Menu.Item>
<Menu.Item key="0">禁用</Menu.Item>
</Menu>
);
const { checkIsRule } = store;
return (
<div>
<Dropdown overlay={statusMenu} trigger={['click']}>
<a className={styles.link}>
状态 <Icon type="down" />
</a>
</Dropdown>
<a className={styles.link} onClick= {(e) => { this.showModal(true, record); }}>编辑</a>
<a className={styles.link} onClick= {() => checkIsRule(record.strategyKey)}>删除</a>
</div>
);
}
}];
const { dataIsLoading, dataList } = store;
let _dataSource = dataList.list ? dataList.list.slice() : [];
const paganationOpts = {
defaultPageSize: 10,
current: store.params.currentPage,
total: dataList.totalCount,
showTotal: (total) => { return `共${total}条`; },
onChange: page => {
const { getDataList, updateParams } = store;
updateParams({currentPage: page});
getDataList();
}
};
return (
<div>
<Button className={styles.newBotton} type="primary" htmlType="submit" onClick={() => this.showModal(false, {})}>新建策略</Button>
<Table
// scroll={{ x: 2900 }}
scroll={{ y: 500 }}
rowKey="id"
columns={columns}
dataSource={_dataSource}
pagination={true}
pagination={paganationOpts}
loading={dataIsLoading}
locale={{ emptyText: '暂无数据' }}
/>
{this.state.show ? <EditModal editObj={this.state.editObj} isEdit={this.state.isEdit} closeModal={this.closeModal}/> : null}
</div>
);
}
}
export default StrategyTable;
.link {
color:#1890ff;
margin:0px 3px
}
.newBotton {
margin-bottom: 20px
}
\ No newline at end of file
import React from 'react';
import ReactDom from 'react-dom';
import { LocaleProvider } from 'antd';
import zhCN from 'antd/lib/locale-provider/zh_CN';
import {
Router,
hashHistory
} from 'react-router';
import rootRoute from '../routes';
ReactDom.render((
<LocaleProvider locale={zhCN}>
<Router history={hashHistory} routes={rootRoute} />
</LocaleProvider>
), document.querySelector('#app'));
import React from 'react';
import { observer } from 'mobx-react';
import common from 'src/lib/common';
import store from '../../../store';
import {
Icon,
Upload,
Modal
} from 'antd';
const url = '/upload/uploadImg';
@observer
class PicturesWall extends React.Component {
constructor(props) {
super(props);
this.state = {
previewVisible: false,
previewImage: props.value
};
}
// 上传前进行检查
handleBeforeUpload = (file, fileList) => {
const { width, height, fileLimit } = this.props;
const imgTypeSize = {
width: parseInt(width, 10) || undefined,
height: parseInt(height, 10) || undefined
};
// 检查文件是否是图片
if (!this.checkIsImage(file)) {
common.handleError('上传的必须是jpg, jpeg, png类型的图片');
return false;
}
// 检查文件大小是否超过限制
if (!this.checkFileLimit(file)) {
const fileLimitText = fileLimit >= (1 * 1024 * 1024) ? `${(fileLimit / 1024 / 1024)}MB` : `${(fileLimit / 1024)}KB`;
common.handleError(`图片必须小于${fileLimitText}`);
return false;
}
// 检查文件尺寸是否超过限制
return this.checkImageSize(file, imgTypeSize);
}
handleChange = (file) => {
const { updatePhoto } = store;
let fileList = file.fileList;
if (file.file.status === 'done') {
const res = file.file.response;
if (res['code'] === '0') {
common.handleSuccess('上传图片成功');
updatePhoto(fileList);
return;
} else {
common.handleError(res['desc']);
}
} else if (file.file.status === 'error') {
common.handleError('上传图片请求出错,请稍候重试');
}
updatePhoto(fileList);
}
// 处理预览框取消事件
handleCancel = () => this.setState({ previewVisible: false })
// 处理预览按钮点击事件
handlePreview = (file) => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true
});
}
handleRemove = (file) => {
const { deletePhoto } = store;
let id;
if (!file.response) {
id = file.uid;
} else {
id = 1;
}
let params = {
id: -id
};
return new Promise((resolve, reject) => {
Modal.confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
deletePhoto(params.id).then(resolve());
},
onCancel() {
console.log('you chose close!');
resolve(false);
}
});
});
}
// 校验图片的大小是否合规
checkImageSize = (file, imgTypeSize) => {
return new Promise(function(resolve, reject) {
function check(width, height) {
if (
(width === imgTypeSize.width || !imgTypeSize.width) &&
(height === imgTypeSize.height || !imgTypeSize.height)
) {
resolve(file);
} else {
common.handleError(
'图片大小不对,要求尺寸为' +
(imgTypeSize.width || '宽度不限') +
'*' +
(imgTypeSize.height || '高度不限') +
' 像素'
);
}
}
// 读取图片数据
if (typeof window.FileReader === 'function') {
// 读取图片数据
const reader = new window.FileReader();
reader.onload = function(e) {
const data = e.target.result;
// 加载图片获取图片真实宽度和高度
const image = new window.Image();
image.onload = function() {
const width = image.width;
const height = image.height;
check(width, height);
};
image.src = data;
};
reader.readAsDataURL(file);
} else {
common.handleError('你的浏览器不支持图片大小判断,请更换现代浏览器,例如Chrome');
}
});
}
// 限制文件格式为图片
checkIsImage = (file) => {
const fileName = file.name;
return !!fileName.match(/.jpg|.jpeg|.png/);
}
// 限制文件大小
checkFileLimit = (file) => {
const { fileLimit } = this.props;
if (!fileLimit) {
return true;
}
return fileLimit > file.size;
}
render() {
const { uploadButtonText = '上传图片' } = this.props;
const { previewVisible, previewImage } = this.state;
const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">{uploadButtonText}</div>
</div>
);
const { fileList } = store;
let imgList = [];
fileList && fileList.forEach(item => {
if (item.status) {
imgList.push(item);
} else {
let obj = {};
obj.uid = -item.id;
obj.name = item.imgUrl;
obj.url = item.imgUrl;
obj.status = 'done';
imgList.push(obj);
}
});
return (
<div className="clearfix">
<Upload
action={url}
listType="picture-card"
beforeUpload={this.handleBeforeUpload}
fileList={imgList}
onPreview={this.handlePreview}
onChange={this.handleChange}
onRemove={this.handleRemove}
>
{fileList.length >= 3 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="图片" src={previewImage || (fileList.length && fileList.url)} />
</Modal>
</div>
);
}
}
export default PicturesWall;
/**
* 选择标签
*/
import React from 'react';
import debounce from 'lodash/debounce';
import common from 'src/lib/common';
import { Select, Spin } from 'antd';
import styles from './index.less';
const Option = Select.Option;
class TagSelect extends React.Component {
constructor(props) {
super(props);
this.lastFetchId = 0;
this.fetchUser = debounce(this.fetchUser, 800);
this.state = {
data: null,
fetching: false
};
}
fetchUser = (value) => {
this.lastFetchId += 1;
const fetchId = this.lastFetchId;
this.setState({ data: [], fetching: true });
common.fetch('/tag/selectTags', {content: value, tagLevel: 2}, 'get')
.then((body) => {
if (fetchId !== this.lastFetchId) { // for fetch callback order
return;
}
const data = (body.data && body.data.map(tag => ({
text: tag.contents,
value: tag.tagId
}))) || [];
this.setState({ data, fetching: false });
});
}
handleChange = (value) => {
this.props.onChange(value);
this.setState({
fetching: false
});
}
render() {
const { fetching, data } = this.state;
const {tagsContent = [], value = []} = this.props;
let sourceMap = [];
sourceMap = data === null ? tagsContent : data;
return (
<div id="tagsContainer">
<Select
mode="multiple"
placeholder="选择标签"
notFoundContent={fetching ? <Spin size="small" /> : null}
filterOption={false}
onSearch={this.fetchUser}
onChange={this.handleChange}
className={styles.select}
value={value}
getPopupContainer={() => document.getElementById('tagsContainer')}
>
{sourceMap && sourceMap.map((d, index) => <Option key={index} value={d.value}>{d.text}</Option>)}
</Select>
</div>
);
}
}
export default TagSelect;
.select {
width: 100%;
}
\ No newline at end of file
import React from 'react';
import common from 'src/lib/common';
import store from 'src/containers/riskmng/auditcase/store';
import {
Icon,
Upload,
Modal
} from 'antd';
import './index.less';
const url = '/upload/uploadImg';
class UploadImage extends React.Component {
constructor(props) {
super(props);
this.state = {
previewVisible: false,
previewImage: props.value
};
}
// 上传前进行检查
handleBeforeUpload = (file, fileList) => {
const { width, height, fileLimit } = this.props;
const imgTypeSize = {
width: parseInt(width, 10) || undefined,
height: parseInt(height, 10) || undefined
};
// 检查文件是否是图片
if (!this.checkIsImage(file)) {
common.handleError('上传的必须是jpg, jpeg, png, gif类型的图片');
return false;
}
// 检查文件大小是否超过限制
if (!this.checkFileLimit(file)) {
const fileLimitText = fileLimit >= (1 * 1024 * 1024) ? `${(fileLimit / 1024 / 1024)}MB` : `${(fileLimit / 1024)}KB`;
common.handleError(`图片必须小于${fileLimitText}`);
return false;
}
// 检查文件尺寸是否超过限制
return this.checkImageSize(file, imgTypeSize);
}
handleChange = (file) => {
let fileList = file.fileList;
this.props.onChange({ fileList });
// 如果已经是done状态,那么就设置数据
if (file.file.status === 'done') {
let uploadList = [];
fileList.map(item => {
if (item.response) {
uploadList.push(item);
}
});
const res = uploadList[0].response;
if (res.data === false) {
common.handleSuccess('上传图片成功');
} else {
common.handleError(res['desc']);
}
} else if (file.file.status === 'error') {
common.handleError('上传图片请求出错,请稍候重试');
}
}
// 处理预览框取消事件
handleCancel = () => this.setState({ previewVisible: false })
// 处理预览按钮点击事件
handlePreview = (file) => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true
});
}
// 校验图片的大小是否合规
checkImageSize = (file, imgTypeSize) => {
return new Promise(function(resolve, reject) {
function check(width, height) {
if (
(width === imgTypeSize.width || !imgTypeSize.width) &&
(height === imgTypeSize.height || !imgTypeSize.height)
) {
resolve(file);
} else {
common.handleError(
'图片大小不对,要求尺寸为' +
(imgTypeSize.width || '宽度不限') +
'*' +
(imgTypeSize.height || '高度不限') +
' 像素'
);
}
}
// 读取图片数据
if (typeof window.FileReader === 'function') {
// 读取图片数据
const reader = new window.FileReader();
reader.onload = function(e) {
const data = e.target.result;
// 加载图片获取图片真实宽度和高度
const image = new window.Image();
image.onload = function() {
const width = image.width;
const height = image.height;
check(width, height);
};
image.src = data;
};
reader.readAsDataURL(file);
} else {
common.handleError('你的浏览器不支持图片大小判断,请更换现代浏览器,例如Chrome');
}
});
}
// 限制文件格式为图片
checkIsImage = (file) => {
const fileName = file.name;
return !!fileName.match(/.jpg|.jpeg|.png|.gif/);
}
// 限制文件大小
checkFileLimit = (file) => {
const { fileLimit } = this.props;
if (!fileLimit) {
return true;
}
return fileLimit > file.size;
}
handleRemove = (file) => {
const { deletePhoto } = store;
let id;
if (!file.response) {
id = file.uid;
} else {
id = -1;
}
let params = {
id: id
};
return new Promise((resolve, reject) => {
Modal.confirm({
title: '提示',
content: '确认修改?',
okText: '确定',
okType: 'danger',
cancelText: '取消',
onOk() {
deletePhoto(params.id).then(resolve());
},
onCancel() {
console.log('you chose close!');
resolve(false);
}
});
});
}
render() {
const { fileList = [] } = this.props;
const { previewVisible, previewImage } = this.state;
const uploadButton = (
<div>
<Icon type="plus" />
</div>
);
return (
<div className="clearfix">
<Upload
className="uploadStyle"
action={url}
listType="picture-card"
beforeUpload={this.handleBeforeUpload}
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
onRemove={this.handleRemove}
>
{fileList.length >= 3 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel} className="modalStyle">
<img alt="图片" className="width_100_percent" src={previewImage || (fileList.length && fileList.url)} />
</Modal>
</div>
);
}
}
export default UploadImage;
:global{
.modalStyle{
width: 1000px!important;;
&.ant-modal{
.ant-modal-body{
overflow: auto!important;
.width_100_percent {
max-width: 150%!important;
}
}
}
}
.uploadStyle{
.ant-upload-list-item{
width: 64px!important;
height: 64px!important;
margin-bottom: 0px!important
}
.ant-upload-select-picture-card{
width: 64px!important;
height: 64px!important;
font-size: 8px
}
}
}
\ No newline at end of file
// import React from 'react';
import React from 'react';
import 'whatwg-fetch';
import utils from 'src/lib/utils';
import errorCodes from 'src/lib/errorcode';
import {
message,
Modal
} from 'antd';
import Loading from 'src/components/loading';
const Common = (function() {
// message提示框延迟时间
const MESSAGE_DURATION = 3;
// 关闭加载提示框
const close = (res) => {
setTimeout(() => {
Loading.close();
}, 300);
return res;
};
// 拼接请求参数
const concatUrl = (params = {}) => {
const esc = encodeURIComponent;
const query = Object.keys(params)
.map(k => esc(k) + '=' + esc(params[k]))
.join('&');
return query;
};
// 检查返回code
const checkStatus = (response) => {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
let error = new Error(response.statusText);
error.response = response;
throw error;
}
};
return {
concatUrl,
// 错误处理框,不阻断用户操作
handleError(msg) {
message.error(msg, MESSAGE_DURATION);
},
// 成功处理框,不阻断用户操作
handleSuccess(msg) {
message.success(msg, MESSAGE_DURATION);
},
// 错误提示框,阻断用户操作,需要用户自己手动点击关闭
handleErrorNeedClick(msg) {
Modal.error({
title: '系统提示',
content: (
<div>
<p>{msg}</p>
</div>
)
});
},
// 成功提示框,阻断用户操作,需要用户自己手动点击关闭
handleSuccessNeedClick(msg) {
Modal.success({
title: '系统提示',
content: (
<div>
<p>{msg}</p>
</div>
)
});
},
handleWarn(msg) {
message.warn(msg, MESSAGE_DURATION);
},
/**
* fetch请求封装
* @param {*} action 请求线上地址
* @param {*} data 请求入参
* @param {*} method 请求方式,默认get
* @param {*} options 其他参数
* options为对象格式,值:
* isLoading(是否激活请求加载动画)
* isJson(是否设置post请求头contentType为application/json)
* content 自定义请求参数
*/
fetch(action, params = {}, method = 'get', options) {
let url = action;
let option = {
method,
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
content: {deleteNullAndUndefinedParams: false}
};
if (options && options.content) {
option = Object.assign({}, option, options.content);
}
// 删除null和undefined的字段
if (option && option.deleteNullAndUndefinedParams) {
Object.keys(params).forEach(key => {
if (params[key] === null || params[key] === undefined) {
delete params[key];
};
});
}
// if (options && options.isJson && method === 'post') {
// option.body = JSON.stringify(params);
// }
if (method === 'post' || method === 'put' || method === 'delete') {
if (options && options.isJson) {
option.body = JSON.stringify(params);
} else {
option = Object.assign({}, option, {
headers: {
'Accept': 'application/json,text/plain,*/*',
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
}
});
option.body = utils.serialize(params);
}
}
if (method === 'get') {
url = Object.keys(params).length ? url + '?' + concatUrl(params) : url;
}
if (options && options.isLoading) {
Loading.open();
}
return fetch(url, option) // eslint-disable-line no-undef
.then(checkStatus)
.then(close, close)
.then((response) => {
return response.json().then((res) => {
// SSO登录验证
if (res.success !== undefined) {
if (!res.success && !!res.notLogin) {
utils.logout();
}
} else {
// 业务接口成功
if (res.code !== '0') {
if (errorCodes[res.code]) {
this.handleErrorNeedClick(errorCodes[res.code]);
} else {
this.handleErrorNeedClick(res.desc);
}
throw new Error(res.desc);
}
}
return res;
}, (ex) => {
throw new Error(`解析JSON字符串出错:${url} ${ex.message}`);
});
}, (ex) => {
throw new Error(`请求服务器出错:${url} ${ex.message}`);
});
}
};
})();
export default Common;
/* eslint-disable */
/*\
|*|
|*| :: cookies.js ::
|*|
|*| A complete cookies reader/writer framework with full unicode support.
|*|
|*| https://developer.mozilla.org/en-US/docs/DOM/document.cookie
|*|
|*| This framework is released under the GNU Public License, version 3 or later.
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*| Syntaxes:
|*|
|*| * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*| * docCookies.getItem(name)
|*| * docCookies.removeItem(name[, path], domain)
|*| * docCookies.hasItem(name)
|*| * docCookies.keys()
|*|
\*/
var docCookies = {
getItem: function (sKey) {
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
},
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
var sExpires = "";
if (vEnd) {
switch (vEnd.constructor) {
case Number:
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
break;
case String:
sExpires = "; expires=" + vEnd;
break;
case Date:
sExpires = "; expires=" + vEnd.toUTCString();
break;
}
}
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
return true;
},
removeItem: function (sKey, sPath, sDomain) {
if (!sKey || !this.hasItem(sKey)) { return false; }
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
return true;
},
hasItem: function (sKey) {
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
},
keys: /* optional method: you can safely remove it! */ function () {
var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
return aKeys;
}
};
\ No newline at end of file
export function formatDate(date) {
if (typeof date !== 'object') {
date = new Date(date);
}
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = ('0' + month).slice(-2);
day = ('0' + day).slice(-2);
return year + '-' + month + '-' + day;
}
export function isSameDay(date1, date2) {
return formatDate(date1) === formatDate(date2);
}
export function formatDateTime(date) {
if (typeof date !== 'object') {
date = new Date(date);
}
let dateStr = formatDate(date);
let timeStr = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2);
return dateStr + ' ' + timeStr;
}
export function dateSubtract(date, day) {
if (typeof date !== 'object') {
date = new Date(date);
}
date.setDate(date.getDate() - day);
return formatDate(date);
}
/**
* @export
* @param {any} dateStr 日期
* @param {any} n 几天前
* @returns 几天前的标准日期
*/
export function getPerDay(dateStr, n) {
let yes = new Date(dateStr) - 1000 * 60 * 60 * 24 * n;
return formatDate(yes);
}
// 保留小数
export default function fixNum(num, long) {
let numLong = 2;
if (long === 0) {
numLong = long;
}
if (long) {
numLong = long;
}
num = Number(num).toFixed(numLong);
if (num) {
num = num + '';
let fix = ''; // 小数点情况
let splitArr = num.split('.');
num = splitArr[0];
fix = splitArr[1] ? splitArr[1] : '';
num = num.replace(/\d{1,3}(?=(\d{3})+$)/g, function(s) {
return s + ',';
});
if (fix) {
return num + '.' + fix;
}
return num;
}
return num;
};
/**
* 管理所有的错误码
*/
const errorCodes = {
'0300034': '没有更多域名,请前往配置'
};
export default errorCodes;
/**
* 权限工具类
*/
let permissionCodes = [];
const Permissions = {
getPermissions() {
return permissionCodes;
},
setPermissions(permissions) {
if (permissions && permissions.length) {
permissionCodes = permissions;
}
},
authRender(item, code) {
if (this.ifRender(code)) {
return item;
} else {
return null;
}
},
// 判断是否需要渲染权限组件
ifRender(code) {
// 用于判断是否需要渲染
let shouldRender = false;
// 如果传入的是个权限数组,那么需要所有权限都有的情况下才能渲染
if (typeof code !== 'string') {
let existNums = 0;
code.map(el => {
let exist = false;
permissionCodes.map(item => {
if (item.indexOf(el) !== -1) {
exist = true;
}
item.indexOf(code) !== -1 && (shouldRender = true);
});
if (exist) {
existNums++;
}
});
if (code.length === existNums) {
shouldRender = true;
}
} else { // 传入的是字符串则匹配是否有该权限
permissionCodes.map(item => {
item.indexOf(code) !== -1 && (shouldRender = true);
});
}
return shouldRender;
}
};
export default Permissions;
// 排序校验规则,只能输入1-列表长度之内的整数
export const sortValidRule = (rule, value, func, store) => {
const {
dataSource,
isAddModal
} = store;
const length = dataSource.length;
// const sRex = '^([1-9]|[1-2]\\d|' + pageSize + ')$';
const sRex = '^[1-9]\\d*$';
const reg = new RegExp(sRex);
if (
value &&
(!value.toString().match(reg) ||
(isAddModal && value > length + 1) ||
(!isAddModal && value > length))
) {
// func(`请输入1~${length < pageSize ? isAddModal ? length + 1 : length : pageSize}之间的整数`);
func(`请输入1~${isAddModal ? length + 1 : length}之间的整数`);
} else {
func();
}
};
// 判断是否已经存在相同的URL
// url为需要匹配的URL,index为当前操作数据的排序
const hasUrl = (data, url, ind) => {
return data.some((element, index, array) => {
return url && element.url === url.trim() && index !== ind;
});
};
// url校验规则,不能重名
export const urlValidRule = (rule, value, func, store) => {
const {
dataSource,
currentIndex
} = store;
if (hasUrl(dataSource, value, currentIndex)) {
func('URL地址已存在,请重新输入');
} else {
func();
}
};
// 标签校验规则
export const tagsValidRule = (rule, value, func, tagsMaxSelected) => {
if (value && Array.isArray(value) && (value.length > tagsMaxSelected)) {
func(`标签最多不能超过${tagsMaxSelected}个`);
} else {
func();
}
};
// 密码校验规则,只能是英文字母大小写,数字,特殊符号!@#.,,不能存在%
export const pwdValidRule = (rule, value, func) => {
if (value && typeof value === 'string') {
if (/%/.test(value)) {
func('输入内容包含特殊字符,请重新输入');
} else if (!/[\da-zA-Z!@#.,]{8,}/.test(value)) {
func('密码格式错误');
} else {
func();
}
} else {
func();
}
};
// 账号校验规则
export const accountValidRule = (rule, value, func) => {
if (value && typeof value === 'string' && /%/.test(value)) {
func('输入内容包含特殊字符,请重新输入');
} else {
func();
}
};
import { hashHistory } from 'react-router';
import common from 'src/lib/common';
const utils = {
// history跳转
jumpTo(url) {
hashHistory.push(url);
},
// // 登出函数
// async logout() {
// const {system, ssoHomeURL} = await common.fetch('/sso/systemInfo');
// window.location.href = `${ssoHomeURL}/login?sysytemId=${system.id}&redirect=${encodeURIComponent(`${window.location.origin}/static/index.html`)}`;
// },
// 登出函数
logout() {
common.fetch('/sso/systemInfo').then((res) => {
if (res.success) {
window.location.href = `${res.ssoHomeURL}/login?systemId=${res.system.id}&redirect=${encodeURIComponent(`${window.location.origin}`)}`;
}
});
},
// 判断是否有值
isNothing(value) {
return value === '' || value === undefined || value === null || (typeof value === 'number' && (isNaN(value) || !isFinite(value)));
},
serialize(obj) {
const str = [];
for (let p in obj) {
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(this.isNothing(obj[p]) ? '' : obj[p]));
}
}
return str.join('&');
},
getURLParameter(name) {
const result = decodeURIComponent((new RegExp('[?|&]' + name + '=([^&;]+?)(&|#|;|$)').exec(window.location.href) || [undefined, ''])[1].replace(/\+/g, '%20')) || null;
return result;
}
};
export default utils;
import React from 'react';
import common from 'src/lib/common';
import PermissionTool from 'src/lib/permissionTools';
import {
Layout
} from 'antd';
import Header from 'src/components/header';
import Menu from 'src/components/menu';
import Footer from 'src/components/footer';
import 'src/styles/antd.less';
import styles from 'src/styles/index.less';
const { Content } = Layout;
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
dataIsReady: false, // 用于判断数据是否获取完成标识
currentAccount: {
name: '',
email: ''
} // 当前用户信息
};
}
componentDidMount() {
this.fetcUserInfo();
}
// 获取用户信息数据
fetcUserInfo = () => {
const actions = ['/auth/getAuthList', '/sso/admin/adminInfo'];
Promise.all(actions.map(action => {
return common.fetch(action, {}, 'get');
}))
.then(datas => {
const [authInfoData = {}, userInfoData = {}] = datas;
const { success: getAuthSuccess, authList } = authInfoData;
const { success: getUserInfoSuccess, adminName: name } = userInfoData;
// 权限数据获取
if (getAuthSuccess) {
PermissionTool.setPermissions(authList);
this.setState({
dataIsReady: true
});
} else {
// 已经统一处理
// const { success: getAuthSuccess, authList, desc } = authInfoData;
// common.handleError(desc);
}
// 用户信息获取
if (getUserInfoSuccess) {
this.setState({
currentAccount: {
name
}
});
}
});
}
render() {
const { currentAccount, dataIsReady } = this.state;
const { router, children } = this.props;
const { getCurrentLocation } = router;
return dataIsReady ? (
<Layout className={styles.app_container}>
<Header accountInfo={currentAccount}/>
<Layout>
<Menu currentLocation={getCurrentLocation()}/>
<Layout className={styles.content_wrap}>
<Content className={styles.content_container}>
{children}
</Content>
<Footer />
</Layout>
</Layout>
</Layout>
) : null;
}
}
module.exports = {
path: 'example',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('src/containers/example').default);
});
},
childRoutes: [{
path: 'lv3',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/example/child').default);
});
}
}]
};
import App from './App';
const checkLoginState = (replaceState) => {
console.log('route to login page here');
};
const rootRoute = {
path: '/',
component: App,
breadcrumbName: '首页',
onEnter: (nextState, replaceState) => {
// 检查登录状态
checkLoginState(replaceState);
},
indexRoute: {
getComponent(location, cb) {
require.ensure([], (require) => {
cb(null, require('src/containers/riskmng/auditsys').default);
});
}
},
childRoutes: [
require('./example'),
require('./riskmng'), // 风控操作台
require('./nameFilter'), // 黑白名单
require('./ruleEngine'), // 决策引擎
// 路由放在这个的前面
// 这里相当于redirect, 放404
{
path: '*',
onEnter: (nextState, replaceState) => {
replaceState('/', null);
}
}
]
};
export default rootRoute;
module.exports = {
path: 'nameFilter',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('src/containers/nameFilter').default);
});
},
childRoutes: [{
path: 'black',
breadcrumbName: '黑名单',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/nameFilter/black').default);
});
}
},
{
path: 'white',
breadcrumbName: '白名单',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/nameFilter/white').default);
});
}
}]
};
module.exports = {
path: 'riskmng',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('src/containers/riskmng').default);
});
},
childRoutes: [{
path: 'auditsys',
breadcrumbName: '审核操作台',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/riskmng/auditsys').default);
});
}
},
{
path: 'auditcase',
breadcrumbName: '案例库',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/riskmng/auditcase').default);
});
}
},
{
path: 'innercheck',
breadcrumbName: '内控审核',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/riskmng/innercheck').default);
});
}
}]
};
module.exports = {
path: 'ruleEngine',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('src/containers/ruleEngine').default);
});
},
childRoutes: [{
path: 'scence',
breadcrumbName: '场景管理',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/ruleEngine/scence').default);
});
}
},
{
path: 'strategy',
breadcrumbName: '策略管理',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/ruleEngine/strategy').default);
});
},
childRoutes: [{
path: 'rule',
breadcrumbName: '规则管理',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/ruleEngine/rule').default);
});
}
}]
},
// {
// path: 'rule',
// breadcrumbName: '规则管理',
// getComponent(location, cb) {
// require.ensure([], require => {
// cb(null, require('src/containers/ruleEngine/rule').default);
// });
// }
// },
{
path: 'report',
breadcrumbName: '风控报告',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/ruleEngine/report').default);
});
}
},
{
path: 'field',
breadcrumbName: '字段管理',
getComponent(location, cb) {
require.ensure([], require => {
cb(null, require('src/containers/ruleEngine/field').default);
});
}
}]
};
@import '~antd/dist/antd.less';
/*
* 重置antd的less变量
*/
/*
*面包屑样式重置
*/
@tian-text-color-secondary: rgba(255, 255, 255, .45);
@tian-primary-5:rgba(255, 255, 255, .65);
@tian-text-color: rgba(255, 255, 255, 1);
@breadcrumb-base-color: @tian-text-color-secondary;
@breadcrumb-link-color: @tian-text-color-secondary;
@breadcrumb-link-color-hover: @tian-primary-5;
@breadcrumb-last-item-color: @tian-text-color;
@breadcrumb-separator-color: @tian-text-color-secondary;
\ No newline at end of file
@import 'mixin.less';
@import 'utils.less';
@import 'reset.less';
@import 'global.less';
@import 'layout.less';
.content_container {
background: #fff;
overflow-y: auto;
padding: 12px;
margin: 0;
min-height: 280px;
}
.app_container {
height: 100vh;
}
.content_wrap {
padding: 12px;
}
.tian_table {
margin-top: 10px;
a {
margin-left: 5px;
color: #2db7f5!important;
&:hover {
color: #57c5f7;
}
}
}
\ No newline at end of file
.clearfix(){
&::after{
content: '';
display: table;
clear: both;
}
}
\ No newline at end of file
/*
* @Author: 周成
* @Date: 2018-03-22 19:57:53
* @Last Modified by: 周成
* @Last Modified time: 2018-04-08 21:21:08
*/
/*
* 重置默认样式
*/
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
outline: none;
}
html {
font-family: 'Helvetica Neue', Helvetica, Hiragino Sans GB, 'Microsoft Yahei',
STHeiTi, Arial, sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent; /* For some Androids */
-webkit-font-smoothing: antialiased;
}
body {
font-size: 12px;
line-height: 1;
overflow-x: hidden;
width: 100%;
margin: 0 auto;
color: #333;
background-color: #f0f0f0;
-webkit-overflow-scrolling: touch;
-webkit-touch-callout: none;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
display: block;
}
a {
text-decoration: none;
color: inherit;
}
a:active {
outline: 0;
}
b,
strong {
font-weight: bold;
}
dfn {
font-style: normal;
}
img {
max-width: 100%;
vertical-align: middle;
border: 0;
}
input,
textarea,
button {
font-family: 'Helvetica Neue', Helvetica, Hiragino Sans GB, 'Microsoft Yahei',
STHeiTi, Arial, sans-serif;
font-size: 12px;
margin: 0;
padding: 0;
border: 0;
}
textarea {
resize: none;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
td,
th {
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
form,
blockquote {
margin: 0;
}
ul,
ol,
li,
dl,
dd {
margin: 0;
padding: 0;
}
ul,
ol,
li {
list-style: none;
}
.placeholder {
font-family: 'Helvetica Neue', Helvetica, Hiragino Sans GB, 'Microsoft Yahei',
STHeiTi, Arial, sans-serif;
text-align: left;
color: #999;
}
input:-moz-placeholder,
textarea:-moz-placeholder {
.placeholder();
}
input::-moz-placeholder,
textarea::-moz-placeholder {
opacity: 1;
.placeholder();
}
input:-ms-input-placeholder,
textarea::-ms-input-placeholder {
.placeholder();
}
input::-webkit-input-placeholder,
textarea::-webkit-input-placeholder {
.placeholder();
}
\ No newline at end of file
{
"compilerOptions": {
"experimentalDecorators": true,
"allowJs": true
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment