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

update agent schedule tbkl

parent cabc6d71
This diff is collapsed.
This diff is collapsed.
......@@ -9,7 +9,15 @@ module.exports = {
},
{
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;
const ButtonGroup = Button.Group;
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{
constructor(props){
super(props);
this.map = ['数据统计','数据统计','配置']
this.map = ['数据统计','数据统计','配置','淘口令','渠道管理']
this.state = {
current: '0',
openKeys: [],
......@@ -47,21 +47,23 @@ class Main extends React.Component{
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys = {[ this.props.menu.currentPage ]}
defaultSelectedKeys = {[ this.props.menu.currentPage +'' ]}
onClick={ this.handleClick.bind(this) }
style={{ lineHeight: '64px' }}
>
<SubMenu title={<span>数据统计</span>}>
<Menu.Item key="0">口令数据</Menu.Item>
<Menu.Item key="1">详细数据</Menu.Item>
<Menu.Item key="1">每日汇总</Menu.Item>
</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>
</Header>
<Content style={{ padding: '0 50px' }}>
<Breadcrumb style={{ margin: '12px 0' }}>
<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>
<div style={{ background: '#fff', padding: 24, minHeight: 280 }}>{
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 = {
host: '0.0.0.0',
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 = {
host: '0.0.0.0',
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({
status:{
type: String,
required: true
},
good:{
type:ObjectId,
required: false,
ref:'tao-link'
}
}, {
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({
timestamps: true
});
schema.index({info: 1});
schema.index({key: 1});
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');
var mongoose = require('mongoose');
var moment = require('moment');
var log = require('../db/mongo/tao-log');
const mongoose = require('mongoose');
const moment = require('moment');
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) => {
console.dir('iniinn')
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{
var u = await agent.findOne({user:user});
if(!u)
......@@ -18,9 +47,9 @@ exports.putAgent = async (req, res, next) => {
}
exports.putTbkl = async (req, res, next) => {
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{
var kl = await kouling.findOne({info:info});
var kl = await Kouling.findOne({info:info});
creater = mongoose.Types.ObjectId(creater);
if(!kl)
tao.saveKouling({info,creater,status},function(e,result){
......@@ -31,8 +60,117 @@ exports.putTbkl = async (req, res, next) => {
}
};
exports.logs = async (req, res, next) => {
try{
var options = {limit: 1000, skip: 0, sort: {'updatedAt':-1}};
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;});
var logs = await Log.find({},null,options).populate('qd','user role');
logs = logs.map(x => { var d = x.toJSON();d['updatedAt'] = dateFormat(d['updatedAt']);return d;});
res.send({ status:'ok',result:logs });
}
\ No newline at end of file
} catch(e){
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 Agent = require('../db/mongo/tao-agent');
var Kouling = require('../db/mongo/tao-kouling');
var Link = require('../db/mongo/tao-link');
var log = require('../db/mongo/tao-log');
var Schedule = require('../db/mongo/tao-schedule');
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) => {
try {
var kouling = new Kouling(data);
......@@ -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) => {
try {
var agent = new Agent(data);
......@@ -38,3 +67,29 @@ exports.findKouling = async (qs,cb) => {
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 @@
"redux-thunk": "^2.2.0",
"request": "^2.81.0",
"request-promise": "^4.2.1",
"url": "^0.11.0",
"urllib": "^2.25.1",
"xlsx": "^0.11.3"
},
"devDependencies": {
......
......@@ -10,5 +10,14 @@ router.get('/logs',controller.logs);
router.post('/agent',controller.putAgent);
router.post('/tbkl',controller.putTbkl);
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;
\ 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