Commit 6c14d914 authored by 刘松's avatar 刘松

update agent schedule tbkl

parent cabc6d71
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.
...@@ -9,7 +9,15 @@ module.exports = { ...@@ -9,7 +9,15 @@ module.exports = {
}, },
{ {
path:'setting', path:'setting',
component:require('../../jsx/setting/agent.jsx') component:require('../../jsx/setting/taopage.jsx')
},
{
path:'tkl',
component:require('../../jsx/setting/tbk.jsx')
},
{
path:'schedule',
component:require('../../jsx/setting/schedule.jsx')
} }
] ]
} }
\ No newline at end of file
...@@ -8,12 +8,12 @@ const MenuItemGroup = Menu.ItemGroup; ...@@ -8,12 +8,12 @@ const MenuItemGroup = Menu.ItemGroup;
const ButtonGroup = Button.Group; const ButtonGroup = Button.Group;
const { Header, Footer, Sider, Content } = Layout; const { Header, Footer, Sider, Content } = Layout;
const mapLocations = ['/manage','/manage/statistics','/manage/setting'] const mapLocations = ['/manage','/manage/statistics','/manage/setting','/manage/tkl','/manage/schedule']
class Main extends React.Component{ class Main extends React.Component{
constructor(props){ constructor(props){
super(props); super(props);
this.map = ['数据统计','数据统计','配置'] this.map = ['数据统计','数据统计','配置','淘口令','渠道管理']
this.state = { this.state = {
current: '0', current: '0',
openKeys: [], openKeys: [],
...@@ -47,21 +47,23 @@ class Main extends React.Component{ ...@@ -47,21 +47,23 @@ class Main extends React.Component{
<Menu <Menu
theme="dark" theme="dark"
mode="horizontal" mode="horizontal"
defaultSelectedKeys = {[ this.props.menu.currentPage ]} defaultSelectedKeys = {[ this.props.menu.currentPage +'' ]}
onClick={ this.handleClick.bind(this) } onClick={ this.handleClick.bind(this) }
style={{ lineHeight: '64px' }} style={{ lineHeight: '64px' }}
> >
<SubMenu title={<span>数据统计</span>}> <SubMenu title={<span>数据统计</span>}>
<Menu.Item key="0">口令数据</Menu.Item> <Menu.Item key="0">口令数据</Menu.Item>
<Menu.Item key="1">详细数据</Menu.Item> <Menu.Item key="1">每日汇总</Menu.Item>
</SubMenu> </SubMenu>
<Menu.Item key="2">配置</Menu.Item> <Menu.Item key="2">推广页管理</Menu.Item>
<Menu.Item key="3">淘口令</Menu.Item>
<Menu.Item key="4">推广计划</Menu.Item>
</Menu> </Menu>
</Header> </Header>
<Content style={{ padding: '0 50px' }}> <Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '12px 0' }}> <Breadcrumb style={{ margin: '12px 0' }}>
<Breadcrumb.Item>{ this.map[ this.props.menu.currentPage ]}</Breadcrumb.Item> <Breadcrumb.Item>{ this.map[ this.props.menu.currentPage ]}</Breadcrumb.Item>
<Breadcrumb.Item>{ this.props.menu.currentPage == '0' ? '基础数据' : (this.props.menu.currentPage == '1' ? '详细数据' : "账户与配置" )}</Breadcrumb.Item> <Breadcrumb.Item>{ this.props.menu.currentPage == '0' ? '数据统计' : (this.props.menu.currentPage == '1' ? '每日汇总' : "配置" )}</Breadcrumb.Item>
</Breadcrumb> </Breadcrumb>
<div style={{ background: '#fff', padding: 24, minHeight: 280 }}>{ <div style={{ background: '#fff', padding: 24, minHeight: 280 }}>{
this.props.children this.props.children
......
const React = require('react');
class Agent extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>agent</div>
)
}
}
module.exports = Agent
\ No newline at end of file
const React = require('react');
const moment = require('moment');
const api = require('../../js/api');
import json2xlsx from '../../js/json2xlsx';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Modal,Form,Input} from 'antd';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
class Schedule extends React.Component{
constructor(props){
super(props);
console.dir(this.props);
this.state= { schedules :[],status:'pending',pagination:{current:1,pageSize:10,total:100},modalVisible:false,username:'channel'};
}
componentDidMount(){
let pagination = this.state.pagination;
if(document.cookie.match('username=[a-zA-Z0-9]+')[0] && document.cookie.match('username=[a-zA-Z0-9]+')[0].split('=')[1] == 'admin'){
this.setState({username:'admin'});
}
//let data = { start:moment().add(-6,'days').format('YYYYMMDD'),end:moment().format('YYYYMMDD')};
api('GET', 'schedules?'+'skip=0&limit=' + pagination.pageSize).then((res) => {
this.setState({schedules:res.result,status:'ready',pagination:{current:res.pagination.skip,pageSize:res.pagination.limit,total:res.pagination.total},info:{quan:'',good:''}})
console.dir(res.result);
});
}
getschedules(pagination){
console.dir(pagination);
this.setState({status:'pending'})
api('GET', 'schedules?'+'skip='+ (pagination.current-1) + '&limit=' + pagination.pageSize).then((res) => {
this.setState({schedules:res.result,status:'ready'})
console.dir(res.result);
});
}
onChange(pagination) {
this.getschedules(pagination);
}
createSchedule(){
this.setModalVisible(true);
}
setModalVisible(b){
this.setState({modalVisible:b});
}
handleSubmit(e){
e.preventDefault();
var self = this;
this.props.form.validateFields((err, values) => {
if (!err) {
console.dir(values)
api('POST', 'schedule',values).then((res) => {
if(res && res.result){
self.setModalVisible(false);
self.getschedules({limit:this.state.limit,skip:0});
}
});
}
});
}
exportData(){
//json2xlsx(data,{sheetName:"基础数据", filename : '基础数据'+moment().format('YYYYMMDD')+'.xlsx'});
}
render(){
const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = this.props.form;
const columns = [
{
title: '推广名称',
dataIndex: 'name',
key: 'name',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '推广链接',
dataIndex: 'target',
key: 'target',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '推广渠道',
dataIndex: 'qd',
key: 'qd',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '推广次数',
dataIndex: 'times',
key: 'times',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '创建日期',
dataIndex: 'create',
key: 'create',
width: 100,
render: text => <span href="#">{text}</span>,
}
];
let data = [];
let schedules = this.state.schedules;
for(let i = 0;i<schedules.length;i++){
data.push({
key:i,
name:schedules[i].taolink && schedules[i].taolink['name'] || '--',
target:schedules[i].taolink && schedules[i].taolink['target'] || '--',
qd:schedules[i].qd && schedules[i].qd['user'] || '--',
times:schedules[i].times,
create:schedules[i].createdAt
});
}
return (
<div>
<Button type="primary" icon="export" onClick={ this.createSchedule.bind(this) } style={{ margin:'10px 0px'}}>
创建
</Button>
<Spin spinning= { this.state.status == 'pending' }>
<Table columns={columns} dataSource = { data } size="middle" pagination={ this.state.pagination } onChange = { this.onChange.bind(this)} bordered/>
</Spin>
<Modal
title="推广计划创建"
style={{ top: 30 }}
visible={this.state.modalVisible}
footer = { null }
onCancel = { this.setModalVisible.bind(this,false) }
>
<Form onSubmit={this.handleSubmit.bind(this)} className="login-form">
<FormItem>
{getFieldDecorator('name', {
rules: [{ required: true, message: '推广名称不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>推广名称</span>} placeholder="例如:推广1" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('user', {
rules: [{ required: true, message: '渠道名称不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>渠道名称</span>} placeholder="例如:qd1" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('times', {
rules: [{ required: true, message: '推广次数不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>推广次数</span>} placeholder="例如:1000000" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
一键生成
</Button>
</FormItem>
</Form>
</Modal>
</div>
)
}
}
Schedule = Form.create()(Schedule);
module.exports = Schedule;
const React = require('react');
const moment = require('moment');
const api = require('../../js/api');
import json2xlsx from '../../js/json2xlsx';
import { Table, Icon, DatePicker, Alert, Row, Col, Spin, Button,Modal,Form,Input} from 'antd';
const { RangePicker } = DatePicker;
const FormItem = Form.Item;
class Agent extends React.Component{
constructor(props){
super(props);
console.dir(this.props);
this.state= { links :[],status:'pending',pagination:{current:1,pageSize:10,total:100},modalVisible:false,username:'channel'};
}
componentDidMount(){
let pagination = this.state.pagination;
if(document.cookie.match('username=[a-zA-Z0-9]+')[0] && document.cookie.match('username=[a-zA-Z0-9]+')[0].split('=')[1] == 'admin'){
this.setState({username:'admin'});
}
//let data = { start:moment().add(-6,'days').format('YYYYMMDD'),end:moment().format('YYYYMMDD')};
api('GET', 'links?'+'skip=0&limit=' + pagination.pageSize).then((res) => {
this.setState({links:res.result,status:'ready',pagination:{current:res.pagination.skip,pageSize:res.pagination.limit,total:res.pagination.total},info:{quan:'',good:''}})
console.dir(res.result);
});
}
getLinks(pagination){
console.dir(pagination);
this.setState({status:'pending'})
api('GET', 'links?'+'skip='+ (pagination.current-1) + '&limit=' + pagination.pageSize).then((res) => {
this.setState({links:res.result,status:'ready'})
console.dir(res.result);
});
}
onChange(pagination) {
this.getLinks(pagination);
}
createLink(){
this.setModalVisible(true);
}
setModalVisible(b){
this.setState({modalVisible:b});
}
handleSubmit(e){
e.preventDefault();
var self = this;
this.props.form.validateFields((err, values) => {
if (!err) {
api('POST', 'link',values).then((res) => {
if(res && res.result){
self.setModalVisible(false);
self.getLinks({limit:this.state.limit,skip:0});
}
});
}
});
}
exportData(){
//json2xlsx(data,{sheetName:"基础数据", filename : '基础数据'+moment().format('YYYYMMDD')+'.xlsx'});
}
render(){
const { getFieldDecorator, getFieldsError, getFieldError, isFieldTouched } = this.props.form;
const columns = [
{
title: '推广名称',
dataIndex: 'name',
key: 'name',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '推广语',
dataIndex: 'slogan',
key: 'slogan',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '优惠券链接',
dataIndex: 'quan',
key: 'quan',
width: 100,
render: text => <span href="#">{text}</span>,
},{
title: '商品连接',
dataIndex: 'good',
key: 'good',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: 'PID',
dataIndex: 'pid',
key: 'pid',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '二合一',
dataIndex: 'target',
key: 'target',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '推广渠道',
dataIndex: 'qd',
key: 'qd',
width: 100,
render: text => <span href="#">{text}</span>,
},
{
title: '大图',
dataIndex: 'img',
key: 'img',
width: 100,
render: text => <img style= {{height:'70px'}} src = { text }/>,
},
{
title: '创建日期',
dataIndex: 'create',
key: 'create',
width: 100,
render: text => <span href="#">{text}</span>,
}
];
let data = [];
let links = this.state.links;
for(let i = 0;i<links.length;i++){
data.push({
key:i,
name:links[i].name,
quan:links[i].quan,
slogan:links[i].title,
good:links[i].good,
pid:links[i].pid,
target:links[i].target,
qd:(links[i].qd && links[i].qd['user']) || '暂无',
img:links[i].pic,
create:links[i].createdAt
});
}
return (
<div>
<Button type="primary" icon="export" onClick={ this.createLink.bind(this) } style={{ margin:'10px 0px'}}>
创建
</Button>
<Spin spinning= { this.state.status == 'pending' }>
<Table columns={columns} dataSource = { data } size="middle" pagination={ this.state.pagination } onChange = { this.onChange.bind(this)} bordered/>
</Spin>
<Modal
title="淘口令推广创建"
style={{ top: 30 }}
visible={this.state.modalVisible}
footer = { null }
onCancel = { this.setModalVisible.bind(this,false) }
>
<Form onSubmit={this.handleSubmit.bind(this)} className="login-form">
<FormItem>
{getFieldDecorator('name', {
rules: [{ required: true, message: '推广名称不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>推广名称</span>} placeholder="例如:推广1" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('quan', {
rules: [{ required: true, message: '优惠券链接不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>优惠券链接</span>} placeholder="例如:https://taoquan.taobao.com/coupon/unify_apply.htm?sellerId=2194810505&activityId=5c3186407cd441d48ecd2460815793e6" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('good', {
rules: [{ required: true, message: '商品连接不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>商品连接</span>} placeholder="例如:https://detail.tmall.com/item.htm?id=40663494639" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('pid', {
rules: [{ required: true, message: 'pid不能为空' }],
})(
<Input prefix={<span style={{ fontSize: 13 }}>PID</span>} placeholder="例如:mm_33320967_40070156_153504280" />
)}
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" className="login-form-button">
一键生成
</Button>
</FormItem>
</Form>
</Modal>
</div>
)
}
}
Agent = Form.create()(Agent);
module.exports = Agent;
const React = require('react');
import {Card, Form, Icon, Input, Button, Checkbox} from 'antd';
const FormItem = Form.Item;
class Tbkl extends React.Component{
constructor(props){
super(props);
}
componentWillMount(){
if(this.props.login && this.props.login.status == 'login')
location.href = '/manage'
const { dispatch } = this.props;
}
render(){
return (
<div>tbkl</div>
)
}
}
module.exports = Tbkl;
\ No newline at end of file
module.exports = { module.exports = {
host: '0.0.0.0', host: '0.0.0.0',
port: process.env.PORT ? process.env.PORT : 9401, port: process.env.PORT ? process.env.PORT : 9401,
mongo:'mongodb://127.0.0.1:27017/taoarticle' mongo:'mongodb://127.0.0.1:27017/taoarticle',
taobao: {
host:"http://gw.api.taobao.com/router/rest",
appKey:"24594025",//"23580470",//"23390725",
appSecret:'def2396c763580d49e4a0aa15c4c18bd'//"e5f350cbdbd6db2a8727f0b65dac1f7c",//"0575587ba36b29fa5680ad571c5e51f4"
}
}; };
\ No newline at end of file
module.exports = { module.exports = {
host: '0.0.0.0', host: '0.0.0.0',
port: process.env.PORT ? process.env.PORT : 9401, port: process.env.PORT ? process.env.PORT : 9401,
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' 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:"24594025",//"23580470",//"23390725",
appSecret:'def2396c763580d49e4a0aa15c4c18bd'//"e5f350cbdbd6db2a8727f0b65dac1f7c",//"0575587ba36b29fa5680ad571c5e51f4"
}
}; };
\ No newline at end of file
...@@ -14,6 +14,11 @@ const schema = mongoose.Schema({ ...@@ -14,6 +14,11 @@ const schema = mongoose.Schema({
status:{ status:{
type: String, type: String,
required: true required: true
},
good:{
type:ObjectId,
required: false,
ref:'tao-link'
} }
}, { }, {
timestamps: true timestamps: true
......
const mongoose = require('mongoose');
const {ObjectId} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
name: {
type: String,
required: true
},
quan: {
type: String,
required: true
},
good:{
type: String,
required: true
},
pid:{
type: String,
required: true
},
title:{
type: String,
required: true
},
pic:{
type: String,
required: false
},
target:{
type:String,
required:true,
},
qd:{
type:ObjectId,
required:false,
ref:'tao-agent'
},
status:{
type:String,
required:false
}
}, {
timestamps: true
});
schema.index({name: 1});
module.exports = mongoose.model('tao-link', schema);
...@@ -23,5 +23,5 @@ const schema = mongoose.Schema({ ...@@ -23,5 +23,5 @@ const schema = mongoose.Schema({
timestamps: true timestamps: true
}); });
schema.index({info: 1}); schema.index({key: 1});
module.exports = mongoose.model('tao-log', schema); module.exports = mongoose.model('tao-log', schema);
const mongoose = require('mongoose');
const {ObjectId} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
taolink:{
type:ObjectId,
required: true,
ref:'tao-link'
},
qd:{
type:ObjectId,
required: true,
ref:'tao-agent'
},
status:{
type: String,
required: true
},
times:{
type:Number,
required: true
}
}, {
timestamps: true
});
schema.index({info: 1});
module.exports = mongoose.model('tao-schedule', schema);
const config = require('../config/index');
const tao = require('./tao'); const tao = require('./tao');
var mongoose = require('mongoose'); const mongoose = require('mongoose');
var moment = require('moment'); const moment = require('moment');
var log = require('../db/mongo/tao-log'); const Log = require('../db/mongo/tao-log');
const Kouling = require('../db/mongo/tao-kouling');
const Link = require('../db/mongo/tao-link');
const Session = require('../db/mongo/session');
const Agent = require('../db/mongo/tao-agent');
const Schedule = require('../db/mongo/tao-schedule');
const url = require('url');
const not_full = 'params not full error';
const not_right = 'params not right error';
function dateFormat(target,format) {
console.dir(target.getTime());
return moment(new Date(target.getTime()),'x').format(format || 'YYYYMMDD HH:mm:ss');
};
function urlArgs(query) {
var args = {};
var pairs = query.split("&");
for (var i = 0; i < pairs.length; i++) {
var pos = pairs[i].indexOf("=");
if (pos == -1) {
continue;
}
var name = pairs[i].substring(0, pos);
console.log(name);
var value = pairs[i].substring(pos + 1);
args[name] = value;
}
return args;
}
exports.putAgent = async (req, res, next) => { exports.putAgent = async (req, res, next) => {
console.dir('iniinn')
let {user,password,role = 'channel'} = req.body; let {user,password,role = 'channel'} = req.body;
if(!user || !password) res.status(400).send('params not full error'); if(!user || !password) res.status(400).send(not_full);
else{ else{
var u = await agent.findOne({user:user}); var u = await agent.findOne({user:user});
if(!u) if(!u)
...@@ -18,9 +47,9 @@ exports.putAgent = async (req, res, next) => { ...@@ -18,9 +47,9 @@ exports.putAgent = async (req, res, next) => {
} }
exports.putTbkl = async (req, res, next) => { exports.putTbkl = async (req, res, next) => {
let {info,creater,status = 'use'} = req.body; let {info,creater,status = 'use'} = req.body;
if(!info || !creater) res.status(400).send('params not full error'); if(!info || !creater) res.status(400).send(not_full);
else{ else{
var kl = await kouling.findOne({info:info}); var kl = await Kouling.findOne({info:info});
creater = mongoose.Types.ObjectId(creater); creater = mongoose.Types.ObjectId(creater);
if(!kl) if(!kl)
tao.saveKouling({info,creater,status},function(e,result){ tao.saveKouling({info,creater,status},function(e,result){
...@@ -31,8 +60,117 @@ exports.putTbkl = async (req, res, next) => { ...@@ -31,8 +60,117 @@ exports.putTbkl = async (req, res, next) => {
} }
}; };
exports.logs = async (req, res, next) => { exports.logs = async (req, res, next) => {
try{
var options = {limit: 1000, skip: 0, sort: {'updatedAt':-1}}; var options = {limit: 1000, skip: 0, sort: {'updatedAt':-1}};
var logs = await log.find({},null,options).populate('qd','user role'); var logs = await Log.find({},null,options).populate('qd','user role');
logs = logs.map(x => { var d = x.toJSON();d['updatedAt'] = moment(new Date(d['updatedAt']).getTime(),'x').format('YYYYMMDD HH:mm:ss');return d;}); logs = logs.map(x => { var d = x.toJSON();d['updatedAt'] = dateFormat(d['updatedAt']);return d;});
res.send({ status:'ok',result:logs }); res.send({ status:'ok',result:logs });
} } catch(e){
\ No newline at end of file console.dir(e);
}
}
exports.getTbkls = async (req, res, next) => {
let {limit = 1000,skip = 0,sort = {'updatedAt': -1}} = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip),sort};
let tbkls = await Kouling.find({},null,options).populate('creater','user role').populate('good','title quan pid good');
let total = await Kouling.count({},null);
res.send({ status:'ok',result:tbkls,pagination:{total:total,skip:skip,limit:limit}});
}
exports.getLinks = async (req, res, next) => {
let {limit = 100,skip = 0,sort = {'updatedAt': -1}} = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip),sort};
let tbkls = await Link.find({},null,options).populate('qd','user role');
let total = await Link.count({},null);
res.send({ status:'ok',result:tbkls,pagination:{total:total,skip:skip,limit:limit}});
}
exports.createLink = async (req, res, next) => {
let {quan,pid,good,name} = req.body;
/* let sess = req.cookies['sess'];
let sessBody = await Session.findById(sess).populate('user','user role');
console.dir(sessBody.toJSON());
return;*/
if(!pid || !good || !quan || !name )
res.status(400).send(not_full);
else{
try {
let quanQuery = urlArgs(url.parse(quan).query);
let goodQuery = urlArgs(url.parse(good).query);
if(!pid || !goodQuery['id'])
res.status(400).send(not_full);
else{
let goodInfo = await tao.getGood(goodQuery['id']);
let title = goodInfo['title'];
let pic = goodInfo['pict_url'] || '';
let target = 'https://uland.taobao.com/coupon/edetail?activityId='+ quanQuery['activityId']+'&itemId='+goodQuery['id']+'&pid='+pid+'&dx=1';
tao.saveLink({name,quan,pid,good,title,pic,target},function(e,result){
if(e) throw e;
res.send({result:'ok',result:result})
});
}
}catch(e){
console.dir(e);
res.status(400).send(e);
}
}
}
exports.getSchedules = async (req, res, next) => {
let {limit = 100,skip = 0,sort = {'updatedAt': -1}} = req.query;
let options = {limit:parseInt(limit),skip:parseInt(skip),sort};
let schedules = await Schedule.find({},null,options).populate('qd','user role').populate('taolink','name title target');
let total = await Schedule.count({},null);
res.send({ status:'ok',result:schedules,pagination:{total:total,skip:skip,limit:limit}});
}
exports.createSchedule = async (req, res, next) => {
let {user,times,status='use',name} = req.body;
try{
if(!user || !times || !name)
res.status(400).send(not_full);
else{
var agent = await Agent.findOne({user:user});
var link = await Link.findOne({name:name});
if(agent && link){
let qd = agent.toJSON()['_id'];
let taolink = link.toJSON()['_id'];
tao.saveSchedule({qd,taolink,status,times},function(e,result){
if(e) throw e;
res.send({status:'ok',result:result});
});
}
else{
res.status(400).send(not_right);
}
}
}catch(e){
res.status(400).send(not_right);
}
}
exports.createTbkl = async (req, res, next) => {
/*let {quan,pid,good,title,qd} = req.body;
let quanQuery = urlArgs(url.parse(quan).query);
let goodQuery = urlArgs(url.parse(good).query);
//console.dir(quanQuery);
try {
if(!pid || !quanQuery['activityId'] || !goodQuery['id'])
res.status(400).send(not_full);
else{
let urlTarget = 'https://uland.taobao.com/coupon/edetail?activityId='+ quanQuery['activityId']+'&itemId='+goodQuery['id']+'&pid='+pid;
let goodInfo = await tao.getGood(goodQuery['id']);
let tbklInfo = await tao.createTbkl(goodInfo['title'],urlTarget);
let model = tbklInfo.model;
//console.dir(title);
console.dir(tbkl);
}
}catch(e){
res.status(400).send(e);
}*/
//res.send({ status:'ok',result:{} });
}
var config = require('../config/index'); var config = require('../config/index');
var Agent = require('../db/mongo/tao-agent'); var Agent = require('../db/mongo/tao-agent');
var Kouling = require('../db/mongo/tao-kouling'); var Kouling = require('../db/mongo/tao-kouling');
var Link = require('../db/mongo/tao-link');
var log = require('../db/mongo/tao-log'); var log = require('../db/mongo/tao-log');
var Schedule = require('../db/mongo/tao-schedule');
var mongoose = require('mongoose'); var mongoose = require('mongoose');
const TopClient = require('./topClient')['TopClient'];
var client = new TopClient({
'appkey': config.taobao.appKey,
'appsecret': config.taobao.appSecret,
'REST_URL': 'http://gw.api.taobao.com/router/rest'
});
exports.saveKouling = async (data,cb) => { exports.saveKouling = async (data,cb) => {
try { try {
var kouling = new Kouling(data); var kouling = new Kouling(data);
...@@ -13,6 +22,26 @@ exports.saveKouling = async (data,cb) => { ...@@ -13,6 +22,26 @@ exports.saveKouling = async (data,cb) => {
} }
} }
exports.saveLink = async (data,cb) => {
try {
console.dir(data);
var link = new Link(data);
cb(null,await link.save());
} catch(e){
cb(e);
}
}
exports.saveSchedule = async (data,cb) => {
try {
var schedule = new Schedule(data);
cb(null,await schedule.save());
} catch(e){
cb(e);
}
}
exports.saveAgent = async (data,cb) => { exports.saveAgent = async (data,cb) => {
try { try {
var agent = new Agent(data); var agent = new Agent(data);
...@@ -38,3 +67,29 @@ exports.findKouling = async (qs,cb) => { ...@@ -38,3 +67,29 @@ exports.findKouling = async (qs,cb) => {
cb(e); cb(e);
} }
} }
exports.getGood = (id) => {
return new Promise((r,d) => {
client.execute('taobao.tbk.item.info.get',
{
'fields':'num_iid,title,pict_url,small_images,reserve_price,zk_final_price,user_type,provcity,item_url',
'platform':'1',
'num_iids':id
},function(error, response) {
if(response.results && response.results.n_tbk_item && response.results.n_tbk_item[0] && !error) r(response.results.n_tbk_item[0]);
else d(error || 'unknown error');
});
});
}
exports.createTbkl = (title,url) => {
return new Promise((r,d) => {
client.execute('taobao.tbk.tpwd.create', {
'text':title,
'url':'https://uland.taobao.com/coupon/edetail?activityId=32fd90b87b9a418bb92d7c8cab52423a&itemId=527016966632&pid=mm_33320967_40070156_150834845&src=czhk_cztkl&ut_sk=1.utdid_null_1511245305902.TaoPassword-Outside.taoketop'
}, function(error, response) {
if (response && response.data && !error) r(response.data);
else d(error);
})
});
}
\ No newline at end of file
'use strict';
const urllib = require('urllib'),
util = require('./topUtil');
/**
* TOP API Client.
*
* @param {Object} options, must set `appkey` and `appsecret`.
* @constructor
*/
function TopClient(options) {
if (!(this instanceof TopClient)) {
return new TopClient(options);
}
options = options || {};
if (!options.appkey || !options.appsecret) {
throw new Error('appkey or appsecret need!');
}
this.REST_URL = options.REST_URL || 'http://gw.api.taobao.com/router/rest';
this.appkey = options.appkey;
this.appsecret = options.appsecret;
}
/**
* Invoke an api by method name.
*
* @param {String} method, method name
* @param {Object} params
* @param {Array} reponseNames, e.g. ['tmall_selected_items_search_response', 'tem_list', 'selected_item']
* @param {Object} defaultResponse
* @param {String} type
* @param {Function(err, response)} callback
*/
TopClient.prototype.invoke = function (method, params, reponseNames, defaultResponse, type, callback) {
params.method = method;
this.request(params, type, function (err, result) {
if (err) {
return callback(err);
}
var response = result;
if (reponseNames && reponseNames.length > 0) {
for (var i = 0; i < reponseNames.length; i++) {
var name = reponseNames[i];
response = response[name];
if (response === undefined) {
break;
}
}
}
if (response === undefined) {
response = defaultResponse;
}
callback(null, response);
});
};
TopClient.prototype._wrapJSON = function (s) {
var matchs = s.match(/\"id\"\:\s?\d{16,}/g);
if (matchs) {
for (var i = 0; i < matchs.length; i++) {
var m = matchs[i];
s = s.replace(m, '"id":"' + m.split(':')[1].trim() + '"');
}
}
return s;
};
var IGNORE_ERROR_CODES = {
'isv.user-not-exist:invalid-nick': 1
};
/**
* Request API.
*
* @param {Object} params
* @param {String} [type='GET']
* @param {Function(err, result)} callback
* @public
*/
TopClient.prototype.request = function (params, type, callback) {
if (typeof type === 'function') {
callback = type;
type = null;
}
var err = util.checkRequired(params, 'method');
if (err) {
return callback(err);
}
var args = {
timestamp: this.timestamp(),
format: 'json',
app_key: this.appkey,
v: '2.0',
sign_method: 'md5'
};
for (var k in params) {
if(typeof params[k] == "object"){
args[k] = JSON.stringify(params[k]);
}else{
args[k] = params[k];
}
}
args.sign = this.sign(args);
type = type || 'GET';
var options = {type: type, data: args, agent: this.agent};
var that = this;
urllib.request(that.REST_URL, options, function (err, buffer) {
var data;
if (buffer) {
buffer = that._wrapJSON(buffer.toString());
try {
data = JSON.parse(buffer);
} catch (e) {
err = e;
e.data = buffer.toString();
data = null;
}
}
var errRes = data && data.error_response;
if (errRes) {
if (!errRes.sub_msg || !IGNORE_ERROR_CODES[errRes.sub_code]) {
// no sub_msg error, let caller handle it.
var msg = errRes.msg + ', code ' + errRes.code;
if (errRes.sub_msg) {
msg += '; ' + errRes.sub_code + ': ' + errRes.sub_msg;
}
err = new Error(msg);
err.name = 'TOPClientError';
err.code = errRes.code;
err.sub_code = errRes.sub_code;
err.data = buffer.toString();
data = null;
}
}
callback(err, data);
});
};
/**
* Get now timestamp with 'yyyy-MM-dd HH:mm:ss' format.
* @return {String}
*/
TopClient.prototype.timestamp = function () {
return util.YYYYMMDDHHmmss();
};
/**
* Sign API request.
* see http://open.taobao.com/doc/detail.htm?id=111#s6
*
* @param {Object} params
* @return {String} sign string
*/
TopClient.prototype.sign = function (params) {
var sorted = Object.keys(params).sort();
var basestring = this.appsecret;
for (var i = 0, l = sorted.length; i < l; i++) {
var k = sorted[i];
basestring += k + params[k];
}
basestring += this.appsecret;
return util.md5(basestring).toUpperCase();
};
/**
* execute top api
*/
TopClient.prototype.execute = function (apiname,params, callback) {
this.invoke(apiname, params, [util.getApiResponseName(apiname)], null, 'POST', callback);
};
exports.TopClient = TopClient;
\ No newline at end of file
'use strict';
const crypto = require('crypto');
/**
* hash
*
* @param {String} method hash method, e.g.: 'md5', 'sha1'
* @param {String|Buffer} s
* @param {String} [format] output string format, could be 'hex' or 'base64'. default is 'hex'.
* @return {String} md5 hash string
* @public
*/
exports.hash = function hash(method, s, format) {
var sum = crypto.createHash(method);
var isBuffer = Buffer.isBuffer(s);
if (!isBuffer && typeof s === 'object') {
s = JSON.stringify(sortObject(s));
}
sum.update(s, isBuffer ? 'binary' : 'utf8');
return sum.digest(format || 'hex');
};
/**
* md5 hash
*
* @param {String|Buffer} s
* @param {String} [format] output string format, could be 'hex' or 'base64'. default is 'hex'.
* @return {String} md5 hash string
* @public
*/
exports.md5 = function md5(s, format) {
return exports.hash('md5', s, format);
};
exports.YYYYMMDDHHmmss = function (d, options) {
d = d || new Date();
if (!(d instanceof Date)) {
d = new Date(d);
}
var dateSep = '-';
var timeSep = ':';
if (options) {
if (options.dateSep) {
dateSep = options.dateSep;
}
if (options.timeSep) {
timeSep = options.timeSep;
}
}
var date = d.getDate();
if (date < 10) {
date = '0' + date;
}
var month = d.getMonth() + 1;
if (month < 10) {
month = '0' + month;
}
var hours = d.getHours();
if (hours < 10) {
hours = '0' + hours;
}
var mintues = d.getMinutes();
if (mintues < 10) {
mintues = '0' + mintues;
}
var seconds = d.getSeconds();
if (seconds < 10) {
seconds = '0' + seconds;
}
return d.getFullYear() + dateSep + month + dateSep + date + ' ' +
hours + timeSep + mintues + timeSep + seconds;
};
exports.checkRequired = function (params, keys) {
if (!Array.isArray(keys)) {
keys = [keys];
}
for (var i = 0, l = keys.length; i < l; i++) {
var k = keys[i];
if (!params.hasOwnProperty(k)) {
var err = new Error('`' + k + '` required');
err.name = "ParameterMissingError";
return err;
}
}
};
exports.getApiResponseName = function(apiName){
var reg = /\./g;
if(apiName.match("^taobao"))
apiName = apiName.substr(7);
return apiName.replace(reg,'_')+"_response";
}
\ No newline at end of file
const mongoose = require('mongoose');
const {ObjectId} = mongoose.SchemaTypes;
const schema = mongoose.Schema({
page:{
type:ObjectId,
required: true,
ref:'tao-link'
},
qd:{
type:ObjectId,
required: true,
ref:'tao-agent'
},
status:{
type: String,
required: true
},
times:{
type:Number,
required: true
}
}, {
timestamps: true
});
schema.index({info: 1});
module.exports = mongoose.model('tao-schedule', schema);
...@@ -38,6 +38,8 @@ ...@@ -38,6 +38,8 @@
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"request": "^2.81.0", "request": "^2.81.0",
"request-promise": "^4.2.1", "request-promise": "^4.2.1",
"url": "^0.11.0",
"urllib": "^2.25.1",
"xlsx": "^0.11.3" "xlsx": "^0.11.3"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -10,5 +10,14 @@ router.get('/logs',controller.logs); ...@@ -10,5 +10,14 @@ router.get('/logs',controller.logs);
router.post('/agent',controller.putAgent); router.post('/agent',controller.putAgent);
router.post('/tbkl',controller.putTbkl); router.post('/tbkl',controller.putTbkl);
router.post('/session',session.login); router.post('/session',session.login);
router.post('/to_tbkl',controller.createTbkl); //系统生成淘口令
router.get('/tbkls',controller.getTbkls);
router.get('/links',controller.getLinks);
router.post('/link',controller.createLink);
router.get('/schedules',controller.getSchedules);
router.post('/schedule',controller.createSchedule);
module.exports = router; module.exports = router;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment