Authored by yyq

seo list

... ... @@ -2,14 +2,69 @@
const Router = require('koa-router');
const _ = require('lodash');
const pager = require('../utils/pager');
let r = new Router();
const TYPE_LIST = [
{name: '商品', type: 'skn', lt: 'SKN'},
{name: '逛', type: 'article', lt: 'ID'},
{name: '店铺', type: 'shop', lt: 'ShopId'},
{name: '链接', type: 'url', lt: 'URL'}
];
const tdk = {
// tdk 列表
index: async(ctx, next) => {
await ctx.render('action/seo_tdk', {title: 'TDK管理'});
let resData = {};
let type = ctx.query.type || 'skn',
page = parseInt(`0${ctx.query.page}`, 10) || 1,
limit = parseInt(`0${ctx.query.limit}`, 10) || 20;
let listKey = `tdk:${type}:links`,
startId = (page - 1) * limit,
typeObj = _.find(TYPE_LIST, {'type': type}) || {};
let hmget = [];
await ctx.redis.multi([
['llen', listKey],
['lrange', listKey, startId, page * limit]
]).execAsync().then(function(res) {
let total = res[0] || 1;
resData.pager = pager(Math.floor((total - 1) / limit) + 1, ctx.query);
_.forEach(res[1], value => {
hmget.push(['hmget', `tdk:${type}:${value}`, 'key', 'title', 'keywords', 'description']);
});
});
await ctx.redis.multi(hmget).execAsync().then(function(res) {
let tdkList = [];
_.forEach(res, value => {
tdkList.push({
id: ++startId,
typeName: typeObj.name,
typeLt: typeObj.lt,
key: value[0],
title: value[1],
keywords: value[2],
description: value[3]
});
});
if (tdkList.length) {
resData.tdkList = tdkList;
}
});
await ctx.render('action/seo_tdk', Object.assign(resData, {
title: 'TDK管理',
typeList: TYPE_LIST,
type: typeObj.type,
typeName: typeObj.name
}));
},
// 添加tdk
... ... @@ -38,12 +93,13 @@ const tdk = {
});
ctx.response.body = result;
}
},
};
r.get('/', tdk.index);
r.get('/tdk', tdk.index);
r.get('/tdk/add', tdk.add);
r.post('/tdk/add', tdk.add);
module.exports = r;
... ...
/**
* 分页处理
* @author: yyq<yanqing.yang@yoho.cn>
* @date: 2017/6/1
*/
'use strict';
const _ = require('lodash');
/**
* 拼接url
* @function joinUrl
* @param params 要拼接的 参数
* @returns {string}
*/
const joinUrl = (params) => {
let dest = '?';
_.forEach(params, function(value, key) {
dest += `${key}=${value}&`;
});
return _.trim(dest, '&');
};
/**
* 设置分页
* @setPager setPager
* @param total 总页数
* @param params 参数
* @returns {object}
*/
module.exports = (total, params)=>{
let resData = {};
let defParams = _.cloneDeep(params);
let cutStatus, // 切割状态 1:去头 2:去尾 3:双切
i;
let pages = [];
let currentPage = parseInt(defParams.page || 1, 10); // 当前页
// 小于两页直接退出
if (total < 2) {
return resData;
}
for (i = currentPage - 2; i <= currentPage + 2; i++) {
if (i < 1) {
cutStatus = 1;
continue;
}
if (i > total) {
cutStatus = cutStatus ? 3 : 2;
continue;
}
pages.push({
url: joinUrl(Object.assign(defParams, {page: i})),
num: i,
cur: currentPage === i
});
}
// 分页中部补全
let len = 5 - pages.length;
let list = [];
if (cutStatus === 1) {
for (i = 1; i <= len; i++) {
let p = currentPage + i + 2;
if (p > total) {
break;
}
list.push({
url: joinUrl(Object.assign(defParams, {page: p})),
num: p
});
}
pages = _.concat(pages, list);
} else if (cutStatus === 2) {
for (i = 1; i <= len; i++) {
let p = currentPage - i - 2;
if (p < 1) {
break;
}
list.push({
url: joinUrl(Object.assign(defParams, {page: p})),
num: p
});
}
pages = _.concat(list, pages);
}
// 分页头尾补全
let fnum = _.get(_.head(pages), 'num', 1),
lnum = _.get(_.last(pages), 'num', 1);
if (fnum > 1) {
if (fnum > 2) {
pages = _.concat({
url: joinUrl(Object.assign(defParams, {page: 1})),
num: 1
}, {num: '...'}, pages);
} else {
pages = _.concat({
url: joinUrl(Object.assign(defParams, {page: 1})),
num: 1
}, pages);
}
}
if (lnum < total) {
if (lnum < total - 1) {
pages = _.concat(pages, {num: '...'}, {
url: joinUrl(Object.assign(defParams, {page: total})),
num: total
});
} else {
pages = _.concat(pages, {
url: joinUrl(Object.assign(defParams, {page: total})),
num: total
});
}
}
resData.pages = pages;
// 上一页
if (currentPage > 1) {
resData.prePage = {url: joinUrl(Object.assign(defParams, {page: currentPage - 1}))};
}
// 下一页
if (currentPage < total) {
resData.nextPage = {url: joinUrl(Object.assign(defParams, {page: currentPage + 1}))};
}
return resData;
};
... ...
<style>
.seo-tdk-page ul {
padding: 0;
}
.seo-tdk-page li {
list-style: none;
}
.seo-tdk-page .query-form {
font-size: 0;
}
.seo-tdk-page .query-form .btn-group {
margin-bottom: 0;
}
.seo-tdk-page .query-form .dropdown-toggle {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.seo-tdk-page .query-form .submit-btn {
height: 39px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.seo-tdk-page .query-key {
width: 220px;
height: 39px;
font-size: 14px;
vertical-align: middle;
outline: none;
}
.seo-tdk-page .text-limit {
max-width: 78px;
display: inline-block;
vertical-align: top;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.seo-tdk-page .pagination {
margin: 0;
}
.seo-tdk-page #pop{
width:500px;
height: 434px;
background: #fff;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin:auto;
}
.seo-tdk-page #pop .control-label {
width: 60px;
text-align: right;
}
.seo-tdk-page #pop li {
padding: 6px 0;
}
.seo-tdk-page #pop select,
.seo-tdk-page #pop input {
height: 30px;
width: 200px;
}
.seo-tdk-page #pop textarea {
height: 70px;
vertical-align: text-top;
border-color: #ccc;
resize: none;
}
.seo-tdk-page #pop .full-w {
width: 390px;
}
.seo-tdk-page #pop .controls {
display: inline-block;
}
</style>
<div class="pageheader">
<div class="media">
<div class="pageicon pull-left">
... ... @@ -6,8 +97,8 @@
<div class="media-body">
<ul class="breadcrumb">
<li><a href=""><i class="glyphicon glyphicon-home"></i></a></li>
<li><a href="">Hotfix</a></li>
<li>{{type}}</li>
<li><a href="/seo/tdk">{{title}}</a></li>
<li>{{typeName}}</li>
</ul>
<h4>{{title}}</h4>
</div>
... ... @@ -16,42 +107,125 @@
</div>
<!-- pageheader -->
<div class="contentpanel">
<div class="panel panel-primary-head">
<div class="panel-heading">
<div class="pull-right">
<a id="new-page" href="/hotfix/new/{{type}}" class="btn btn-success btn-rounded"><i class="glyphicon glyphicon-plus"></i> 新增Hotfix</a>
<div class="contentpanel seo-tdk-page" style="padding-bottom:0;">
<div class="panel panel-default">
<div class="panel-body">
<label style="margin-right:20px;"><input type="checkbox" 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" type="submit">删除</button>
<div class="input-append query-form pull-right">
<div class="btn-group">
<button class="btn dropdown-toggle" data-toggle="dropdown" data-type="{{type}}">
{{typeName}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{{# typeList}}
<li><a href="?type={{type}}">{{name}}</a></li>
{{/ typeList}}
</ul>
</div>
<input class="span2 query-key" type="text">
<button class="btn submit-btn" type="button">搜索</button>
</div>
<h4 class="panel-title">{{type}} hotfix</h4>
<p>&nbsp;</p>
</div>
<!-- panel-heading -->
<table id="table-hotfixs" class="table table-striped table-bordered responsive">
<thead class="">
<tr>
<th>ID</th>
<th>类型</th>
<th>标题</th>
<th>关键词</th>
<th>描述</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{{#each hotfixs}}
<tr>
<td>{{id}}</td>
<td>{{type}}</td>
<td>{{title}}</td>
<td>{{keywords}}</td>
<td>{{description}}</td>
<td>{{operate}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
<!-- panel -->
</div>
\ No newline at end of file
<div class="panel panel-default">
<div class="panel-body">
<table id="table-tdk" class="table table-striped table-bordered responsive">
<thead>
<tr>
<th class="text-center" width="60">ID</th>
<th class="text-center" width="160">类型</th>
<th class="text-center">标题</th>
<th class="text-center">关键词</th>
<th class="text-center">描述</th>
<th class="text-center" width="120">操作</th>
</tr>
</thead>
<tbody>
{{#each tdkList}}
<tr data-type="{{../type}}" data-key="{{key}}" data-title="{{title}}" data-keywords="{{keywords}}" data-description="{{description}}">
<td class="text-center"><input type="checkbox" style="margin-right:5px;">{{id}}</td>
<td class="text-center" title="{{typeName}}({{typeLt}}:{{key}})">{{typeName}}({{typeLt}}:<span class="text-limit">{{key}}</span>)</td>
<td>{{title}}</td>
<td>{{keywords}}</td>
<td>{{description}}</td>
<td class="text-center">
<span>编辑</span>
<span>删除</span>
</td>
</tr>
{{/each}}
</tbody>
</table>
{{# pager}}
<div class="text-right">
<ul class="pagination">
{{# prePage}}
<li><a href="{{url}}">上一页</a></li>
{{/ prePage}}
{{# pages}}
<li class="{{#unless url}}disabled {{/unless}}{{#if cur}}active{{/if}}"><a {{#if url}}href="{{url}}"{{^}}href="javascript:;"{{/if}}>{{num}}</a></li>
{{/ pages}}
{{# nextPage}}
<li><a href="{{url}}">下一页</a></li>
{{/ nextPage}}
</ul>
</div>
{{/ pager}}
</div>
</div>
<div id="pop" class="modal fade in" style="display: none;">
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h4>添加TDK</h4>
</div>
<div class="modal-body">
<ul>
<li>
<label class="control-label" for="select-type">类型:</label>
<div class="controls">
<select id="select-type">
{{# typeList}}
<option value="{{type}}">{{name}}</option>
{{/ typeList}}
</select>
</div>
</li>
<li>
<label class="control-label" for="input-key">SKN:</label>
<div class="controls">
<input type="text" id="input-key">
</div>
</li>
<li>
<label class="control-label" for="input-title">标题:</label>
<div class="controls">
<input type="text" id="input-title" class="full-w">
</div>
</li>
<li>
<label class="control-label" for="input-keywords">关键词:</label>
<div class="controls">
<input type="text" id="input-keywords" class="full-w">
</div>
</li>
<li>
<label class="control-label" for="input-description">描述:</label>
<div class="controls">
<textarea id="input-description" class="full-w"></textarea>
</div>
</li>
</ul>
</div>
<div class="modal-footer">
<a class="btn">关闭</a>
<a class="btn btn-primary">确定</a>
</div>
</div>
</div>
... ...