Authored by 陈峰

Merge branch 'feature/export' into 'master'

Feature/export



See merge request !39
... ... @@ -5,11 +5,14 @@
*/
const _ = require('lodash');
const fs = require('fs');
const Req = require('request-promise');
const moment = require('moment');
const Router = require('koa-router');
const r = new Router();
const Mysql = require('../../../lib/mysql-promise');
const pager = require('../utils/pager');
const xlsx = require('xlsx');
const config = require('../../../config/config');
const singleBrandKeyPre = config.singleBrandKeyPre;
... ... @@ -175,7 +178,59 @@ r.post('/save', async (ctx) => {
result.code = 200;
return ctx.response.body = result;
})
});
r.post('/upload', async(ctx) => { // 导入关键词EXCEL
if (ctx.request.body._files) {
let file = ctx.request.body._files.up_excel;
const workbook = xlsx.readFile(file.path);
const sheetNames = workbook.Props.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
let json_data = xlsx.utils.sheet_to_json(worksheet);
console.log(json_data);
let post_data = [];
_.each(json_data, (obj, index) => {
if (obj.keyword) {
post_data.push({
id: index,
keyword: obj.keyword,
describe: obj.describe || ''
})
}
});
console.log(post_data);
if (post_data.length > 0) {
return Req({ // 传数据给爬虫接口
method: 'POST',
uri: 'http://spiderwebhook.yoho.cn/importApiHot', // 'http://172.16.6.84:9100/importApiHot',
body: {
keywords: post_data
},
json: true,
timeout: 5000
}).then(res => {
// console.log('res:', res);
return ctx.response.body = res;
}).catch(err => {
// console.log(err);
return ctx.response.body = {
code: 301,
message: '接口数据处理错误'
}
});
} else {
return ctx.response.body = {
code: 400,
data: post_data,
message: 'excel无数据或数据格式不正确!'
}
}
}
});
module.exports = r;
... ...
... ... @@ -6,6 +6,7 @@ const md5 = require('md5');
const moment = require('moment');
const pager = require('../utils/pager');
const seoModel = require('../models/seoModel');
const xlsx = require('xlsx');
let r = new Router();
... ... @@ -149,7 +150,6 @@ const tdk = {
ctx.response.body = result;
},
edit: async(ctx, next) => {
let result = {code: 500, message: '非法参数'};
... ... @@ -217,6 +217,76 @@ const tdk = {
}
ctx.response.body = result;
},
upload: async(ctx, next) => {
// console.log(ctx.request.body);
let result = {code: 500, message: '非法参数'};
if (ctx.request.body._files) {
let file = ctx.request.body._files.up_excel;
const workbook = xlsx.readFile(file.path);
// console.log('workbook=',workbook);
const sheetNames = workbook.Props.SheetNames;
const worksheet = workbook.Sheets[sheetNames[0]];
let json_data = xlsx.utils.sheet_to_json(worksheet);
let post_data = [];
let success = 0;
// 处理EXCEL数据,并插入redis
let createRedisData = async function (ctx, data, index) {
if (index < data.length) {
let obj = data[index];
let type = obj.type || '';
let key = obj.key || '';
let title = obj.title || '';
let keywords = obj.keywords || '';
let description = obj.description || '';
// console.log(obj, index);
if (_.find(TYPE_LIST, ['type', type]) && key) {
// console.log('type: ', type, key);
let hashKey = key;
if (type === 'url') {
key = _.replace(key, /http[s]?:\/\//, '');
hashKey = md5(key);
}
//先删除掉相同值的字段
let exist = await ctx.redis.multi([['lrem', `tdk:${type}:links`, 1, hashKey]]).execAsync();
//插入List, 插入数据
let res = await ctx.redis.multi([
['lpushx', `tdk:${type}:links`, hashKey],
['hmset', `tdk:${type}:${hashKey}`, 'key', key, 'title', title, 'keywords', keywords,
'description', description, 'modify_time', Date.parse(new Date()) / 1000]
]).execAsync();
if (res[1]) {
if (!res[0]) {
ctx.redis.lpush(`tdk:${type}:links`, hashKey);
}
}
success += 1;
return createRedisData(ctx, data, index + 1);
} else {
return createRedisData(ctx, data, index + 1);
}
} else {
result = {
code: 200,
data: data,
message: `导入完成${success}条`
};
console.log(result);
ctx.response.body = result;
}
};
return createRedisData(ctx, json_data, 0);
}
}
};
... ... @@ -720,6 +790,7 @@ r.get('/tdk', tdk.index);
r.post('/tdk/add', tdk.add);
r.post('/tdk/edit', tdk.edit);
r.post('/tdk/delete', tdk.delete);
r.post('/tdk/upload', tdk.upload);
// 词根管理
r.get('/rootwords', rootWords.index);
... ...
... ... @@ -128,7 +128,15 @@
<label style="margin-right:20px;"><input type="checkbox" id="check-all" style="margin-right:5px;">全选</label>
<a data-toggle="modal" href="#pop" class="btn btn-default" style="margin-right:10px;">增加</a>
<button class="btn btn-default delete-all" type="submit">删除</button>
<form id="uploadForm" enctype="multipart/form-data" style="display: inline-block;">
<div href="javascript:void(0)" class="btn btn-default btn-upload-excel" style="margin-left:10px">
<input id="up_excel" name="up_excel"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
type="file" style="position: absolute; opacity: 0; width: 100px;">
上传EXCEL
</div>
</form>
<span>(excel必要字段type,key,title, keywords,description)</span>
<div class="input-append pull-right">
<form id="query-form" action="/seo/tdk" class="query-form" method="get">
<div class="btn-group">
... ... @@ -408,5 +416,26 @@
delTdk([data]);
});
$('#up_excel').on('change', function(e) { // EXCEL上传
let $form = $('#uploadForm')[0];
let formData = new FormData($form);
$.ajax({
url: '/seo/tdk/upload', // web/actions/seo.js => tdk.upload
data: formData,
method: 'POST',
cache: false,
processData: false,
contentType: false,
success: function(res) {
if(res.code === 200) {
alert(res.message);
document.location.reload();
} else {
alert('导入失败!');
}
}
});
});
});
</script>
... ...
... ... @@ -14,7 +14,7 @@ const defaults = {
},
redis: {
connect: {
host: '127.0.0.1',
host: '192.168.102.49', //'127.0.0.1',
port: '6379',
retry_strategy: options => {
if (options.error && options.error.code === 'ECONNREFUSED') {
... ...
... ... @@ -73,7 +73,8 @@
"ssh2": "^0.5.4",
"superagent": "^3.6.0",
"tar": "^2.2.1",
"utility": "^1.8.0"
"utility": "^1.8.0",
"xlsx": "^0.13.0"
},
"devDependencies": {
"ada": "^1.1.0",
... ...
... ... @@ -361,13 +361,55 @@ class HotKeywords extends React.Component {
record.callbackFn = this.showOptionModal.bind(this);
return record.id;
}
};
const props = {
name: 'up_excel',
action: '/hot-keywords/upload', // web/actions/hot-keywords.js
accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers: {
authorization: 'authorization-text',
},
showUploadList: false, // 不显示文件列表
onChange(info) {
message.destroy();
message.info(`正在上传中...${info.file.percent || 0}%`, 2);
if(info.file.status === 'done') {
// 因为不知道如何清除调fileList,所以只能以最后一个上传的文件状态为当前状态
let fileLength = info.fileList.length - 1 || 0;
// fileList中的response是服务端返回的数据
if (info.fileList[fileLength] && info.fileList[fileLength].response && info.fileList[fileLength].response.code) {
console.log(info.fileList[fileLength].response);
if (info.fileList[fileLength].response.code === 400) {
let msg = info.fileList[fileLength].response.message;
console.log(msg);
message.error(`上传失败! ${msg}`, 5);
} else if (info.fileList[fileLength].response.code === 200) {
message.success(`${info.file.name} 文件上传成功!`);
document.location.reload();
}
}
console.log(info);
}
if(info.file.status === 'error') {
message.error(`${info.file.name} 文件上传失败!`);
}
console.log(info);
}
};
return (
<div>
<div style={{ paddingBottom: 10 }}>
<Button type="primary" onClick={this.deleteTableRow} disabled={!hasSelected} loading={loading}>删除</Button>
<Button type="primary" style={{ marginLeft: 10 }} onClick={this.addTableRow}>添加</Button>
<Upload {...props} style={{marginLeft: 10}}>
<Button type="primary">
<Icon type="upload" />上传Excel
</Button>
</Upload>
{this.optionModal(showModal)}
</div>
... ...