Commit 6383932d authored by 刘松's avatar 刘松

fix

parent 8e13891a
FROM node:latest
FROM hub.c.163.com/library/node:latest
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
RUN \
rm /etc/localtime && \
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN npm install --production --registry=https://registry.npm.taobao.org
# RUN npm install yarn --registry=https://registry.npm.taobao.org
......
......@@ -58,7 +58,6 @@ app.use(async function(req,res,next){
else res.redirect('/');
});
app.get('/', function (req, res){
console.dir('login');
res.sendFile(path.resolve(__dirname, 'app', 'index.html'))
});
app.get('/manage', function (req, res){
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -103,7 +103,7 @@ div.ant-row .ant-col-6:nth-of-type(4) .box h3{
text-align: center;
}
.detail-body{
.detail-body,.detail-b-body{
margin-bottom: 3px;
}
.detail-body-list{
......@@ -112,6 +112,11 @@ div.ant-row .ant-col-6:nth-of-type(4) .box h3{
.detail-body span{
width: 33.3%;
display: inline-block;
overflow: hidden;
}
.detail-body span:nth-of-type(1){
text-overflow: ellipsis;
overflow: hidden;
}
.detail-body-list{
margin-bottom: 3px;
......
......@@ -4,7 +4,7 @@ const api = require('../../js/api');
import json2xlsx from '../../js/json2xlsx';
import { Table, Icon, Alert, Row, Col, Spin, Button,Modal,Form,Input,Switch,message,Select,DatePicker} from 'antd';
import { Table, Icon, Alert, Row, Col, Spin, Button,Modal,Form,Input,Switch,message,Select,DatePicker,Radio} from 'antd';
const { RangePicker } = DatePicker;
const Option = Select.Option;
const FormItem = Form.Item;
......@@ -13,7 +13,7 @@ class Schedule extends React.Component{
constructor(props){
super(props);
this.state= { currentQd:'all',qds:[],schedules :[],status:'pending',pagination:{current:1,pageSize:10,total:1},modalVisible:false,username:'channel'};
this.state= { currentQd:'all',qds:[],schedules :[],status:'pending',pagination:{current:1,pageSize:10,total:1},modalVisible:false,username:'channel', sort:'createdAt'};
}
componentDidMount(){
let pagination = this.state.pagination;
......@@ -29,26 +29,43 @@ class Schedule extends React.Component{
});
}
getschedules(pagination,qd){
getschedules(pagination,qd,sort){
console.dir(pagination);
this.setState({status:'pending'});
var url = 'schedules?'+'skip='+ (pagination.current-1) + '&limit=' + pagination.pageSize;
if(qd && qd !== 'all')
url += ('&qd='+ qd);
if(sort)
url += ('&sort='+ sort);
api('GET', url).then((res) => {
this.setState({schedules:res.result,status:'ready',pagination:{current:res.pagination.skip,pageSize:res.pagination.limit,total:res.pagination.total}})
console.dir(res.result);
});
}
handleSort(e){
this.setState({sort:e.target.value});
this.getschedules({current:1,pageSize:this.state.pagination.pageSize},this.state.currentQd,e.target.value);
}
onChange(pagination) {
this.getschedules(pagination,this.state.currentQd);
this.getschedules(pagination,this.state.currentQd,this.state.sort);
}
createSchedule(){
this.setModalVisible(true);
}
tendFinal(schedule,data) {
var scheduleID = schedule.id;
var final = data.valueOf();
api('GET', 'schedule/final?final='+ final + '&scheduleID='+scheduleID).then((res) => {
message.success('修改成功,刷新查看');
}).catch((data) =>{
message.error(data.responseText);
});
}
setModalVisible(b){
this.setState({modalVisible:b});
}
......@@ -129,21 +146,21 @@ class Schedule extends React.Component{
title: '计划ID',
dataIndex: 'id',
key: 'id',
width: 100,
width: 50,
render: text => <span href="#">{text}</span>,
},
{
title: '分发ID/渠道',
dataIndex: 'qd',
key: 'qd',
width: 100,
width: 70,
render: text => <span href="#">{text}</span>,
},
{
title: '推广页名称',
dataIndex: 'names',
key: 'names',
width: 100,
width: 50,
render: text => <span href="#">{text}</span>,
},
{
......@@ -167,12 +184,13 @@ class Schedule extends React.Component{
width: 75,
render: text => <span href="#">{text}</span>,
},{
title: '投放状态 / 手动替换 / 定时更新 ',
title: '投放状态 / 手动替换 / 定时更新 / 延长投放 ',
dataIndex: 'status',
key: 'status',
width: 130,
width: 230,
render: (data,schedule) => <div><Switch checked={ data.status == 'use' ? true : false } onChange={this.checkUpdate.bind(this,schedule)} style = {{'marginRight': '10px'}}/><Button onClick = {this.tklUpdate.bind(this,schedule)} style = {{'marginRight': '10px'}}>生成淘口令</Button>
<Switch checked={ data.auto == 'use' ? true : false } onChange={this.autoUpdate.bind(this,schedule)} style = {{'marginRight': '17px'}}/></div>,
<Switch checked={ data.auto == 'use' ? true : false } onChange={this.autoUpdate.bind(this,schedule)} style = {{'marginRight': '17px'}}/>
<DatePicker showTime onOk={ this.tendFinal.bind(this,schedule) } format="YYYY-MM-DD HH:mm:ss" /></div>,
}
];
let children = [<Option key='all'>全部</Option>];
......@@ -213,6 +231,10 @@ class Schedule extends React.Component{
>
{children}
</Select>
<Radio.Group value = { this.state.sort } onChange={this.handleSort.bind(this)} style={{ float:'right', "margin":'10px' }}>
<Radio.Button value="createdAt">按时间</Radio.Button>
<Radio.Button value="status">按状态</Radio.Button>
</Radio.Group>
<Spin spinning= { this.state.status == 'pending' }>
<Table columns={columns} dataSource = { data } size="middle" pagination={ this.state.pagination } onChange = { this.onChange.bind(this)} bordered/>
</Spin>
......
......@@ -4,8 +4,9 @@ const api = require('../../js/api');
import json2xlsx from '../../js/json2xlsx';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Modal,Form,Input,Radio} from 'antd';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Modal,Form,Input,Radio,message} from 'antd';
const RadioGroup = Radio.Group;
const Search = Input.Search;
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
......@@ -14,7 +15,7 @@ class Agent extends React.Component{
constructor(props){
super(props);
console.dir(this.props);
this.state= { links :[],status:'pending',pagination:{current:1,pageSize:500,total:1},modalVisible:false,username:'channel',target:'target'};
this.state= { links :[],status:'pending',pagination:{current:1,pageSize:200,total:0},modalVisible:false,username:'channel',target:'target',keyword:''};
}
componentDidMount(){
let pagination = this.state.pagination;
......@@ -28,27 +29,40 @@ class Agent extends React.Component{
});
}
getLinks(pagination){
console.dir(pagination);
getLinks(pagination,keyword){
this.setState({status:'pending'})
api('GET', 'links?'+'skip='+ (pagination.current-1) + '&limit=' + pagination.pageSize).then((res) => {
keyword = keyword || '';
api('GET', 'links?'+'skip='+ (pagination.current-1) + '&limit=' + pagination.pageSize + '&keyword=' + keyword).then((res) => {
this.setState({links:res.result,status:'ready',pagination:{current:res.pagination.skip,pageSize:res.pagination.limit,total:res.pagination.total}})
console.dir(res.result);
});
}
onChange(pagination) {
this.getLinks(pagination);
this.getLinks(pagination,this.state.keyword);
}
createLink(){
this.setModalVisible(true);
}
delete(data) {
api('GET', 'link/del/'+ data.key).then((res) => {
message.success('删除成功');
}).catch((data) => {
message.error(data.responseText);
});
}
setModalVisible(b){
this.setState({modalVisible:b});
}
search(value) {
this.setState({ keyword:value });
this.getLinks({ current:1,pageSize:this.state.pagination.pageSize }, value);
}
handleSubmit(e){
e.preventDefault();
var self = this;
......@@ -58,10 +72,11 @@ class Agent extends React.Component{
if(values[k]) values[k] = values[k].trim();
}
values['select'] = this.state.target;
console.dir(values);
api('POST', 'link',values).then((res) => {
if(res && res.result){
self.setModalVisible(false);
self.getLinks({limit:this.state.pagination.pageSize,skip:0});
self.getLinks({limit:this.state.pagination.pageSize,skip:0},this.state.keyword);
}
});
}
......@@ -141,13 +156,24 @@ class Agent extends React.Component{
key: 'create',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '操作',
dataIndex: 'delete',
key: 'delete',
width: 10,
render: (text,data) =><div>
<Button type="primary" onClick={ this.delete.bind(this,data) } style = {{ marginLeft:'10px' }}>
删除
</Button>
</div>
}
];
let data = [];
let links = this.state.links;
for(let i = 0;i<links.length;i++){
data.push({
key:i,
key:links[i]._id,
name:links[i].name,
quan:links[i].quan,
slogan:links[i].title,
......@@ -164,6 +190,12 @@ class Agent extends React.Component{
<Button type="primary" icon="plus" onClick={ this.createLink.bind(this) } style={{ margin:'10px 0px'}}>
创建推广页
</Button>
<Search
placeholder="搜索推广页"
onSearch={ this.search.bind(this) }
style={{ width: 200, float:'right' }}
/>
<Spin spinning= { this.state.status == 'pending' }>
<Table columns={columns} dataSource = { data } size="middle" pagination={ this.state.pagination } onChange = { this.onChange.bind(this)} bordered/>
</Spin>
......@@ -182,6 +214,7 @@ class Agent extends React.Component{
<Radio.Button value="target">二合一链接</Radio.Button>
<Radio.Button value="quan">优惠券链接</Radio.Button>
<Radio.Button value="good">商品链接</Radio.Button>
<Radio.Button value="notbk">推广链接(非淘宝客)</Radio.Button>
</Radio.Group>
</FormItem>
<FormItem>
......@@ -192,7 +225,7 @@ class Agent extends React.Component{
)}
</FormItem>
{
this.state.target == 'good' ? <div></div> : <FormItem>
this.state.target == 'good' || this.state.target == 'notbk' ? <div></div> : <FormItem>
{getFieldDecorator('quan', {
rules: [{ required: true, message: '优惠券链接不能为空' }],
})(
......@@ -200,6 +233,24 @@ class Agent extends React.Component{
)}
</FormItem>
}
{
this.state.target == 'good' ? <FormItem>
{getFieldDecorator('good_id', {
rules: [{ required: true, message: 'id不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>商品ID</span>} placeholder="例如:2194810505" />
)}
</FormItem> : <div></div>
}
{
this.state.target == 'notbk' ? <FormItem>
{getFieldDecorator('pic', {
rules: [{ required: true, message: '图片链接不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>图片链接</span>} placeholder="例如:..." />
)}
</FormItem> : <div></div>
}
<FormItem>
{getFieldDecorator('good', {
rules: [{ required: true, message: '商品连接不能为空' }],
......@@ -208,7 +259,7 @@ class Agent extends React.Component{
)}
</FormItem>
{
this.state.target == 'good' ? <div></div> : <FormItem>
this.state.target == 'good' || this.state.target == 'notbk' ? <div></div> : <FormItem>
{getFieldDecorator('pid', {
rules: [{ required: true, message: 'pid不能为空' }],
})(
......
......@@ -5,7 +5,7 @@ import ReactEcharts from "echarts-for-react";
import json2xlsx from '../../js/json2xlsx';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Popover,Form,Input,Modal,InputNumber,message,Select,Tabs} from 'antd';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Popover,Form,Input,Modal,InputNumber,message,Select,Tabs,Tag} from 'antd';
const FormItem = Form.Item;
const { RangePicker } = DatePicker;
const TabPane = Tabs.TabPane;
......@@ -19,18 +19,16 @@ class Gather extends React.Component{
this.count = 51;
this.dynamic = { sum:0,click:0 };
this.range = [moment().subtract(14,'days').format('YYYYMMDD'), moment().format('YYYYMMDD')];
this.state= { range:this.range,currentQd:'all',qds:[],qdgathers :[],status:'pending',pagination:{current:1,pageSize:20,total:100},username:'channel',tody:{ click_count:0,tkl_count:0,count:0,schedule_count:0} ,none_tkls:[],list:[],modalVisible:false,xAxis:[],series:[],loading:true,dynamicOption:this.getDynamicOption(),websocket:(("WebSocket" in window) || ('MozWebSocket' in window))};
this.state= { info:{request:0,dc:0,click:0},range:this.range,currentQdforcharts:'all',currentQd:'all',qds:[],qdgathers :[],status:'pending',pagination:{current:1,pageSize:20,total:100},username:'channel',tody:{ click_count:0,tkl_count:0,count:0,schedule_count:0} ,none_tkls:[],list:[],modalVisible:false,modaltodyVisible:false,xAxis:[],series:[],loading:true,dynamicOption:this.getDynamicOption(),websocket:(("WebSocket" in window) || ('MozWebSocket' in window))};
}
fetchNewDate(date,_data0,_data1){
let axisData = (date).toLocaleTimeString().replace(/^\D*/,'');
let option = this.state.dynamicOption;
//option.title.text = 'Hello Echarts-for-react.' + new Date().getSeconds();
let data0 = option.series[0].data;
let data1 = option.series[1].data;
var sum = this.dynamic['sum'] != 0 ? _data0 - this.dynamic['sum'] : 0;
var click = this.dynamic['click'] != 0 ? _data1 - this.dynamic['click'] : 0;
// console.dir(this.dynamic);
this.dynamic['sum'] = _data0;
this.dynamic['click'] = _data1;
data0.shift();
......@@ -46,8 +44,6 @@ class Gather extends React.Component{
if (this.timeTicket) {
clearInterval(this.timeTicket);
}
//this.timeTicket = setInterval(this.fetchNewDate.bind(this), 1000);
//let data = { start:moment().add(-6,'days').format('YYYYMMDD'),end:moment().format('YYYYMMDD')};
if(document.cookie.match('username=[a-zA-Z0-9]+')[0] && document.cookie.match('username=[a-zA-Z0-9]+')[0].split('=')[1]){
this.setState({username:document.cookie.match('username=[a-zA-Z0-9]+')[0].split('=')[1]});
if(document.cookie.match('username=[a-zA-Z0-9]+')[0].split('=')[1] == 'admin')
......@@ -58,6 +54,7 @@ class Gather extends React.Component{
}
api('GET', 'gathers/qd?skip=0&limit=20').then((res) => {
this.setState({qdgathers:res.result,status:'ready',none_tkls:res.none_tkls,list:res.list,pagination:{current:res.pagination.skip,pageSize:res.pagination.limit,total:res.pagination.total}});
this.setState({clickData:res.clickData});
this.handle(res.list,res.tkl_count,res.clickData);
});
if("WebSocket" in window || 'MozWebSocket' in window){
......@@ -117,19 +114,26 @@ class Gather extends React.Component{
}, 3000);*/
}
getCharts(start,end){
getCharts(start,end,qd){
var self = this;
this.setState({loading:true});
api('GET','gatherall?start=' +start+ '&end=' + end).then((res) => {
if(res.status == 'ok' && res.list && res.list.length){
this.setState({loading:true,info:{request:0,dc:0}});
var url = 'gatherall?start=' +start+ '&end=' + end;
if(qd)
url += ('&qd='+qd)
api('GET',url).then((res) => {
if(res.status == 'ok' && res.list){
if(res.list.length == 0)
return message.warn('无数据');
var times = [];
var dc_times = [];
var click_times = [];
var xAxis = [];
res.list.sort(function(a,b){ return parseInt(a._id) - parseInt(b._id) });
for(var k in res.list){
var item = res.list[k];
times.push(item.times);
dc_times.push(item.dc_times);
click_times.push(item.click_times);
xAxis.push(item.date);
}
self.setState({series:[ {
......@@ -140,12 +144,18 @@ class Gather extends React.Component{
data:times
},
{
name:'点击数',
type:'line',
stack: '总量',
areaStyle: {normal: {}},
data:click_times
}, {
name:'导出数',
type:'line',
stack: '总量',
areaStyle: {normal: {}},
data:dc_times
}],xAxis:xAxis,loading:false});
}],xAxis:xAxis,loading:false,info:{request:times.reduce(function(a,b){ return a+b}),click:click_times.reduce(function(a,b){ return a+b}),dc:dc_times.reduce(function(a,b){ return a+b})} });
}
else
message.warn('取数错误');
......@@ -175,7 +185,7 @@ class Gather extends React.Component{
trigger: 'axis'
},
legend: {
data:['请求数','导出数']
data:['请求数','点击数','导出数']
},
toolbox: {
feature: {
......@@ -371,25 +381,36 @@ class Gather extends React.Component{
//let data = { start:dateString[0],end:dateString[1]};
//this.range = ;
this.setState({range:[dateString[0],dateString[1]]});
this.getCharts(dateString[0],dateString[1])
this.getCharts(dateString[0],dateString[1],this.state.currentQdforcharts)
//console.dir(data);
}
exportData(){
//json2xlsx(data,{sheetName:"基础数据", filename : '基础数据'+moment().format('YYYYMMDD')+'.xlsx'});
exportData(data){
var datas = [['日期','渠道','推广页面','请求数']];
for(var i =0; i < data.length; i++){
var item = [data[i].date, data[i].user, data[i].page, data[i].times];
datas.push(item);
}
json2xlsx(datas,{sheetName:"基础数据", filename : '基础数据'+moment().format('YYYYMMDDHH')+'.xlsx'});
}
setModalVisible(b){
this.setState({modalVisible:b});
}
settodyModalVisible(b){
this.setState({modaltodyVisible:b});
}
detaiShow(){
this.setModalVisible(true);
}
todydetaiShow(){
this.settodyModalVisible(true);
}
putexData(data){
console.dir(data);
api('POST','put_data',{dc_times:data['dc_times'],id:data['id']}).then( res => {
message.success('执行成功, 影响'+ (res.result ? res.result.nModified : 0 )+" 条数据");
});
......@@ -405,6 +426,11 @@ class Gather extends React.Component{
//console.log(`selected ${value}`);
}
handleChangeforCharts(value){
this.setState({currentQdforcharts:value});
this.getCharts(this.state.range[0],this.state.range[1],value)
}
detailData(data){
console.dir(data);
var date = data.date;
......@@ -493,7 +519,6 @@ class Gather extends React.Component{
</Button>
</Popover>
});
columns.push({
title: '操作',
dataIndex: 'put',
......@@ -521,6 +546,7 @@ class Gather extends React.Component{
ranges.push(moment(end,'YYYYMMDD'));
let data = [];
let modal_data = [];
let tody_modal_data = [];
let count = 0;
let qdgathers = this.state.qdgathers;
......@@ -539,6 +565,13 @@ class Gather extends React.Component{
rate:item.dc_times / item.times ? ((item.dc_times / item.times).toFixed(6) * 100).toFixed(3) : 0
}
if(this.state.username == 'admin'){
modal_data.push({
key:i + '-total' ,
date:item.date,
user:(item.qd && item.qd.user),
page:'全部推广汇总',
times:item.times,
});
if(item.schedules && item.schedules.length)
item.schedules.sort((a,b) => { return b.times - a.times });
for(var j = 0;j < item.schedules.length; j++){
......@@ -568,9 +601,11 @@ class Gather extends React.Component{
}
var none_tkls = this.state.none_tkls;
var list = this.state.list;
var clickData = this.state.clickData;
var sum = 0;
var list_show = [];
var sum_list_show = [];
var click_sum_list_show = [];
for(var i in none_tkls){
sum += none_tkls[i]['times'];
let qd = none_tkls[i]["qd"];
......@@ -581,9 +616,20 @@ class Gather extends React.Component{
for(var k in list){
if(list[k] && list[k].qd && list[k]['qd']['user'])
map2qd[list[k]['qd']['user']] = (map2qd[list[k]['qd']['user']] ? (map2qd[list[k]['qd']['user']]+list[k]['sum']) : list[k]['sum']);
tody_modal_data.push({
key: list[k]._id,
date:moment().format('YYYYMMDD'),
user:list[k] && list[k].qd && list[k]['qd']['user'] ? list[k]['qd']['user'] : '--' ,
page:list[k] && list[k].links ? list[k].links.map( x => x.name ).join(',') : '--',
times:list[k].sum
})
}
for(var m in clickData){
click_sum_list_show.push(<div className="detail-body" key={ m }><span style={{ width:"50%"}}>{clickData[m]['_id']}</span><span style={{ width:"50%"}}>{ clickData[m]['sum'] }</span></div>);
}
for(var j in map2qd){
sum_list_show.push(<div className="detail-body" key={ j }><span>{j}</span><span>{ map2qd[j] }</span></div>);
sum_list_show.push(<div className="detail-body" key={ j }><span style={{ width:"50%"}}>{j}</span><span style={{ width:"50%"}}>{ map2qd[j] }</span></div>);
}
const content = (
......@@ -595,6 +641,9 @@ class Gather extends React.Component{
<div>
{ sum_list_show }
</div>);
const click_sum_content = (<div>
{ click_sum_list_show }
</div>);
return (
<div>
<div>
......@@ -607,13 +656,16 @@ class Gather extends React.Component{
<span>{ this.state.tody.count }</span>
</Popover>
}
</div>
</Col>
<Col span="6">
<div className = "box">
<h3>点击数</h3>
<h3>点击数</h3>{
this.state.username !== 'admin' ? <span>{ this.state.tody.click_count }</span> :
<Popover placement="bottom" content={click_sum_content} title="详情">
<span>{ this.state.tody.click_count }</span>
</Popover>
}
</div>
</Col>
{
......@@ -642,10 +694,23 @@ class Gather extends React.Component{
{this.state.username == 'admin' ? <Tabs
defaultActiveKey="1"
tabPosition={'left'}
style={{height: '406px', width: '100%',margin:'15px 0px'}}
style={{height: '436px', width: '100%',margin:'15px 0px'}}
>
<TabPane tab="每日走势" key="1" >
<RangePicker onChange={ this.onChangeDate.bind(this) } value={ ranges } format={'YYYYMMDD'} style={{margin:'10px 0px'}}/>
<RangePicker onChange={ this.onChangeDate.bind(this) } value={ ranges } format={'YYYYMMDD'} style={{margin:'10px'}}/>
<Select
style={{ float:'left',width:200,margin:'10px 0px 10px 0px'}}
placeholder="输入渠道名称"
defaultValue="all"
onChange={this.handleChangeforCharts.bind(this)}
>
{children}
</Select>
<div style={{ float:'right',margin:'10px 0px 10px 0px'}}>
<Tag color="#f50" style={{ height:'28px',lineHeight:'28px'}}>{"请求数: "+this.state.info.request}</Tag>
<Tag color="#87d068" style={{ height:'28px',lineHeight:'28px'}}>{"点击数: "+this.state.info.click}</Tag>
<Tag color="#108ee9" style={{ height:'28px',lineHeight:'28px'}}>{"导出数: "+this.state.info.dc}</Tag>
</div>
<ReactEcharts
option={this.getOption()}
style={{height: '350px', width: '100%',margin:'15px 0px'}}
......@@ -662,7 +727,7 @@ class Gather extends React.Component{
</Tabs> : <div></div>}
<div style={{ overflow:"hidden"}}>
<Button type="primary" icon="export" onClick={ this.exportData.bind(this) } style={{ float:'right',margin:'10px 0px'}}>
<Button type="primary" icon="export" onClick={ this.exportData.bind(this, modal_data) } style={{ float:'right',margin:'10px 0px'}}>
导出数据
</Button>
{
......@@ -671,6 +736,12 @@ class Gather extends React.Component{
本页详情
</Button> : <div></div>
}
{
this.state.username == 'admin' ?
<Button type="primary" onClick={ this.todydetaiShow.bind(this) } style={{ float:'right',margin:'10px'}}>
今日详情
</Button> : <div></div>
}
{
this.state.username == 'admin' ? <Modal
......@@ -684,6 +755,19 @@ class Gather extends React.Component{
</Modal> : <div></div>
}
{
this.state.username == 'admin' ? <Modal
title="今日数据详情"
style={{ top: 30 }}
visible={this.state.modaltodyVisible}
footer = { null }
onCancel = { this.settodyModalVisible.bind(this,false) }
>
<Table columns={ modal_columns } dataSource = { tody_modal_data } size="middle" bordered/>
</Modal> : <div></div>
}
{
this.state.username == 'admin' ? <Select
style={{ float:'left',width:200,margin:'10px 0px'}}
......
......@@ -4,8 +4,8 @@ module.exports = {
mongo:'mongodb://user:password@mongo-gp-content-distribution-1.localhost:1302,mongo-gp-content-distribution-2.localhost:1302,mongo-gp-content-distribution-3.localhost:1302/taoarticle?replicaSet=gp-content-aiweibang',
taobao: {
host:"http://gw.api.taobao.com/router/rest",
appKey:"23390725",
appSecret:'0575587ba36b29fa5680ad571c5e51f4'
appKey:"24594025",
appSecret:'def2396c763580d49e4a0aa15c4c18bd'
//appKey:"24594025",//"23580470",//"23390725",
//appSecret:'def2396c763580d49e4a0aa15c4c18bd'//"e5f350cbdbd6db2a8727f0b65dac1f7c",//"0575587ba36b29fa5680ad571c5e51f4"
}
......
......@@ -24,6 +24,10 @@ const schema = mongoose.Schema({
type:Number,
required: true
},
click_times:{
type:Number,
required: false
},
dc_times:{
type:Number,
required: false
......
......@@ -19,6 +19,10 @@ const schema = mongoose.Schema({
type: String,
required: false
},
id:{
type: String,
required: false
},
title:{
type: String,
required: true
......@@ -39,6 +43,10 @@ const schema = mongoose.Schema({
status:{
type:String,
required:false
},
removed:{
type:String,
required:false
}
}, {
timestamps: true
......
......@@ -15,12 +15,12 @@ const Nonetkl = require('../db/mongo/tao-nonetkl-log');
const url = require('url');
const not_full = 'params not full error';
const not_right = 'params not right error';
const not_login = 'please login first';
const not_login = 'please login first'
const not_auth = 'auth error';
const {ObjectId} = mongoose.SchemaTypes;
function dateFormat(target,format) {
return moment(new Date(target.getTime()),'x').format(format || 'YYYYMMDD HH:mm:ss');
return moment(new Date(target.getTime()),'x').add(0,'hours').format(format || 'YYYYMMDD HH:mm:ss');
};
function urlArgs(query) {
......@@ -106,7 +106,7 @@ exports.logs = async (req, res, next) => {
}
exports.getIps = async(req,res,next) => {
let now = moment().add(8,'hours').format('YYYYMMDD');
let now = moment().add(0,'hours').format('YYYYMMDD');
let { qd = 'all', date = now,limit = 100,skip = 0} = req.query;
if(!qd ) return res.status(400).send(not_full);
let sess = req.cookies['sess'];
......@@ -116,7 +116,7 @@ exports.getIps = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
var qs = {date:date};
......@@ -130,7 +130,7 @@ exports.getIps = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else
res.status(400).send(not_login);
......@@ -143,7 +143,7 @@ exports.getQdGatherData = async (req, res, next) => {
let sess = req.cookies['sess'];
var qs = {};
var clickData = {};
var date = moment().add(8,'hours').format('YYYYMMDD');
var date = moment().add(0,'hours').format('YYYYMMDD');
if(sess){
if(qd)
qs['qd'] = qd;
......@@ -191,8 +191,9 @@ exports.getQdGatherData = async (req, res, next) => {
]);
var tasks = [];
list.forEach( async (item,i) => {
var schedule = await Schedule.findById(item._id).populate('qd','user');
var schedule = await Schedule.findById(item._id).populate('qd','user').populate('links','name');
list[i]['qd'] = schedule.toJSON().qd;
list[i]['links'] = schedule.toJSON().links;
});
clickData = await Click.aggregate([
{
......@@ -265,7 +266,7 @@ exports.putGatherData = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
console.dir(dc_times);
......@@ -275,7 +276,7 @@ exports.putGatherData = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else
res.status(400).send(not_login);
......@@ -291,7 +292,7 @@ exports.putIp = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
console.dir(iplimit);
......@@ -301,7 +302,7 @@ exports.putIp = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else
res.status(400).send(not_login);
......@@ -317,7 +318,7 @@ exports.putQdUpdate = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
var result = await Agent.update({_id:id},{$set:{ipstatus:ipstatus}});
......@@ -325,7 +326,7 @@ exports.putQdUpdate = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else
res.status(400).send(not_login);
......@@ -341,11 +342,15 @@ exports.getTbkls = async (req, res, next) => {
}
exports.getLinks = async (req, res, next) => {
let {limit = 100,skip = 0,sort = {'updatedAt': -1}} = req.query;
let {limit = 100,skip = 0,sort = {'updatedAt': -1}, keyword='' } = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip)*limit,sort};
let links = await Link.find({},null,options);
let qs = { removed: { $ne:true } };
if(keyword.length) {
qs.name = new RegExp(`${keyword}`)
}
let links = await Link.find(qs,null,options);
links = links.map(x => { var d = x.toJSON();d['createdAt'] = dateFormat(d['createdAt']);return d;})
let total = await Link.count({},null);
let total = await Link.count(qs,null);
var tasks = [];
links.forEach(item => {
tasks.push(Schedule.find({status:'use',links:{ '$in':[ item._id ]}}).populate('qd','user').limit(1000));
......@@ -366,36 +371,44 @@ exports.getLinks = async (req, res, next) => {
}
exports.createLink = async (req, res, next) => {
var {quan,pid,good,name,select = 'target'} = req.body;
console.dir((select == 'good' && !good) || (select == 'good' && (!pid || !good || !quan || !name)));
if((select == 'good' && !good) || (select != 'good' && (!pid || !good || !quan || !name)))
res.status(400).send(not_full);
var {quan,pid,good,name,select = 'target',good_id,pic,title} = req.body;
//console.dir((select == 'good' && !good) || (select == 'good' && (!pid || !good || !quan || !name)));
if((select == 'good' && !good) || (select == 'notbk' && !pic && !name && !good && !title) || ((select != 'good' && select != 'notbk') && (!pid || !good || !quan || !name)))
return res.status(400).send(not_full);
else{
try {
if(select === 'notbk') {
tao.saveLink({name,good,title,pic,target: good},function(e,result){
if(e) throw e;
res.send({result:'ok',result:result})
});
} else {
let quanQuery = '';
if(select !== 'good' && quan) quanQuery = urlArgs(url.parse(quan).query);
if(select !== 'good' && select !== 'notbk' && quan) quanQuery = urlArgs(url.parse(quan).query);
let goodQuery = urlArgs(url.parse(good).query);
console.dir(goodQuery);
if(!goodQuery['id'])
if(!goodQuery['id'] && !good_id)
res.status(400).send(not_full);
else{
let goodInfo = await tao.getGood(goodQuery['id']);
let goodInfo = await tao.getGood(goodQuery['id'] || good_id);
let title = (req.body.title && req.body.title.length) ? req.body.title : goodInfo['title'];
let pic = goodInfo['pict_url'] || '';
let target = '';
let id = good_id;
console.dir(select);
if(select == 'target')
target = 'https://uland.taobao.com/coupon/edetail?activityId='+ quanQuery['activityId']+'&itemId='+goodQuery['id']+'&pid='+pid+'&dx=1&src=tkm_tkmwz';
target = 'https://uland.taobao.com/coupon/edetail?activityId='+ quanQuery['activityId']+'&itemId='+goodQuery['id']+'&pid='+pid+'&src=tkdg_tkdggj';
if(select == 'good')
target = good;
if(select == 'quan')
target = quan;
console.dir(target);
tao.saveLink({name,quan,pid,good,title,pic,target},function(e,result){
tao.saveLink({name,quan,pid,good,title,pic,target,id},function(e,result){
if(e) throw e;
res.send({result:'ok',result:result})
});
}
}
}catch(e){
console.dir(e);
res.status(400).send(e);
......@@ -403,13 +416,48 @@ exports.createLink = async (req, res, next) => {
}
}
exports.removeLink = async (req,res,next) => {
let sess = req.cookies['sess'];
let link = req.params.link;
if(!/^[0-9a-z]{24}$/.test(link)) return res.status(500).send('格式错误');
if(sess){
var none_tkls = [];
var session_body = await Session.findById(sess);
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(403).send(not_auth);
}
else{
let count = await Schedule.count({links: { $in: [ mongoose.Types.ObjectId(link) ] }});
if(!count) {
let result = await Link.update({ _id: mongoose.Types.ObjectId(link) },{$set:{ removed:true }});
res.send({ result:'ok',result });
} else {
return res.status(500).send('有绑定计划不能删除');
}
}
}
else
res.status(403).send(not_auth);
}else{
res.status(403).send(not_auth);
}
};
exports.getSchedules = async (req, res, next) => {
let {limit = 100,skip = 0,sort = {'createdAt': -1},qd = 'all'} = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip)*limit,sort};
let {limit = 100,skip = 0,sort,qd = 'all'} = req.query;
var qs = {};
if(qd != 'all')
qs = {qd:qd}
console.dir(qs);
var sort_body = {}
if(sort) sort_body[ sort ] = -1;
else sort_body['createdAt'] = -1;
let options = {limit:parseInt(limit),skip:parseInt(skip)*limit,sort:sort_body};
console.dir(options)
let schedules = await Schedule.find(qs,null,options).populate('links','name title target').populate('qd','user');
var tasks = [];
schedules.forEach( (item) => {
......@@ -424,6 +472,18 @@ exports.getSchedules = async (req, res, next) => {
});
}
exports.updateScheduleFinal = async (req, res, next) => {
let { final, scheduleID } = req.query
let now = Date.now();
if(final <= now) return res.status(403).send('日期不能小于当前');
try {
const result = await Schedule.update({_id:mongoose.Types.ObjectId(scheduleID)},{$set:{final: parseInt(final)}});
res.send({status:'ok',result});
} catch(error) {
res.status(500).send('修改失败');
}
}
exports.getQds = async (req, res, next) => {
let {limit = 100,skip = 0,sort = {'createdAt': -1}} = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip)*limit,sort};
......@@ -484,9 +544,11 @@ exports.updateSchedule = async (req, res, next) => {
pic:item.pic,
qd:qd,
link:item._id,
schedule:schedule._id
schedule:schedule._id,
id:item.id,
pid: item.pid
}
for(var i=0;i<5;i++){
for(var i=0;i<10;i++){
tasks.push(createTbkl(data));
}
});
......@@ -520,6 +582,7 @@ exports.createSchedule = async (req, res, next) => {
Promise.all(links).then(function(arr){
arr = arr.map(x => x.toJSON()); //获取所有推广页id
ids = arr.map(x => x._id);
console.dir(arr);
if(agent && ids.length){
var qd = agent.toJSON()['_id'];
var links = ids;
......@@ -532,7 +595,9 @@ exports.createSchedule = async (req, res, next) => {
item['link'] = item._id;
item['schedule'] = schedule;
item['qd'] = qd;
for(let i = 0;i<5;i++){
item['id'] = item.id;
item['pid'] = item.pid;
for(let i = 0;i<10;i++){
tkl_Tasks.push(createTbkl(item));
}
});
......@@ -567,9 +632,11 @@ exports.newTbkl = async (req, res, next) => {
pic:item.pic,
qd:qd,
link:item._id,
schedule:schedule._id
schedule:schedule._id,
id:item.id,
pid: item.pid,
}
for(var i=0;i<5;i++){
for(var i=0;i<10;i++){
tasks.push(createTbkl(data));
}
});
......@@ -599,7 +666,7 @@ exports.adminTbkl = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
var quanQuery = urlArgs(url.parse(quan).query);
......@@ -623,15 +690,15 @@ exports.adminTbkl = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}else{
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
}
exports.getAllGatherData = async(req,res,next) => {
var {start,end} = req.query;
var {start,end,qd='all'} = req.query;
if(!start || !end) return res.status(400).send(not_full);
let sess = req.cookies['sess'];
if(sess){
......@@ -640,12 +707,13 @@ exports.getAllGatherData = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b'){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
console.dir(start);
console.dir(end);
const condition = {'date': {'$gte': moment(start, 'YYYYMMDD').startOf('day').toDate(),'$lt': moment(end, 'YYYYMMDD').endOf('day').toDate()}};
var condition = {'date': {'$gte': moment(start, 'YYYYMMDD').startOf('day').toDate(),'$lt': moment(end, 'YYYYMMDD').endOf('day').toDate()}};
if(qd != 'all')
condition['qd'] = mongoose.Types.ObjectId(qd);
console.dir(condition);
var list = await GatherData.aggregate([
{
$match:condition
......@@ -654,7 +722,8 @@ exports.getAllGatherData = async(req,res,next) => {
$group:{
_id: "$date",
times:{ $sum:"$times" },
dc_times:{ $sum:"$dc_times" }
dc_times:{ $sum:"$dc_times" },
click_times:{ $sum:"$click_times" }
}
}
]);
......@@ -663,9 +732,9 @@ exports.getAllGatherData = async(req,res,next) => {
}
}
else
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}else{
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
}
......@@ -685,7 +754,7 @@ exports.admin2Tbkl = async(req,res,next) => {
/*exports.getDetails = async (req,res,next) => {
var {date,qd} = req.query;
let now = moment().add(8,'hours').format('YYYYMMDD');
let now = moment().add(0,'hours').format('YYYYMMDD');
if(!date || !qd || parseInt(now) - parseInt(date) < 0){
res.status(400).send(not_right);
}
......@@ -695,7 +764,7 @@ exports.admin2Tbkl = async(req,res,next) => {
if(session_body){
var user = session_body.toJSON().user;
if(user != '5a1e81f8c86fa7aa4b51b18b' && user != qd){
res.status(400).send(not_auth);
res.status(403).send(not_auth);
}
else{
......@@ -739,14 +808,17 @@ exports.admin2Tbkl = async(req,res,next) => {
}
}*/
var createTbkl = async (data) => {
let {title,target,pic,qd} = data;
console.dir('data ========================');
console.dir(data);
let {title,target,pic,qd,id,pid} = data;
return new Promise(async (r,d) => {
try {
let targetQuery = urlArgs(url.parse(target).query);
var tbklInfo = null;
console.dir(targetQuery);
if(targetQuery['pid'])
if(targetQuery['pid'] || id || pid)
tbklInfo = await tao.createTbkl(title,target,pic);
else
tbklInfo = await tao.createnormalTbkl(title,target,pic);
......
......@@ -55,13 +55,14 @@ async function tbklTask () {
var tasks_schedule_koulings = [];
if(item.final && item.final < moment().format('x')){
console.dir(schedule + '过期')
tasks_schedules.push(Kouling.update({status:'use',schedule:schedule},{$set:{status:'disable'}},{multi:true}));
tasks_schedule_koulings.push(Schedule.update({_id:schedule},{$set:{status:"disable"}},{multi:true}));
}
// console.dir(schedule);
// 查询计划内 超过20000 请求 淘口令
//console.dir({times:{$gte:10},status:'use',schedule:schedule});
let logs = await Log.find({times:{$gte:max},schedule:schedule,status:{$ne:'disable'}}).populate('link','title target pic').limit(1000);
let logs = await Log.find({times:{$gte:max},schedule:schedule,status:{$ne:'disable'}}).populate('link','title target pic id pid').limit(1000);
var tasks_new = [];
var tasks_old = [];
var tasks_log = [];
......@@ -76,7 +77,9 @@ async function tbklTask () {
link:item.link,
status:'use',
qd:qd,
pic:item.link.pic
id:item.link.id,
pic:item.link.pic,
pid:item.link.pid,
}
tasks_new.push(controller.createTbkl(data));
tasks_old.push(Kouling.update({info:item.key,status:{$ne:'disable'}},{$set:{status:'disable'}},{multi:true}));
......
......@@ -57,7 +57,7 @@ async function tbklTask () {
// console.dir(schedule);
// 查询计划内 超过20000 请求 淘口令
//console.dir({times:{$gte:10},status:'use',schedule:schedule});
let logs = await Log.find({times:{$gte:max},schedule:schedule,status:{$ne:'disable'}}).populate('link','title target pic').limit(1000);
let logs = await Log.find({times:{$gte:max},schedule:schedule,status:{$ne:'disable'}}).populate('link','title target pic id').limit(1000);
var tasks_new = [];
var tasks_old = [];
if(auto == 'use'){
......@@ -69,6 +69,7 @@ async function tbklTask () {
link:_item._id,
status:'use',
qd:qd,
id:_item.id,
pic:_item.pic
}
for(var i = 0;i<10; i++){
......
......@@ -3,6 +3,7 @@ const nodemailer = require('nodemailer');
const Schedule = require('../db/mongo/tao-schedule');
const Data = require('../db/mongo/tao-data');
const Log = require('../db/mongo/tao-log');
const Click = require('../db/mongo/tao-log-click');
const _ = require('lodash');
const moment = require('moment');
const controller = require('./controller');
......@@ -56,6 +57,26 @@ async function tbklTask () {
}
}
]);
var clicks = await Click.aggregate([
{
$match:{
"date": date
}
},
{
$group:{
_id: "$qd",
sum:{ $sum:"$times" }
}
}
]);
var qd2clicks = {};
clicks.forEach( async item => {
//schedule = schedule.toJSON();
//var schedule = _tasks.push(Schedule.findById(item._id));
qd2clicks[item._id] = item.sum;
console.dir(item);
});
var qd2schedule = {};
var sum2schedule = {};
......@@ -90,7 +111,7 @@ async function tbklTask () {
}
//var total = qd2schedule[k].reduce(function(a,b){ return a.times + b.times},{times:0});
//console.dir({qd:qd,schedules:qd2schedule[k],date:logDate,times:total});
var data = new Data({qd:qd,schedules:qd2schedule[k],date:logDate,times:total});
var data = new Data({qd:qd,schedules:qd2schedule[k],date:logDate,times:total,click_times:qd2clicks[qd]});
tasks.push(data.save());
}
Promise.all(tasks).then(function(arr){
......
......@@ -19,6 +19,7 @@ router.post('/qd',controller.createQd);
router.post('/newtkl',controller.newTbkl);
router.post('/link',controller.createLink);
router.get('/link/del/:link',controller.removeLink);
router.post('/put_data',controller.putGatherData);
......@@ -32,6 +33,7 @@ router.post('/tool2_tbkls',controller.admin2Tbkl);
router.get('/schedules',controller.getSchedules);
router.post('/schedule',controller.createSchedule);
router.get('/schedule/final',controller.updateScheduleFinal)
router.post('/schedule_update',controller.updateSchedule);
router.post('/schedule_auto_update',controller.updateAutoSchedule);
router.get('/gathers/qd',controller.getQdGatherData);
......
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