Commit c52300a7 authored by wangchunxiang's avatar wangchunxiang

Initial commit

parents
Pipeline #2076 canceled with stages
File added
{
"plugins": [
["import", {
"libraryName": "antd",
"style": true
}]
]
}
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
APP_HOST_URL='http://testonlinenightclub.srccwl.com/api'
env=dev
APP_HOST_URL='https://m-b.ahgcloud.com'
AMS_API_URL_01='https://m-b.ahgcloud.com'
AMS_API_URL_02='https://m-b.ahgcloud.com'
env=prod
# 忽略目录
build/
tests/
demo/
# node 覆盖率文件
coverage/
# 忽略文件
**/*-min.js
**/*.min.js
{
"root": true,
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6,
"ecmaFeatures": {
"jsx": true,
"experimentalObjectRestSpread": true
}
},
"env": {
"browser": true,
"mocha": true
},
"plugins": ["react", "babel"],
"rules": {
"react/prefer-stateless-function": 0,
"no-console": 0,
"no-use-before-define": 0,
"jsx-a11y/label-has-for": 0,
"jsx-a11y/no-static-element-interactions": 0,
"jsx-a11y/anchor-has-content": 0,
"jsx-a11y/click-events-have-key-events": 0,
"jsx-a11y/anchor-is-valid": 0,
"react/no-array-index-key": 0,
"func-names": 0,
"arrow-body-style": 0,
"react/sort-comp": 0,
"react/prop-types": 0,
"react/jsx-first-prop-new-line": 0,
"react/jsx-filename-extension": [
1,
{
"extensions": [".js", ".jsx"]
}
],
"import/extensions": 0,
"import/no-unresolved": 0,
"import/no-extraneous-dependencies": 0,
"prefer-destructuring": 0,
"no-param-reassign": 0,
"no-return-assign": 0,
"max-len": 0,
"consistent-return": 0,
"no-redeclare": 0,
"react/require-extension": 0,
"react/no-danger": 0,
"function-paren-newline": 0,
"object-curly-newline": 0,
"no-restricted-globals": 0,
"global-require": 0
}
}
node_modules/
.env
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="JSX" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/manager.ahg.aimhighsdk.com.iml" filepath="$PROJECT_DIR$/.idea/manager.ahg.aimhighsdk.com.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
const path = require('path');
const Dotenv = require('dotenv-webpack');
const build_env = process.env.build_env ? process.env.build_env : 'dev';
module.exports = context => {
const { webpack } = context;
return {
mode: process.env.NODE_ENV,
devtool: 'source-map',
entry: {
index: './src/index.js'
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
plugins: [
new Dotenv({
path: `.env.${build_env}`, // load this now instead of the ones in '.env'
safe: false, // load '.env.example' to verify the '.env' variables are all set. Can also be a string to a different file.
systemvars: true, // load all the predefined 'process.env' variables which will trump anything local per dotenv specs.
silent: false // hide any errors
})
],
output: {
path: path.resolve('release'),
filename: process.env.NODE_ENV === 'development' ? '[name].js' : '[name].[contenthash].js'
},
optimization: {
splitChunks: {
chunks: 'all'
}
}
};
};
# ice-scaffold-lite
## 使用
- 启动调试服务: `npm run start`
- 构建 release: `npm run buildProd`
## 目录结构
- react-router @4.x 默认采用 hashHistory 的单页应用
- 入口文件: `src/index.js`
- 导航配置: `src/menuConfig.js`
- 路由配置: `src/routerConfig.js`
- 路由入口: `src/router.jsx`
- 布局文件: `src/layouts`
- 通用组件: `src/components`
- 页面文件: `src/pages`
This diff is collapsed.
{
"name": "@icedesign/lite-scaffold",
"version": "1.0.0",
"files": [
"src/",
"src/assets",
"build/",
"public/",
"tests/",
"_gitignore",
".editorconfig",
".eslintignore",
".eslintrc"
],
"dependencies": {
"@alifd/next": "^1.13.2",
"@alifd/theme-ice-orange": "^0.1.2",
"@ice/store": "^0.3.0",
"@icedesign/container": "^1.x",
"@icedesign/data-binder": "^1.0.0",
"ali-oss": "^6.1.0",
"antd": "^3.23.2",
"axios": "^0.18.0",
"base-64": "^0.1.0",
"bizcharts": "latest",
"classnames": "^2.2.6",
"cross-env": "^5.2.0",
"dotenv-webpack": "^1.7.0",
"enquire-js": "^0.1.2",
"js-export-excel": "^1.1.4",
"less": "2.7.3",
"marine": "^1.0.16",
"moment": "^2.24.0",
"node-sass": "^4.14.1",
"path": "^0.12.7",
"prop-types": "^15.5.8",
"react": "^16.4.1",
"react-cookie": "^3.0.8",
"react-document-title": "^2.0.3",
"react-dom": "^16.4.1",
"react-router-dom": "^4.3.1",
"reactjs-localstorage": "0.0.7"
},
"devDependencies": {
"babel-eslint": "^8.0.3",
"eslint": "^4.13.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-babel": "^4.1.1",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.5.1",
"ice-scripts": "^1.8.7",
"jest": "^24.4.0"
},
"scripts": {
"start": "ice dev",
"lint": "eslint . --ext '.js,.jsx' --fix",
"test": "jest",
"build": "ice build",
"buildProd": "ice build --mode prod",
"preinstall": "npx npm-force-resolutions"
},
"resolutions": {
"graceful-fs": "4.2.3"
},
"publishConfig": {
"access": "public"
},
"buildConfig": {
"entry": "src/index.js",
"localization": false,
"output": {
"publicPath": "./"
}
},
"scaffoldConfig": {
"builder": "ice-scripts",
"name": "ice-design-lite",
"title": "ICE Design Lite",
"categories": [
"基础模板"
],
"screenshot": "https://img.alicdn.com/tfs/TB1CjPVw4naK1RjSZFBXXcW7VXa-2872-1580.png"
},
"engines": {
"node": ">=8.0.0"
},
"title": "ams-portal"
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>夜店后台管理</title>
</head>
<body>
<div id="ice-container"></div>
</body>
</html>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<title>海外管理系统</title>
<link rel="shortcut icon" href="./favicon.png"><link href="./css\1.css" rel="stylesheet"><link href="./css\index.css" rel="stylesheet"></head>
<body>
<div id="ice-container"></div>
<script type="text/javascript" src="./vendors~index.90bbc091ff3d706d4ac7.js"></script><script type="text/javascript" src="./index.1158e86530440d84d73d.js"></script></body>
</html>
This diff is collapsed.
export const Platforms = [
{
"id": 1,
"name": "PC",
},
{
"id": 2,
"name": "安卓",
},
{
"id": 3,
"name": "iOS",
},
{
"id": 4,
"name": "H5",
},
{
"id": 5,
"name": "微信小游戏",
}
];
import { Action, Store } from 'marine';
Action.def('global', {
'getProjectId': (action, data) => {
action.emit({
channel:'projectIdSave',
data: data
});
}
});
This diff is collapsed.
import React, {Component, Fragment} from 'react';
import {withRouter} from "react-router-dom";
import {Button} from "antd";
import { get } from "../../service/Global";
import './ItemAppInfo.scss'
@withRouter
export default class ItemAppInfo extends Component {
constructor(props) {
super(props)
this.state = {
a: '',
}
}
componentWillMount() {
this.setState({
a: get('readonly')
})
}
eidtApp = (id) => {
console.log(id);
this.props.history.push({
pathname:'/app/edit',
state:{
appid:id,
},
})
};
render() {
console.log(this.props.app_info);
return (
<Fragment>
<div className="app-info-group">
<img src={this.props.app_info.icon ? this.props.app_info.icon : null} alt={this.props.app_info.name}/>
<div className="app-text ctm-left">
<p className="name">{this.props.app_info.name}</p>
<ul>
<li>运营平台:<span>{this.props.app_info.operator_name}</span></li>
<li>官网:<span>{this.props.app_info.website}</span></li>
<li>H5应用地址:<span>{this.props.app_info.website_h5}</span></li>
{
this.props.app_info.platform_name ?
<Fragment>
<li>应用平台:<span>{this.props.app_info.platform_name}</span></li>
<li>应用ID:<span>{this.props.app_info.appid}</span></li>
</Fragment>
:
null
}
</ul>
</div>
{
this.props.app_info.platform_name ?
null
:
<div className="btn-edit ctm-right">
<Button type="normal" onClick={() => this.eidtApp(this.props.app_info.id)} disabled={this.state.a == 1 ? true : false}>编辑</Button>
</div>
}
</div>
</Fragment>
)
}
}
.app-info-group{
@include clearfix;
img{
width: 150px;
height: 150px;
border-radius: 4px;
float: left;
}
.app-text{
margin-left: 30px;
>.name{
font-size: 24px;
color: #404040;
}
ul{
width: 460px;
>li{
width: 50%;
float: left;
font-size: 14px;
color: #404040;
margin-top: 16px;
}
}
}
}
import ItemAppInfo from './ItemAppInfo'
export default ItemAppInfo;
import React,{Fragment} from 'react';
import UnitInput from './components/UnitInput'
import UnitModal from './components/UnitModal'
import './ItemCard.scss'
export default class ItemCard extends React.Component{
constructor(props){
super(props)
}
render() {
return(
<ul className="item-card ctm-clearfix">
{
this.props.columns.map((item,index)=>{
if(item === {}){
return <li key={index}></li>
}
if(item.type === 'input'){
return <Fragment>
<li key={index}>
<ul>
<li>{item.title}</li>
<li>
<UnitInput value={this.props.res[item.dataIndex]} config={item}/>
</li>
</ul>
</li>
</Fragment>
}else if(item.type === 'modal'){
return <Fragment>
<li key={index}>
<ul>
<li>{item.title}</li>
<li><UnitModal value={this.props.res} config={item}/></li>
</ul>
</li>
</Fragment>
}else if(item.render){
return <Fragment>
<li key={index}>
<ul>
<li>{item.title}</li>
<li>{item.render(this.props.res[item.dataIndex])}</li>
</ul>
</li>
</Fragment>
} else {
return <Fragment>
<li key={index}>
<ul>
<li>{item.title}</li>
<li>{this.props.res[item.dataIndex]||undefined}</li>
</ul>
</li>
</Fragment>
}
})
}
</ul>
)
}
}
.item-card{
padding: 20px;
width: 100%;
>li:nth-child(4n+1),>li:nth-child(4n+2){
background-color: #F7F9FA;
}
>li{
width: 50%;
float: left;
height: 50px;
border-bottom: 1px solid #ebedee;
border-right: 1px solid #ebedee;
>ul{
float: left;
width: 100%;
li{
float: left;
line-height: 50px;
padding-left: 20px;
}
li:first-child{
width: 23%;
}
li:last-child{
width: 77%;
}
}
}
}
import React,{Fragment} from 'react';
import {Button, Icon, Input, message, Popconfirm} from 'antd';
export default class UnitInput extends React.Component{
constructor(props){
super(props);
this.state={
value:undefined,
editStatus:false
}
}
inputVal;
editStatusToggle=(boolean)=>{
this.setState({
editStatus:boolean
})
}
save=()=>{
if(this.props.config.pattern.test(this.inputVal)){
this.setState({
value:this.inputVal,
editStatus:false,
});
this.props.config.getOutput(this.inputVal);
}else {
message.error('输入有误')
}
};
cancel=()=>{
this.setState({
defaultValue:this.state.value,
editStatus:false
})
};
componentDidMount() {
this.setState({
value : this.props.value
})
}
getValue=(e)=>{
this.inputVal = e.target.value
};
render() {
return(
<Fragment>
{
(()=>{
if(!this.state.editStatus){
return <span>{this.state.value} <Icon onClick={()=>this.editStatusToggle(true)} type="edit" /> <i className="ml-20" style={{fontSize:'12px'}}>{this.props.config.tips}</i>
{
(()=>{
if(this.props.config.removeBd){
return <Popconfirm title="确定解绑?" okText="是" onConfirm={this.props.config.removeBd} cancelText="否"><a className='ml-20'>解绑</a></Popconfirm>
}
})()
}
</span>
}else {
return <div>
<Input style={{width:'34%'}} placeholder={this.props.placeholder||'请输入...'} onChange={this.getValue} defaultValue={this.state.value}/>
<a className="ml-10 mr-10" onClick={this.save}>保存</a>
<a onClick={this.cancel}>取消</a>
<i className="ml-20" style={{fontSize:'12px'}}>{this.props.config.tips}</i>
</div>
}
})()
}
</Fragment>
)
}
}
import UnitInput from './UnitInput'
export default UnitInput
import React,{Fragment} from 'react';
import {Icon, Tag} from 'antd';
import ItemModal from '../../../../components/ItemModal'
export default class UnitModal extends React.Component{
constructor(props){
super(props);
this.state={
value:{status:undefined},
config:{
title:'用户状态修改',
render:[
{
type:'select',
label:'状态',
key: 'status',
data:[{name:'正常',id:0},{name:'黑名单',id:1}],
required:true,
},
{
type:'textarea',
label:'修改原因',
key: 'remark',
required:true,
}
],
dataSource:{}
},
}
}
modal;
editStatusToggle=()=>{
this.modal.showModal();
};
componentDidMount() {
this.setState({
value:this.props.value,
config:Object.assign(this.state.config,{dataSource:this.props.value},{...this.props.config})
})
}
componentWillReceiveProps(nextProps, nextContext) {
this.setState({
value:nextProps.value,
config:Object.assign(this.state.config,{dataSource:nextProps.value},{...this.props.config})
})
}
render() {
return(
<Fragment>
<span>
{
(()=>{
switch (this.state.value.status) {
case 1:
return <Tag color="#404040">黑名单</Tag>;
case 0:
return <Tag color="#9AD680">正常</Tag>;
}
})()
}
<Icon onClick={this.editStatusToggle} type="edit" />
</span>
<ItemModal ref={r=> this.modal =r} config={this.state.config}/>
</Fragment>
)
}
}
import UnitModal from './UnitModal'
export default UnitModal
import ItemCard from './ItemCard'
export default ItemCard
This diff is collapsed.
import React, { Fragment } from 'react'
import { Switch, Typography } from 'antd';
const { Text } = Typography;
export default class ItemFunctionSwitches extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
triggerChange = changedValue => {
const { onChange, value } = this.props;
if (onChange) {
onChange({
...value,
...changedValue,
});
}
}
componentDidMount() {
}
handleuUgradeAccountChange = (checked) => {
let data = {
switch_upgrade_account: checked === true ? 1 : 0,
}
this.triggerChange(data)
}
handleProtocolChange = (checked) => {
let data = {
switch_protocol: checked === true ? 1 : 0,
}
this.triggerChange(data)
}
handleuMycardChange = (checked) => {
let data = {
mycard: checked === true ? 1 : 0,
}
this.triggerChange(data)
}
handleRazerChange = (checked) => {
let data = {
razer: checked === true ? 1 : 0,
}
this.triggerChange(data)
}
render() {
let switch_upgrade_account = this.props.value.switch_upgrade_account || 0;
let switch_protocol = this.props.value.switch_protocol || 0;
let mycard = this.props.value.mycard || 0;
let razer = this.props.value.razer || 0;
let id = this.props.id.split('validate_other_')[1];
return (
<Fragment>
{(id==='function_switches') ? (<div><div>
<div className="ant-col ant-form-item-label ant-col-xs-5 ant-col-sm-5">账户升级:</div>
<div className="ant-col ant-form-item-control-wrapper ant-col-xs-16 ant-col-sm-16">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
checked={switch_upgrade_account === 1} onChange={this.handleuUgradeAccountChange} />
<Text>每次支付后对未升级的账户弹窗提醒账户升级</Text>
</div>
</div>
<div>
<div className="ant-col ant-form-item-label ant-col-xs-5 ant-col-sm-5">强制确认协议:</div>
<div className="ant-col ant-form-item-control-wrapper ant-col-xs-16 ant-col-sm-16">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
checked={switch_protocol === 1} onChange={this.handleProtocolChange} />
<Text>在用户登录前让用户同意所有协议条款</Text>
</div>
</div></div>):(id==='pay_switches') ? (<div><div>
<div className="ant-col ant-form-item-label ant-col-xs-5 ant-col-sm-5">mycard支付开关:</div>
<div className="ant-col ant-form-item-control-wrapper ant-col-xs-16 ant-col-sm-16">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
checked={mycard === 1} onChange={this.handleuMycardChange} />
</div>
</div>
<div>
<div className="ant-col ant-form-item-label ant-col-xs-5 ant-col-sm-5">razer gold支付开关:</div>
<div className="ant-col ant-form-item-control-wrapper ant-col-xs-16 ant-col-sm-16">
<Switch checkedChildren="启用" unCheckedChildren="禁用"
checked={razer === 1} onChange={this.handleRazerChange} />
</div>
</div></div>):null}
</Fragment>
)
}
}
import ItemFunctionSwitches from './ItemFunctionSwitches'
export default ItemFunctionSwitches
import React, { Fragment } from 'react'
import { Table, Divider, Row, Col, Alert, Input, Switch } from 'antd';
export default class ItemLoginMethod extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
unused_data: []
}
}
triggerChange = (changedValue) => {
// Should provide an event to pass value to Form.
const onChange = this.props.onChange;
if (onChange) {
onChange(changedValue);
}
};
source = [
{
order_id: 1,
name: '邮箱账号',
type: 'account',
app_id: '',
app_key: '',
},
{
order_id: 2,
name: '谷歌账号',
type: 'google',
app_id: '',
app_key: '',
},
{
order_id: 3,
name: 'Facebook账号',
type: 'facebook',
app_id: '',
app_key: '',
use_union_id: false
},
{
order_id: 4,
name: 'NAVER账号',
type: 'naver',
app_id: '',
app_key: '',
},
{
order_id: 5,
name: 'Line账号',
type: 'line',
app_id: '',
app_key: '',
},
{
order_id: 6,
name: 'Twitter账号',
type: 'twitter',
app_id: '',
app_key: '',
},
{
order_id: 7,
name: 'Apple账号',
type: 'apple',
app_id: '',
app_key: '',
first_priority_login: false
},
{
order_id: 8,
name: '游客登录',
type: 'guest',
app_id: '',
app_key: '',
},
{
order_id: 9,
name: '引继码登录',
type: 'citation',
app_id: '',
app_key: '',
}
]
columns = [{
title: '顺序',
dataIndex: 'order_id',
key: 'order_id',
width: 80,
}, {
title: '登录方式',
dataIndex: 'name',
key: 'name',
width: 150,
}, {
title: '参数',
dataIndex: 'app_id',
key: 'app_id',
width: 250,
render: (text, record, index) => {
if (record.type == 'guest' || record.type == 'account' || record.type == 'citation' ) {
return <span></span>
}
let idPlaceholder = 'APP ID'
let secretPlaceholder = 'APP SECRET'
switch (record.type) {
case 'google':
idPlaceholder = 'Google_SERVER_CLIENT_ID'
break
case 'facebook':
idPlaceholder = 'APP ID'
secretPlaceholder = 'APP KEY'
break
case 'naver':
idPlaceholder = 'NV_clinet_ID'
secretPlaceholder = 'NV_clinet_SECRET'
break
case 'line':
idPlaceholder = 'Channel ID'
secretPlaceholder = 'Channel Secret'
break
case 'twitter':
idPlaceholder = 'Custom key'
secretPlaceholder = 'Custom Secret'
break
case 'apple':
idPlaceholder = 'APP ID'
}
let appSecretDom = ''
let unionIDDom = ''
let priorityLoginDom = ''
if (record.type == 'facebook' || record.type == 'naver' || record.type == 'line' || record.type == 'twitter') {
appSecretDom = (
<div style={{ marginTop: "15px" }}>
<span>
{secretPlaceholder}
</span>
<Input placeholder={secretPlaceholder} value={record.app_key}
onChange={(e) => {
this.state.data[index].app_key = e.target.value
// this.setState({ data: this.state.data })
this.triggerChange(this.state.data)
}}
/>
</div>
)
}
if (record.type == 'facebook') {
let defaultChecked = record.use_union_id == 1 ? true : false
unionIDDom = (
<div style={{ marginTop: "15px" }}>
<div>
UnionID开关
</div>
<Switch checkedChildren="开启" unCheckedChildren="关闭" checked={defaultChecked} onChange={(checked) => {
this.state.data[index].use_union_id = checked === true ? 1 : 0
// this.setState({ data: this.state.data })
this.triggerChange(this.state.data)
}} />
</div>
)
}
if (record.type == 'apple') {
let defaultChecked = record.first_priority_login == 1 ? true : false
priorityLoginDom = (
<div style={{ marginTop: "15px"}}>
<div>
首次启动自动登陆开关
</div>
<Switch checkedChildren="开启" unCheckedChildren="关闭" checked={defaultChecked} onChange={(checked) => {
this.state.data[index].first_priority_login = checked === true ? 1: 0
this.triggerChange(this.state.data)
}}/>
</div>
)
}
return (
<div>
<div>
<span>
{idPlaceholder}
</span>
<Input placeholder={idPlaceholder} value={record.app_id}
onChange={(e) => {
this.state.data[index].app_id = e.target.value
// this.setState({ data: this.state.data })
this.triggerChange(this.state.data)
}}
/>
<br />
</div>
{appSecretDom}
{unionIDDom}
{priorityLoginDom}
</div>
)
}
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
width: 180,
render: (text, record, index) => {
if(record.type !== 'guest'){
return <span >
<a disabled={index == 0} onClick={() => {
let item = this.state.data.splice(index, 1)[0]
this.state.data.splice(index - 1, 0, item)
this.triggerChange(this.state.data)
}}>上移</a>
<Divider type="vertical" />
<a disabled={index == this.state.data.length - 1} onClick={() => {
let item = this.state.data.splice(index, 1)[0]
this.state.data.splice(index + 1, 0, item)
this.triggerChange(this.state.data)
}}>下移</a>
<Divider type="vertical" />
<a onClick={() => {
let item = this.state.data.splice(index, 1)
this.triggerChange(this.state.data)
}}>删除</a>
</span>
}else {
return <span >
<a onClick={() => {
let item = this.state.data.splice(index, 1)
this.triggerChange(this.state.data)
}}>删除</a>
</span>
}
}
}];
unused_columns = [{
title: '登录方式',
dataIndex: 'name',
key: 'name',
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
render: (text, record, index) => (
<a onClick={() => {
this.addLoginType(record);
this.triggerChange(this.state.data)
}}>添加</a>
)
}];
addLoginType = (record) => {
let guestIndex = 0;
let hasGuest = false;
if(record.type !== 'guest'){
this.state.data.map((item,index)=>{
if(item.type === 'guest'){
guestIndex = index;
hasGuest = true;
}
});
if(hasGuest){
this.state.data.splice(guestIndex,0,record)
}else {
this.state.data.push(record)
}
}else {
this.state.data.push(record)
}
};
componentWillReceiveProps(props) {
const datasource = props.value || [];
let data = []
let unused_data = []
if (datasource.length == 0) {
if (this.state.unused_data.length == 0) {
data = JSON.parse(JSON.stringify(this.source))
}else{
unused_data = JSON.parse(JSON.stringify(this.source))
}
} else {
data = datasource
this.source.forEach(row => {
let item = datasource.find(i => {
return row.type == i.type
})
if (!item) {
unused_data.push(row)
}
})
}
let order_id = 1;
for(let item of data){
item.order_id = order_id++
}
this.setState({
data: data,
unused_data: unused_data
})
}
render() {
return (
<Fragment>
<Alert message="登录方式按顺序从小到大排序(UI从右到左)" type="warning" showIcon />
<br />
<Row gutter={24}>
<Col span={18} >
<Table rowKey="type" dataSource={this.state.data} columns={this.columns} title={() => '已选登录方式'} bordered pagination={false} />
</Col>
<Col span={6} >
<Table rowKey="type" dataSource={this.state.unused_data} columns={this.unused_columns} bordered title={() => '未选登录方式'} pagination={false} />
</Col>
</Row>
</Fragment>
)
}
}
import ItemLoginMethod from './ItemLoginMethod'
export default ItemLoginMethod
import React, { Fragment } from 'react'
import {Table, Divider, Row, Col, Alert, Input, Switch, Button} from 'antd';
const { TextArea } = Input;
export default class ItemProductList extends React.Component{
constructor(props) {
super(props);
this.state = {
data: [],
dataStr: '',
isChange: false
}
}
triggerChange = (changedValue) => {
// Should provide an event to pass value to Form.
const onChange = this.props.onChange;
if (onChange) {
onChange(changedValue);
}
};
column = [
{
title: '商品ID',
dataIndex: 'product_id',
key: 'product_id',
render: (text, record, index) => {
return (
<div>
<Input type="text" value={record.product_id} onChange={(e) => {
this.state.data[index].product_id = e.target.value;
this.triggerChange(this.state.data);
}}/>
</div>
);
}
},
{
title: '价格',
dataIndex: 'price',
key: 'price',
render: (text, record, index) => {
return (
<div>
<Input type="text" value={record.price} onChange={(e) => {
this.state.data[index].price = e.target.value;
this.triggerChange(this.state.data);
}}/>
</div>
);
}
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
render: (text, record, index) => {
return (
<div>
<a onClick={() => {
this.delProductInfo(index);
this.triggerChange(this.state.data);
}}>删除</a>
</div>
);
}
},
];
// componentWillReceiveProps(props) {
// const datasource = props.value || [];
// let data = []
// if (datasource.length == 0) {
// data = []
// } else {
// data = datasource
// }
// this.setState({
// data: data,
// })
// }
componentWillReceiveProps(props) {
if (this.state.isChange) {
return;
}
console.log('componentWillReceiveProps', props.value)
const datasource = props.value || [];
let data = [];
let that = this;
if (datasource.length == 0) {
data = []
} else {
data = datasource
}
this.setState({
data: data,
},() => {
that.getDataStr();
})
}
addProductInfo = () => {
this.state.data.push({
product_id: '',
price: ''
});
};
delProductInfo = (index) => {
this.state.data.splice(index, 1);
};
// componentWillMount() {
// const datasource = this.props.value || [];
// let data = [];
// let that = this;
// if (datasource.length == 0) {
// data = []
// } else {
// data = datasource
// }
// this.setState({
// data: data,
// },() => {
// that.getDataStr();
// })
// }
reorganizationData = (e) => {
let currentValue = e.target.value;
let currentValueList = currentValue.split('\n');
let dataList = [];
for (let index = 0; index < currentValueList.length; index++) {
const element = (currentValueList[index].trim()).replace(/\n/g,'');
if(element.trim() != ''){
// if(!element.split(":")[1] && element.split(":")[0]) {
// if(element.split(":").length==1) {
// content = content + element.split(":")[0] + "\n";
// }else {
// content = content + element.split(":")[0] + ":" + "\n";
// }
// }else if(!element.split(":")[0] && element.split(":")[1]) {
// content = content + ":" + element.split(":")[1] + "\n";
// } else if(!element.split(":")[1] && !element.split(":")[0]) {
// content = content + ":" + "\n";
// }
let dataObj = {};
dataObj.price = element.split(":")[1];
dataObj.product_id = element.split(":")[0];
dataList.push(dataObj);
}
}
this.setState({
dataStr: currentValue,
isChange: true
}, () => {
this.triggerChange(dataList)
})
// console.log(dataList)
// this.state.data = dataList;
// this.triggerChange(dataList);
}
getDataStr = () => {
let dataStr = "";
this.state.data.map((item, index) => {
dataStr = dataStr + item.product_id + ':' + item.price + "\n";
})
this.setState({
dataStr: dataStr
})
}
render() {
return (
<Fragment>
{/*<Table dataSource={this.source} columns={this.column} />*/}
<Row gutter={10}>
<Col span={36} >
<TextArea rows={10} onChange={(e) => {this.reorganizationData(e)}}
value={this.state.dataStr} />
{/* <Table dataSource={this.state.data} columns={this.column} pagination={false} /> */}
</Col>
{/*<Col span={6} >*/}
{/* <Table rowKey="type" dataSource={this.state.unused_data} columns={this.unused_columns} bordered title={() => '未选登录方式'} pagination={false} />*/}
{/*</Col>*/}
</Row>
{/* <Button block type={"dashed"} onClick={() => {
this.addProductInfo();
this.triggerChange(this.state.data);
}}> + 添加</Button> */}
</Fragment>
);
}
}
import ItemProductList from "./ItemProductList";
export default ItemProductList;
import React, {Fragment} from 'react'
import { Form, Radio, Select } from 'antd'
import './ItemRadioSelect.scss'
const Option = Select.Option;
const RadioGroup = Radio.Group;
export default class ItemRadioSelect extends React.Component{
constructor(props){
super(props);
this.state = {
disabled: true,
}
}
onChange = (e) => {
if(e.target.value ===1 ){
this.setState({
disabled: true,
})
}else {
this.setState({
disabled: false,
})
}
this.setState({
value: e.target.value,
});
};
componentDidMount() {
if(this.props.dataSource[this.props.item.key.radio].initialValue < 1){
this.setState({
disabled:false,
})
}
}
componentWillReceiveProps(nextProps, nextContext) {
if(nextProps.dataSource[this.props.item.key.radio].initialValue > 0){
this.setState({
disabled:true,
})
}
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Fragment>
<Form.Item label={
<span>
<i className={'iconfont '+ this.props.item.transfer}></i>
{this.props.item.label.radio}
</span>
} {...this.props.formItemLayout}>
{getFieldDecorator(this.props.item.key.radio, {
initialValue: this.props.dataSource[this.props.item.key.radio]?this.props.dataSource[this.props.item.key.radio].initialValue:null,
rules: [
{
required: this.props.item.required,
message: '必须',
},
],
})(
<RadioGroup onChange={this.onChange}>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</RadioGroup>
)}
</Form.Item>
<Form.Item label={this.props.item.label.select} {...this.props.formItemLayout}>
{getFieldDecorator(this.props.item.key.select, {
initialValue: this.props.dataSource[this.props.item.key.select].initialValue?this.props.dataSource[this.props.item.key.select].initialValue:[],
rules: [
{
required: this.state.disabled,
message: '必须',
},
],
})(
<Select disabled={!this.state.disabled} style={{ width: 120 }} onChange={this.handleChange}>
{
this.props.item.data.select.map((item,i)=> {
return <Option value={item.id}>{item.name}</Option>
})
}
</Select>
)}
</Form.Item>
</Fragment>
);
}
}
.wechat{
color: #7AE62F;
margin-right: 6px;
font-size: 22px;
vertical-align: middle;
&:before{
content: '\e668';
}
}
.alipay{
color: #65C7FF;
margin-right: 6px;
font-size: 22px;
vertical-align: middle;
&:before{
content: '\e64a';
}
}
import ItemRadioSelect from './ItemRadioSelect'
export default ItemRadioSelect;
import React,{Fragment} from 'react'
import { Select, Form } from 'antd';
import HttpClient from '../../../../service/HttpClient'
import Api from '../../../../service/Api'
const Option = Select.Option;
export default class SelectAdd extends React.Component{
constructor(props){
super(props);
this.state = {
platform: [],
app: [],
proSelect:'',
}
}
handlePlatformChange = (id) => {
this.setState({proSelect:''});
this.getProjectList({operator_id:id,flatten:1}).then(data => {
this.setState({
app: data.list,
});
})
};
onProjectChange = (value) => {
this.props.getParams(value);
this.setState({proSelect:value.id});
this.getAppList({project_id:value.id,flatten:1}).then(data => {
this.props.getRadioData(data);
})
};
componentDidMount() {
this.getPlatForm({limit:100}).then(data => {
this.setState({
platform:data,
})
})
}
async getPlatForm(params){
return await HttpClient.get(Api.operation_all_platform,params)
}
async getProjectList(params){
return await HttpClient.get(Api.project_list, params)
}
async getAppList(params){
return await HttpClient.get(Api.app_list,params)
}
render() {
const { getFieldDecorator } = this.props.form;
return(
<Fragment>
<Form.Item label={this.props.item.label} {...this.props.formItemLayout}>
{getFieldDecorator(this.props.item.key.first_key, {
rules: [
{
required: true,
message: '必须',
},
],
})(
<Select className="mr-20" style={{ width: 120 }}>
{this.state.platform.map(item => <Option key={item.id} onClick={() =>this.handlePlatformChange(item.id)}>{item.name}</Option>)}
</Select>
)}
{getFieldDecorator(this.props.item.key.second_key, {
rules: [
{
required: true,
message: '必须',
},
],
})(
<Select style={{ width: 200 }} value={this.state.proSelect}>
{this.state.app.map(item => <Option key={item.id} value={[item.name,item.id]} onClick={()=>this.onProjectChange(item)}>{item.name}</Option>)}
</Select>
)}
</Form.Item>
</Fragment>
)
}
}
import ItemSelectPlus from './ItemSelectPlus'
export default ItemSelectPlus
import React,{Fragment} from 'react';
import axios from 'axios';
import {Upload, Icon, Modal, message, Form, Select} from 'antd';
import HttpClient from "../../../../service/HttpClient";
import Api from "../../../../service/Api";
export default class ItemUploader extends React.Component{
constructor(props){
super(props);
this.state = {
previewVisible: false,
previewImage: '',
fileList: [],
}
}
componentWillReceiveProps(nextProps, nextContext) {
if (nextProps.value) {
this.setState({
fileList: [
{
uid: '-1',
url: nextProps.value,
status: 'done',
},
],
})
}
}
beforeUpload=(file)=>{
if (!file.type === 'image/png' || !file.type === 'image/jpeg') {
message.error('您上传的文件格式不支持!');
return false
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('请小于2M!');
return false
}
return true;
};
handleChange = ({fileList}) => {
if(fileList.length === 0){
this.setState({fileList:[]});
this.props.onChange(undefined);
}
this.setState({fileList});
}
handleCancel = (e) => {
this.setState({ previewVisible: false })
}
handlePreview = (file) => {
this.setState({
previewImage: file.url || file.thumbUrl,
previewVisible: true,
});
};
customRequest = (option)=> {
this.getToken({name:option.file.name,type:option.file.type}).then(data =>{
let param = new FormData(); // 创建form对象
let fileList = Object.assign([],this.state.fileList);
param.append('name', option.file.name);// 通过append向form对象添加数据
param.append('key', data.key);
param.append('policy', data.policy);
param.append('OSSAccessKeyId', data.accessid);
param.append('success_action_status', 200);
param.append('signature', data.signature);
param.append('file', option.file, option.file.name);
let up = axios.create({
timeout: 15000,// 请求超时时间
headers: {
'Content-Type': 'multipart/form-data',
},
});
let arr = [];
up.post(data.host, param).then(response => {
this.state.fileList = this.state.fileList.map((item,index)=>{
if(option.file.uid === item.uid){
return {
uid: option.file.uid,
name: option.file.name,
status: 'done',
url: `${data.host}/${data.key}`,
}
}
});
this.setState({
fileList:this.state.fileList,
})
this.props.onChange(this.state.fileList[0].url);
}).catch(function (error) {
message.error('上传失败!',1)
});
})
};
async getToken(params){
return await HttpClient.get(Api.upload_token,params);
}
componentDidMount() {
}
render() {
const { previewVisible, previewImage, fileList } = this.state;
const uploadButton = (
<div>
<Icon type="plus" />
<div className="ant-upload-text">上传</div>
</div>
);
return(
<div className="ctm-clearfix">
<Upload
listType="picture-card"
fileList={fileList}
beforeUpload={this.beforeUpload}
customRequest={this.customRequest}
onPreview={this.handlePreview}
onChange={this.handleChange}
>
{fileList.length >= 1 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
<img alt="预览" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
)
}
}
import ItemUpload from './ItemUpload'
export default ItemUpload;
import ItemForm from './ItemForm'
export default ItemForm;
import React,{Fragment} from 'react';
import { Modal } from 'antd';
import ItemForm from '../ItemForm'
export default class ItemModal extends React.Component{
constructor(props){
super(props);
this.state = {
visible: false,
dataSource:{},
config:[],
};
this.modalConfirm = React.createRef();
}
modalConfirm;
showModal = () => {
this.setState({
visible: true,
});
};
handleOk = () => {
this.modalConfirm.handleSubmit();
if(this.props.config && this.props.config.autoClose){
this.handleCancel();
}
};
handleCancel = () => {
this.setState({
visible: false,
});
this.modalConfirm.handleReset();
};
getReqParams=(values,err)=>{
if(!err){
this.props.config.getOutput(values)
}
}
componentWillReceiveProps(nextProps, nextContext) {
this.setState({
dataSource:nextProps.config.dataSource,
config:nextProps.config.render
})
}
render() {
const { visible, confirmLoading } = this.state;
return(
<div>
<Modal
title={this.props.config.title}
visible={visible}
onOk={this.handleOk}
onCancel={this.handleCancel}
>
<div>
<ItemForm wrappedComponentRef={r => this.modalConfirm = r} dataSource={this.state.dataSource} config={this.state.config} getReqParams={this.getReqParams}/>
</div>
</Modal>
</div>
)
}
}
import ItemModal from './ItemModal'
export default ItemModal;
import React, { Component } from 'react';
import './ItemName.scss'
export default class ItemName extends Component{
constructor(props){
super(props)
}
render() {
return(
<div className="title">
<p>{this.props.itemName}</p>
</div>
)
}
}
.title{
>p{
line-height: 62px;
font-size: 20px;
border-bottom: 1px solid #E5E5E5;
}
}
import ItemName from './ItemName'
export default ItemName;
import React, { Component, Fragment } from 'react';
import { withRouter } from "react-router-dom";
import { Breadcrumb, Button } from 'antd';
import { get } from "../../service/Global";
import './ItemNav.scss'
@withRouter
export default class ItemNav extends Component {
constructor(props) {
super(props)
this.state = {
a: '',
}
}
componentWillMount() {
this.setState({
a: get('readonly')
})
}
render() {
return (
<Fragment>
<div className="breadcrumb-nav">
{
(() => {
if (this.props.itemNav.list) {
return (
<div className="nav-group">
<Breadcrumb>
{
this.props.itemNav.list.map((item, i) => {
return (
<Breadcrumb.Item key={i.toString()}>{item.anchor}</Breadcrumb.Item>
)
})
}
</Breadcrumb>
</div>
)
}
})()
}
{
(() => {
if (this.props.itemNav.extends) {
return (
<div className="btn-group">
{
this.props.itemNav.extends.map((item, i) => {
if (item.url) {
return (
<Button key={i.toString()} type={item.type} onClick={() => { this.props.history.push(item.url) }} disabled={this.state.a == 1 ? true : false}>
{
(() => {
if (item.icon) {
return <i className="iconfont" dangerouslySetInnerHTML={{ __html: item.icon }}></i>
}
})()
}
{item.label}
</Button>
)
} else if (item.render) {
return item.render()
}
})
}
</div>
)
}
})()
}
</div>
</Fragment>
)
}
}
.breadcrumb-nav{
color: #404040;
height: 60px;
background-color: #ffffff;
@include clearfix;
.nav-group{
padding-left: 30px;
float: left;
span{
font-size: 20px;
line-height: 60px;
}
}
.btn-group{
float: right;
margin-top: 14px;
margin-right: 30px;
}
}
import ItemNav from './ItemNav';
export default ItemNav
import React, {Component, Fragment} from 'react';
import { Table} from 'antd';
export default class ItemTable extends Component{
constructor(props){
super(props)
}
render() {
return(
<Fragment>
{
(()=>{
if(this.props.scroll){
return <Table rowKey='id' bordered scroll={this.props.scroll} onChange={this.props.onChange || null} columns={this.props.columns} dataSource={this.props.dataSource.data} pagination={{onChange: this.props.pager,pageSize:this.props.dataSource.pageSize,current:this.props.dataSource.page,total:this.props.dataSource.totalNum}} rowSelection={this.props.rowSelection}/>
}else {
return <Table rowKey='id' bordered onChange={this.props.onChange || null} columns={this.props.columns} dataSource={this.props.dataSource.data} pagination={{onChange: this.props.pager,pageSize:this.props.dataSource.pageSize,current:this.props.dataSource.page,total:this.props.dataSource.totalNum}} rowSelection={this.props.rowSelection}/>
}
})()
}
</Fragment>
)
}
}
import ItemTable from './ItemTable'
export default ItemTable
import React, {Component, Fragment} from 'react'
import {Form, Select, Input, Switch, Radio, Slider, Button, DatePicker, Row, Col} from 'antd';
import './ItemTableQuery.scss'
const {Option} = Select;
const {RangePicker} = DatePicker;
class Tpl extends Component {
constructor(props) {
super(props);
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, fieldsValue) => {
if (err) {
return
}
let values ={};
if(fieldsValue.range_picker){
const rangeValue = fieldsValue['range_picker'];
values = {
...fieldsValue,
'range_picker': [rangeValue[0].format('YYYY-MM-DD'), rangeValue[1].format('YYYY-MM-DD')],
};
}else {
values = {
...fieldsValue,
};
}
this.props.getTableQuery(values);
});
};
handleReset = (e) => {
this.props.form.resetFields();
this.props.resetParams();
this.handleSubmit(e)
};
render() {
const {getFieldDecorator} = this.props.form;
return (
<Form layout="inline" onSubmit={this.handleSubmit}>
{
this.props.itemTableQuery.map((item, i) => {
switch (item.type) {
case 'range_picker':
return (
<Form.Item label={item.label} key={i}>
{getFieldDecorator('range_picker',
{
initialValue:item.defaultSelectDate || null,
rules: [
{
type: 'array',
required: item.required||false,
message: '请选择时间!'
}],
})(
<RangePicker disabledDate={item.disabledDate||null}/>
)}
</Form.Item>
);
case 'input':
return (
<Form.Item label={item.label} key={i}>
{getFieldDecorator(item.key, {
rules: [{
required: item.required,
message: item.placeholder,
}],
})(
<Input placeholder={item.placeholder} style={{minWidth:'260px'}}/>
)}
</Form.Item>
);
case 'select':
return (
<Form.Item label={item.label} key={i}>
{getFieldDecorator(item.key, {
initialValue: item.defaultValue?item.defaultValue:undefined,
rules: [
{required: item.required, message: item.placeholder},
],
})(
<Select onChange={item.onChange || null} disabled={item.disabled||false} placeholder={item.placeholder} style={{minWidth:'160px'}} allowClear mode={item.mode}>
{
item.data.map((item,index) => {
if(item)
return <Option value={item.id} key={index}>{item.name}</Option>
})
}
</Select>
)}
</Form.Item>
);
case 'radio':
return (
<Form.Item label={item.label} key={i} {...this.formItemLayout}>
{getFieldDecorator(item.key, {
initialValue: this.props.dataSource[item.key]
? this.props.dataSource[item.key]
: undefined,
rules: [
{
required: item.required,
message: "缺少" + item.label
}
]
})(
<Radio.Group>
{item.data.map((data, index) => {
return <Radio value={data.id} key={index}>{data.name}</Radio>;
})}
</Radio.Group>
)}
</Form.Item>
)
case 'submit':
return (
<Form.Item key={i} >
{
(()=> {
switch (item.extend) {
case true:
return item.render;
default: return <Fragment>
<Button type="primary" htmlType="submit" className="mr-20">查询</Button>
{/* <Button onClick={this.handleReset}>重置</Button> */}
{
(()=>{
if(item.render){
return item.render
}else {
return null
}
})()
}
</Fragment>
}
})()
}
</Form.Item>
)
}
})
}
</Form>
)
}
}
const ItemTableQuery = Form.create({name: 'form_query'})(Tpl);
export default ItemTableQuery;
.item-table-query{
display: inline-block;
margin-bottom: 20px;
@include clearfix;
.item{
margin-right: 20px;
}
}
import ItemTableQuery from './ItemTableQuery'
export default ItemTableQuery
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import IceContainer from '@icedesign/container';
import './NotFound.scss';
export default class NotFound extends Component {
static displayName = 'NotFound';
render() {
return (
<div className="basic-not-found">
<IceContainer>
<div style={styles.exceptionContent} className="exception-content">
<img
src="https://img.alicdn.com/tfs/TB1txw7bNrI8KJjy0FpXXb5hVXa-260-260.png"
style={styles.image}
className="imgException"
alt="页面不存在"
/>
<div className="prompt">
<h3 style={styles.title} className="title">
抱歉,你访问的页面不存在
</h3>
<p style={styles.description} className="description">
您要找的页面没有找到,请返回
<Link to="/">首页</Link>
继续浏览
</p>
</div>
</div>
</IceContainer>
</div>
);
}
}
const styles = {
exceptionContent: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
},
title: {
color: '#333',
},
description: {
color: '#666',
},
};
@media screen and (max-width: 720px) {
.exception-content {
min-height: 200px;
.imgException {
max-width: 100px;
margin-right: 10px;
}
.title {
font-size: 14px;
margin: 10px 0;
}
.description {
font-size: 12px;
}
}
}
@media screen and (min-width: 721px) and (max-width: 1199px) {
.exception-content {
min-height: 300px;
.imgException {
max-width: 180px;
margin-right: 30px;
}
.title {
font-size: 20px;
margin: 10px 0;
}
.description {
font-size: 14px;
}
}
}
@media screen and (min-width: 1200px) {
.exception-content {
min-height: 500px;
.imgException {
max-width: 260px;
margin-right: 50px;
}
.title {
font-size: 24px;
margin: 20px 0;
}
.description {
font-size: 16px;
}
}
}
import NotFound from './NotFound';
export default NotFound;
This diff is collapsed.
This diff is collapsed.
import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter } from 'react-router-dom';
// 载入默认全局样式 normalize 、.clearfix 和一些 mixin 方法等
import './style/antd-loader.less'
import '@alifd/next/reset.scss';
import './style/public.scss';
import router from './router';
require('./action');
const ICE_CONTAINER = document.getElementById('ice-container');
if (!ICE_CONTAINER) {
throw new Error('当前页面不存在 <div id="ice-container"></div> 节点.');
}
ReactDOM.render(
<HashRouter>{router()}</HashRouter>,
ICE_CONTAINER
);
import React, { Component } from 'react';
import { Layout } from 'antd';
import {Action, Store} from 'marine';
import { withRouter,hashHistory } from 'react-router-dom';
import Headers from './components/Headers';
import Aside from './components/Aside';
import MainRoutes from './MainRoutes';
import { ConfigProvider } from 'antd';
import zh_CN from 'antd/lib/locale-provider/zh_CN';
import moment from 'moment';
import 'moment/locale/zh-cn';
import {set} from "../../service/Global";
import {hasIt} from "../../service/utils";
moment.locale('zh-cn');
const {Content} = Layout;
@withRouter
export default class BasicLayout extends Component {
constructor(props) {
super(props);
this.state = {
projectId:''
};
}
projectIdChange = (id)=>{
Action.global.getProjectId({project_id:id});
this.setState({
projectId:id
});
if(!hasIt('/app/list',window.location.href)){
// this.props.history.push('/app/list')
}
};
componentDidMount() {
Store.on('global.projectIdSave',StoreDate =>{
set('project_id', StoreDate.data.project_id);
})
}
render() {
return (
<Layout style={{height:'100%'}}>
<Aside />
<Layout>
<Headers history={this.props.history}/>
{
<Content style={{overFlow:'hidden'}}>
<ConfigProvider locale={zh_CN}>
<MainRoutes/>
</ConfigProvider>
</Content>
}
</Layout>
</Layout>
);
}
}
import React from 'react'
import Login from "../../pages/Login";
export default class LoginLayout extends React.Component{
constructor(props){
super(props)
}
render() {
return(
<section>
<Login />
</section>
)
}
}
import React, { Component } from 'react';
import { Redirect, Switch, Route } from 'react-router-dom';
import { asideMenuConfig } from '../../menuConfig';
import routerData from '../../routerConfig';
import NotFound from '../../components/NotFound'
import {clear, get} from "../../service/Global";
import HttpClient from "../../service/HttpClient";
import Api from '../../service/Api'
let old = [{
name: '监控预警',
path: '/monitor',
icon: '&#xe654;',
authority: 'user',
children: [{
name: '提现监控管理',
path: '/monitor/manage',
authority: 'user',
},
{
name: '通知管理人',
path: '/monitor/manger',
authority: 'user',
},
{
name: '报警通知',
path: '/monitor/inform',
authority: 'user',
},
]
},
{
name: '玩家查询',
path: '/query',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '玩家货币查询',
path: '/query/player',
authority: 'user',
},
]
},
{
name: '白名单',
path: '/white',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '白名单管理',
path: '/white/mange',
authority: 'user',
},
]
},
{
name: '系统设置',
path: '/set',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '用户管理',
path: '/set/user',
authority: 'user',
},
]
}
];
class MainRoutes extends Component {
static displayName = 'MainRoutes';
constructor(props) {
super(props);
this.state = {
asideMenuConfig: []
}
}
componentWillMount() {
this.setState({
asideMenuConfig:old
})
// let scanType = get('scanCode');
// if (scanType == 0) {
// this.setState({
// asideMenuConfig:old
// })
// } else {
// this.headerMenuConfigs();
// }
}
headerMenuConfigs = () => {
HttpClient.get(Api.menu).then(data => {
this.setState({
asideMenuConfig: data
})
})
}
/**
* 根据菜单取得重定向地址.
*/
getRedirectData = () => {
const asideMenuConfig=this.state.asideMenuConfig
const redirectData = [];
const getRedirect = (item) => {
if (item && item.children) {
if (item.children[0] && item.children[0].path) {
redirectData.push({
from: `${item.path}`,
to: `${item.children[0].path}`,
});
item.children.forEach((children) => {
getRedirect(children);
});
}
}
};
asideMenuConfig.forEach(getRedirect);
return redirectData;
};
/**
* 渲染路由组件
*/
renderNormalRoute = (item, index) => {
let token = get('token');
if(item.authority === 'admin'){
if (token) {
if(get('overdue_data') < Date.now()){
clear();
window.location.href='/#/login';
return
}
} else {
window.location.href='/#/login';
return
}
}
return item.component ? (
<Route
key={index}
path={item.path}
component={item.component}
exact={item.exact}
/>
) : null;
};
render() {
const redirectData = this.getRedirectData();
return (
<Switch>
{/* 渲染路由表 */}
{routerData.map(this.renderNormalRoute)}
{/* 路由重定向,嵌套路由默认重定向到当前菜单的第一个路由 */}
{redirectData.map((item, index) => {
return <Redirect key={index} exact from={item.from} to={item.to} />;
})}
<Redirect exact from="/" to="/" />
{/* 未匹配到的路由重定向到 <Guide> 组件,实际情况应该重定向到 404 */}
<Route component={NotFound} />
</Switch>
);
}
}
export default MainRoutes;
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import { Menu, Icon, Button, Layout } from 'antd';
import { get,set } from "../../../../service/Global";
import HttpClient from "../../../../service/HttpClient";
import Api from '../../../../service/Api'
import Logo from '../Logo/Logo'
import { asideMenuConfig } from '../../../../menuConfig';
const SubMenu = Menu.SubMenu;
const { Sider } = Layout;
let old = [{
name: '监控预警',
path: '/monitor',
icon: '&#xe654;',
authority: 'user',
children: [{
name: '提现监控管理',
path: '/monitor/manage',
authority: 'user',
},
{
name: '通知管理人',
path: '/monitor/manger',
authority: 'user',
},
{
name: '报警通知',
path: '/monitor/inform',
authority: 'user',
},
]
},
{
name: '玩家查询',
path: '/query',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '玩家货币查询',
path: '/query/player',
authority: 'user',
},
]
},
{
name: '白名单',
path: '/white',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '白名单管理',
path: '/white/mange',
authority: 'user',
},
]
},
{
name: '系统设置',
path: '/set',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '用户管理',
path: '/set/user',
authority: 'user',
},
]
}
];
@withRouter
export default class Aside extends Component {
constructor(props) {
super(props);
this.state = {
asideMenuConfig: []
}
}
componentWillMount() {
this.setState({
asideMenuConfig:old
})
// let scanType = get('scanCode');
// if (scanType == 0) {
// } else {
// this.headerMenuConfigs();
// }
}
headerMenuConfigs = () => {
HttpClient.get(Api.menu).then(data => {
this.setState({
asideMenuConfig: data
})
})
}
/**
* 获取默认展开菜单项
*/
getDefaultOpenKeys = () => {
const { location = {} } = this.props;
const { pathname } = location;
const asideMenuConfig=this.state.asideMenuConfig
const menus = this.getNavMenuItems(asideMenuConfig);
let openKeys = [];
if (Array.isArray(menus)) {
asideMenuConfig.forEach((item, index) => {
if (pathname.startsWith(item.path)) {
openKeys = [`${index}`];
}
});
}
return openKeys;
};
toggleCollapsed = () => {
this.setState({
collapsed: !this.state.collapsed,
});
};
/**
* 获取菜单项数据
*/
getNavMenuItems = (menusData) => {
if (!menusData) {
return [];
}
return menusData.filter(item => item.name && !item.hideInMenu).map((item, index) => {
const role = get('role');
if (item.authority === 'user') {
return this.getSubMenuOrItem(item, index);
} else {
if (role === 'admin' || role === 'configurer') {
return this.getSubMenuOrItem(item, index);
}
}
});
};
handleClick=(item)=>{
// if(!item){return}
set('readonly',item)
}
/**
* 二级导航
*/
getSubMenuOrItem = (item, index) => {
if (item.children && item.children.some(child => child.name)) {
const childrenItems = this.getNavMenuItems(item.children);
if (childrenItems && childrenItems.length > 0) {
return (
<SubMenu key={item.path + index} title={<span>
{
(() => {
if (item.icon) {
return <i className="iconfont mr-12" dangerouslySetInnerHTML={{ __html: item.icon }}></i>
} else {
return null
}
})()
}
{item.name}
</span>}>
{childrenItems}
</SubMenu>
);
}
return null;
}
return (
<Menu.Item key={'#' + item.path}>
<Link to={item.path} onClick={()=>this.handleClick(item.readonly)}>
{
(() => {
if (item.icon) {
return <i className="iconfont mr-12" dangerouslySetInnerHTML={{ __html: item.icon }}></i>
} else {
return null
}
})()
}
{item.name}
</Link>
</Menu.Item>
);
};
render() {
const asideMenuConfig=this.state.asideMenuConfig
return (
<Sider style={{ height: '100%', maxWidth: '160px', backgroundColor: '#FFF', boxShadow: '0 1px 10px rgba(200,200,200,.5)', zIndex: '999' }}>
<Logo />
<Menu selectedKeys={[window.location.hash]} defaultOpenKeys={['sub0']} mode="inline">
{this.getNavMenuItems(asideMenuConfig)}
</Menu>
</Sider>
)
}
}
import Aside from './Aside';
export default Aside;
import React, { PureComponent } from 'react';
import { Layout } from 'antd';
const {Footer} = Layout;
export default class Footers extends PureComponent {
render() {
return (
<Footer style={{ textAlign: 'center' }}>
Kingnet ©2019 应用接入系统
</Footer>
);
}
}
import Footers from './Footers';
export default Footers;
import React, { PureComponent } from "react";
import { Layout, Menu, Dropdown, Icon, Select, Form } from "antd";
import {get, getObj, set} from "../../../../service/Global";
import HttpClient from "../../../../service/HttpClient";
import Api from "../../../../service/Api";
import {hasIt} from "../../../../service/utils";
const { Header } = Layout;
@Form.create()
export default class Headers extends PureComponent {
state = {
loginInfo: { ...getObj("login_info") },
projectList:[],
projectId:''
};
getMenu = () => {
if (!this.state.loginInfo) {
return "";
} else {
return (
<Menu>
<Menu.Item key="1">
<a rel="noopener noreferrer" href="/#/account/change_password">
修改密码
</a>
</Menu.Item>
<Menu.Item key="2">
<a rel="noopener noreferrer" onClick={this.Logout}>
退出登录
</a>
</Menu.Item>
</Menu>
);
}
};
Logout=()=>{
return HttpClient.post(Api.logout).then(data => {
if(data){
this.props.history.push({
pathname:'/login'
})
}
})
}
// getProjectIds(params) {
// HttpClient.get(Api.projects, params).then(data => {
// if(data && data.data.length > 0){
// set('project_id', data.data[0].id);
// this.props.projectIdChange(data.data[0].id);
// this.setState({
// projectList: data.data,
// });
// }
// });
// }
componentDidMount() {
// this.getProjectIds({page_size:9999});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Header style={{ padding: "0 40px" }} className="ctm-clearfix">
<div className="ctm-right">
<Dropdown overlay={this.getMenu}>
<a className="ant-dropdown-link" style={{ color: "#fff" }}>
<span className="mr-12">Hi! {this.state.loginInfo.name}</span>
<Icon type="down" />
</a>
</Dropdown>
</div>
</Header>
);
}
}
import Headers from './Headers';
export default Headers;
import React, { PureComponent } from 'react';
import { Link } from 'react-router-dom';
import './Logo.scss';
export default class Logo extends PureComponent {
render() {
return (
<div className="logo">
<Link to="/" className="logo-text"><i className="iconfont" style={{color:''}}>&#xe659;</i><span className="ml-10">夜店后台管理</span></Link>
</div>
);
}
}
.logo {
max-width: 256px;
height: 64px;
line-height: 64px;
text-align: center;
// border-bottom: 1px solid #E5E5E5;
.logo-text {
display: block;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 22px;
// color: #FF751A;
font-weight: bold;
>i{
font-weight: lighter;
font-size: 24px;
}
}
}
@media screen and (max-width: 1199px) {
.logo {
width: 80px;
.logo-text {
font-size: 22px;
}
}
}
import Logo from './Logo';
export default Logo;
import BasicLayout from './BasicLayout';
export default BasicLayout;
.ice-design-layout-dark {
&.ice-design-layout {
min-height: 100vh;
background-size: 100%;
background-repeat: no-repeat;
background-attachment: fixed;
}
.ice-layout {
width: 100%;
min-height: 100vh;
padding: 0 20px;
// background: transparent;
}
.ice-layout-main {
padding: 0 0 0 20px;
}
.ice-layout-section {
margin: 20px 0 0;
}
}
import HttpClient from "./service/HttpClient";
import Api from './service/Api'
import { get } from "./service/Global";
let asideMenuConfig =[{
name: '监控预警',
path: '/monitor',
icon: '&#xe654;',
authority: 'user',
children: [{
name: '提现监控管理',
path: '/monitor/manage',
authority: 'user',
},
{
name: '通知管理人',
path: '/monitor/manger',
authority: 'user',
},
{
name: '报警通知',
path: '/monitor/inform',
authority: 'user',
},
]
},
{
name: '玩家查询',
path: '/query',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '玩家货币查询',
path: '/query/player',
authority: 'user',
},
]
},
{
name: '白名单',
path: '/white',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '白名单管理',
path: '/white/mange',
authority: 'user',
},
]
},
{
name: '系统设置',
path: '/set',
icon: '&#xe657;',
authority: 'user',
children:[
{
name: '用户管理',
path: '/set/user',
authority: 'user',
},
]
}
];
// let scanType = get('scanCode');
// if (scanType == 0||!scanType) {
// asideMenuConfig = old;
// } else {
// const headerMenuConfigs = function () {
// HttpClient.get(Api.menu).then(data => {
// asideMenuConfig = data.data;
// })
// };
// headerMenuConfigs();
// }
const headerMenuConfig = []
export {
headerMenuConfig,
asideMenuConfig
};
import React, { Component, Fragment } from "react";
import ItemNav from "../../components/ItemNav";
import ItemName from "../../components/ItemName";
import ItemForm from "../../components/ItemForm";
import { Button, message, Alert } from "antd";
import HttpClient from "../../service/HttpClient";
import Api from "../../service/Api";
import { getObj } from "../../service/Global";
import { locale } from "moment";
export default class AccountChangePassword extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: {
...getObj('login_info')
},
};
}
itemNav = {
list: [{ anchor: "账户配置" }, { anchor: "重置密码" }]
};
itemName = "账户信息";
back = () => {
location.href = '/#/login'
};
formItemLayout = {
labelCol: {
xs: { span: 4 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 4 },
sm: { span: 4 }
}
};
config = [
{
type: "input",
label: "用户ID",
placeholder: "请输入...",
key: "id",
required: true,
disabled : true
},
{
type: "password",
label: "重置密码",
placeholder: "请输入...",
key: "pwd",
required: true,
},
// {
// type: "password",
// label: "新密码",
// placeholder: "请输入...",
// key: "new_password",
// required: true,
// },
// {
// type: "password",
// label: "确认密码",
// placeholder: "请输入...",
// key: "confirm_new_password",
// required: true,
// },
{
type: "submit",
extend: true,
render: (
<Fragment>
<Button type="primary" htmlType="submit" className="mr-20">
提交
</Button>
{/* <Button onClick={this.onClose}>返回</Button> */}
</Fragment>
)
}
];
getReqParams = params => {
// if(params.new_password != params.confirm_new_password){
// message.error('确认密码不一致')
// return
// }
this.changePassword({ ...params});
};
async getInfo(id) {
return await HttpClient.get(Api.get_user_list + "/" + id);
}
async changePassword(data) {
return await HttpClient.post(Api.rePwd, data).then(
data => {
if (data) {
message.success("操作成功", 1, this.back);
}
}
);
}
componentDidMount() {
}
render() {
return (
<Fragment>
<ItemNav itemNav={this.itemNav} />
<section className="content-base">
<ItemForm
config={this.config}
dataSource={this.state.dataSource}
formItemLayout={this.formItemLayout}
getReqParams={this.getReqParams}
/>
</section>
</Fragment>
);
}
}
import AccountChangePassword from './AccountChangePassword'
export default AccountChangePassword
import React from 'react'
import {Form, Icon, Input, Button} from 'antd'
import {withRouter} from "react-router-dom";
import {set, setObj,clear} from "../../service/Global";
import HttpClient from '../../service/HttpClient'
import Api from '../../service/Api'
import Base64 from 'base-64'
import './Login.scss'
@withRouter
class LoginTpl extends React.Component{
constructor(props){
super(props)
this.state={
loginType:0,
display:0
}
}
handleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
this.loginTo(values);
}
});
};
loginTo(values){
HttpClient.post(Api.login,values).then(data => {
if(data){
setObj('login_info',data);
set('token', data.token);
//set('role', data.role);
// set('overdue_data', Date.now() + 1000*60*60*24);
// set('scanCode',data.scanCode)
this.props.history.push('/');
}
})
}
// componentDidMount() {
// clear();
// }
componentWillMount(){
//引入“微信内嵌二维码”脚本
var script = document.createElement('script');
script.type = 'text/javascript';
script.async = false;
script.src = 'https://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js';
document.head.appendChild(script);
}
componentDidMount(){
clear();
var data=location.href.split('=')[1]
if(data){
var lists=Base64.decode(data);
var email=lists.split('&')[0].split('=')[1]
var password=lists.split('&')[1].split('=')[1]
var obj={
email:email,
password:password
}
this.loginTo(obj);
}
/**
* ... other code
* */
//加载微信二维码
setTimeout(function() {
/**
* 微信内嵌二维码自定义样式有两种方式实现
* 第一种是把自定义样式写在一个css文件里面,部署到一个https链接上
* 第二种是把自定义样式通过base64加密后设置在href上
* */
var customeStyle = "data:text/css;base64,Lnd4X3FyY29kZSBpZnJhbWUgeyB3aWR0aDogMTYwcHg7IGhlaWdodDogMTYwcHg7IG1hcmdpbjogMDsgcGFkZGluZzogMDsgfQ0KLmxvZ2luUGFuZWwgeyBtYXJnaW46MDsgcGFkZGluZzogMDsgfQ0KLmxvZ2luUGFuZWwgLnRpdGxlLCAubG9naW5QYW5lbCAuaW5mbyB7IGRpc3BsYXk6IG5vbmU7IH0NCi5pbXBvd2VyQm94IC5xcmNvZGUgeyBtYXJnaW46IDA7IHdpZHRoOiAxNjBweDsgYm9yZGVyOiBub25lOyB9";
window.WwLogin({
// self_redirect: false,
id: "wx_login_container",
appid: "wwa846aeddd5ae71bf", //微信开放平台网站应用appid
// scope: "snsapi_login",
agentid:"1000021",
redirect_uri: encodeURI('http://test.auth.ahg-op.com/wx-api/user/permission'), //设置扫码成功后回调页面
state: "1",
style: "black",
href: customeStyle, //location.origin + "/css/wx_qrcode.css", //自定义微信二维码样式文件
});
//设置iframe标签可以进行跨域跳转
var qrcodeBox = document.getElementById("wx_login_container");
var iframes = qrcodeBox.getElementsByTagName("iframe");
if (iframes.length){
var ifr = iframes[0];
ifr.setAttribute("sandbox", "allow-scripts allow-top-navigation allow-same-origin");
}
}, 1000)
}
handleType=(e)=>{
e.preventDefault();
this.setState({
loginType:0,
display:0
})
}
handleType1=(e)=>{
e.preventDefault();
this.setState({
loginType:1,
display:1
})
}
render() {
const { getFieldDecorator } = this.props.form;
return(
<section>
<div className="login_panel">
<div className="title">夜店管理后台</div>
<div className='tab'>
<a href="#" className={this.state.display==0?'first active':'first'} onClick={this.handleType}>账号登录</a>
{/* <a href="#" onClick={this.handleType1} className={this.state.display==1?'active':''}>注册</a> */}
</div>
<Form onSubmit={this.handleSubmit} className="login-form" style={{display:this.state.loginType==0?'block':'none'}}>
<Form.Item>
{getFieldDecorator('name', {
rules: [{ required: true, message: '请输入用户名!' }],
})(
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="用户名" />
)}
</Form.Item>
<Form.Item>
{getFieldDecorator('pwd', {
rules: [{ required: true, message: '请输入密码!' }],
})(
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="密码" />
)}
</Form.Item>
<Button type="primary" htmlType="submit" className="login-form-button">
登录
</Button>
</Form>
{/* <div className='codeContainer' style={{display:this.state.loginType==1?'block':'none'}}>
<div id='wx_login_container' className="wx_qrcode"></div>
</div> */}
</div>
</section>
)
}
}
const Login = Form.create({ name: 'login' })(LoginTpl);
export default Login;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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