增加一种自定义分类标签,同时可配置默认显示方式

This commit is contained in:
luchenqun 2017-03-19 15:18:55 +08:00
parent f670192e80
commit 3ad3041e35
12 changed files with 378 additions and 104 deletions

View File

@ -291,6 +291,20 @@ db.resetPassword = function(userId, password) {
});
}
db.updateShowStyle = function(userId, show_style) {
console.log('updateUserLastLogin');
var sql = "UPDATE `users` SET `show_style` = '" + show_style + "' WHERE(`id` = '" + userId + "')";
return new Promise(function(resolve, reject) {
client.query(sql, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result.affectedRows);
}
});
});
}
db.register = function(user) {
console.log('register');
var sql = "INSERT INTO `users` (`username`, `password`, `email`) VALUES ('" + user.username + "', '" + user.password + "', '" + user.email + "')";
@ -518,6 +532,24 @@ db.getBookmarksNavigate = function(tags) {
});
};
db.getBookmarksCostomTag = function(user_id) {
console.log('getBookmarksCostomTag');
var sql1 = "(SELECT id, user_id, title, description, url, public, click_count, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') as created_at, DATE_FORMAT(last_click, '%Y-%m-%d %H:%i:%s') as last_click FROM `bookmarks` WHERE `user_id` = '" + user_id + "' ORDER BY `click_count` DESC LIMIT 0, 68)";
var sql2 = "(SELECT id, user_id, title, description, url, public, click_count, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') as created_at, DATE_FORMAT(last_click, '%Y-%m-%d %H:%i:%s') as last_click FROM `bookmarks` WHERE `user_id` = '" + user_id + "' ORDER BY `created_at` DESC LIMIT 0, 68)";
var sql3 = "(SELECT id, user_id, title, description, url, public, click_count, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') as created_at, DATE_FORMAT(last_click, '%Y-%m-%d %H:%i:%s') as last_click FROM `bookmarks` WHERE `user_id` = '" + user_id + "' ORDER BY `last_click` DESC LIMIT 0, 68)";
var sql = sql1 + " UNION " + sql2 + " UNION " + sql3;
return new Promise(function(resolve, reject) {
client.query(sql, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
db.getBookmarksTable = function(params) {
var user_id = params.userId;
params.currentPage = params.currentPage || 1;

View File

@ -10,7 +10,7 @@ app.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
url: '/bookmarks',
templateUrl: '/views/bookmarks.html',
params: {
showStyle: 'navigate',
showStyle: null,
},
controller: 'bookmarksCtr'
})

View File

@ -4,8 +4,8 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
$scope.showSearch = false; // 搜索对话框
$scope.bookmarkNormalHover = false;
$scope.bookmarkEditHover = false;
$scope.showStyle = ($stateParams && $stateParams.showStyle) || 'navigate'; // 显示风格'navigate', 'card', 'table'
$('.js-radio-' + $scope.showStyle).checkbox('set checked');
var menusScope = $('div[ng-controller="menuCtr"]').scope();
$scope.showStyle = ($stateParams && $stateParams.showStyle) || (menusScope && menusScope.showStyle); // 显示风格'navigate', 'costomTag', 'card', 'table'
$scope.edit = false;
const perPageItems = 20;
var dialog = null;
@ -17,6 +17,22 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
$scope.order = [false, false, false];
$scope.order[($stateParams && $stateParams.orderIndex) || 0] = true;
$scope.bookmarkData = {};
$scope.costomTags = [{
index: 0,
clicked: true,
name: '最近使用'
}, {
index: 1,
clicked: false,
name: '最近添加'
}, {
index: 2,
clicked: false,
name: '最多使用'
}]
updateShowStyle();
getBookmarks();
$scope.changeCurrentPage = function(currentPage) {
currentPage = parseInt(currentPage) || 0;
@ -25,17 +41,12 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
$scope.loadBusy = true;
$scope.currentPage = currentPage;
$scope.inputPage = '';
getBookmarks(params);
getBookmarks();
} else {
$scope.currentPage = $scope.totalPages
}
}
var params = {
showStyle: $scope.showStyle,
}
getBookmarks(params);
$scope.jumpToUrl = function(url, id) {
if (!$scope.edit) {
$window.open(url, '_blank');
@ -43,7 +54,7 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
id: id
});
if (params.showStyle != 'navigate') {
if ($scope.showStyle != 'navigate') {
$scope.bookmarks.forEach(function(bookmark) {
if (bookmark.id == id) {
bookmark.click_count += 1;
@ -181,34 +192,65 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
}
}
$scope.updateCostomTagBookmarks = function(index) {
console.log('updateCostomTagBookmarks index = ' + index);
$scope.costomTags.forEach((tag, i) => {
$scope.costomTags[i].clicked = false;
})
$scope.costomTags[index].clicked = true;
if (index == 0) {
$scope.bookmarkData.sort((a, b) => a.last_click >= b.last_click ? -1 : 1);
} else if (index == 1) {
$scope.bookmarkData.sort((a, b) => a.created_at >= b.created_at ? -1 : 1);
} else {
$scope.bookmarkData.sort((a, b) => {
var click1 = parseInt(a.click_count);
var click2 = parseInt(b.click_count);
if (click1 > click2) {
return -1;
} else if (click1 == click2) {
return a.created_at >= b.created_at ? -1 : 1;
} else {
return 1;
}
})
}
$scope.bookmarks = $scope.bookmarkData.slice(0, 68);
}
pubSubService.subscribe('EditCtr.inserBookmarsSuccess', $scope, function(event, data) {
console.log('subscribe EditCtr.inserBookmarsSuccess', params);
var menusScope = $('div[ng-controller="menuCtr"]').scope();
if (menusScope.login && menusScope.selectLoginIndex == 0) {
params.showStyle = $scope.showStyle;
params.forbidTransition = true;
$scope.showStyle = $scope.showStyle;
$scope.forbidTransition = true;
if ($scope.showStyle == 'card') {
$scope.currentPage = 1;
$scope.bookmarks = [];
}
getBookmarks(params);
getBookmarks();
}
});
function getBookmarks(params) {
if (params.showStyle != 'navigate') {
function getBookmarks() {
var params = {}
params.showStyle = $scope.showStyle
params.currentPage = $scope.currentPage;
params.perPageItems = perPageItems;
}
var sendData = {
totalItems: 0,
bookmarksClickCount: [],
bookmarksCreatedAt: [],
bookmarksLatestClick: [],
}
if (!params.showStyle) {
bookmarkService.userInfo({})
.then((user) => {
$scope.showStyle = user && user.show_style;
updateShowStyle();
getBookmarks(); // 拿到默认显示风格了,继续取获取书签
})
.catch((err) => {
toastr.error('获取信息失败。错误信息:' + JSON.stringify(err), "错误");
});
} else {
bookmarkService.getBookmarks(params)
.then((data) => {
if (params.showStyle != 'navigate') {
@ -223,6 +265,13 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
$scope.bookmarks.push(bookmark);
})
$scope.loadBusy = false;
} else if (params.showStyle == 'costomTag') {
$scope.costomTags.forEach((tag) => {
console.log('tag', tag)
if (tag.clicked) {
$scope.updateCostomTagBookmarks(tag.index)
}
})
} else {
$scope.changeOrder($scope.order.indexOf(true));
}
@ -239,33 +288,40 @@ app.controller('bookmarksCtr', ['$scope', '$state', '$stateParams', '$filter', '
login: true,
index: 0
});
if (!(params.forbidTransition && params.forbidTransition == true)) {
if (!($scope.forbidTransition && $scope.forbidTransition == true)) {
transition();
}
})
.catch((err) => console.log('getBookmarks err', err));
}
}
function updateShowStyle() {
$timeout(function() {
if ($scope.showStyle) {
$('.js-bookmark-dropdown' + ' .radio.checkbox').checkbox('set unchecked');
$('.js-radio-' + $scope.showStyle).checkbox('set checked');
$('.js-bookmark-dropdown' + ' .field.item').removeClass('active selected');
$('.js-field-' + $scope.showStyle).addClass('active selected');
}
}, 100)
}
function transition() {
if ($scope.showStyle == 'card' && $scope.currentPage > 1) {
return;
}
var data = ['scale', 'fade', 'fade up', 'fade down', 'fade left', 'fade right', 'horizontal flip',
'vertical flip', 'drop', 'fly left', 'fly right', 'fly up', 'fly down', 'swing left', 'swing right', 'swing up',
'swing down', 'browse', 'browse right', 'slide down', 'slide up', 'slide left', 'slide right'
];
var t = data[parseInt(Math.random() * 1000) % data.length];
var className = 'js-segment-navigate';
if ($scope.showStyle == 'card') {
className = 'js-segment-card'
} else if ($scope.showStyle == 'table') {
className = 'js-table-bookmarks'
} else if ($scope.showStyle == 'costomTag') {
className = 'js-segment-costomTag'
}
$('.' + className).transition('hide');
$('.' + className).transition({
animation: t,
animation: animation(),
duration: 500,
});
}

View File

@ -8,7 +8,7 @@ app.controller('homeCtr', ['$scope', '$stateParams', '$filter', '$state', '$wind
'login': data.logined,
});
$state.go('bookmarks', {
showStyle: 'navigate',
showStyle: (data.user && data.user.show_style) || 'costomTag',
})
toastr.success('自动登陆成功,系统将自动跳转到主页', "提示");
} else {

View File

@ -4,6 +4,7 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', 'pubSubService',
$scope.selectLoginIndex = 0; /**< 默认登陆之后的选择的菜单索引,下表从 0 开始 */
$scope.selectNotLoginIndex = 0; /**< 默认未登陆之后的选择的菜单索引,下表从 0 开始 */
$scope.searchWord = ''; /**< 搜索关键字 */
$scope.showStyle = null;
// 防止在登陆的情况下在浏览器里面直接输入url这时候要更新菜单选项
pubSubService.subscribe('Common.menuActive', $scope, function(event, params) {
console.log("subscribe Common.menuActive", params)
@ -49,15 +50,16 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', 'pubSubService',
$scope.searchBookmarks = function(searchWord) {
$state.go('search', {
searchWord: searchWord,
},{
reload:true,
}, {
reload: true,
})
$scope.login = true;
updateMenuActive($scope.selectLoginIndex = 0);
}
$scope.updateShowStyle = function(showStyle) {
console.log('updateShowStyle', showStyle)
console.log('updateShowStyle', showStyle);
$scope.showStyle = showStyle;
$('.js-radio-' + showStyle).checkbox('set checked');
$state.go('bookmarks', {
showStyle: showStyle,
@ -70,10 +72,7 @@ app.controller('menuCtr', ['$scope', '$stateParams', '$state', 'pubSubService',
});
}
$scope.logout = function() {
var params = {
userName: 'luchenqun'
};
bookmarkService.logout(params)
bookmarkService.logout({})
.then((data) => {
console.log('logout..........', data)
$scope.login = false;

View File

@ -10,18 +10,22 @@ app.controller('settingsCtr', ['$scope', '$stateParams', '$filter', '$state', '$
$scope.form[($stateParams && $stateParams.formIndex) || 0] = true;
$scope.changeForm = function(index) {
console.log("changeForm = ", index);
$scope.form = $scope.form.map(() => false);
$scope.form[index] = true;
if (index == 1) {
if (index <= 1) {
bookmarkService.userInfo({})
.then((data) => {
$scope.user = data;
if (index == 0) {
updateShowStyle($scope.user && $scope.user.show_style);
}
})
.catch((err) => {
toastr.error('获取信息失败。错误信息:' + JSON.stringify(err), "错误");
});
if (index == 1) {
bookmarkService.getTags({})
.then((data) => {
$scope.tagCnt = data.length;
@ -35,6 +39,9 @@ app.controller('settingsCtr', ['$scope', '$stateParams', '$filter', '$state', '$
});
}
}
}
$scope.changeForm($scope.form.indexOf(true)); // 马上调用一次
$scope.resetPassword = function() {
if (!$scope.passwordOrgin || !$scope.passwordNew1 || !$scope.passwordNew2) {
@ -51,12 +58,18 @@ app.controller('settingsCtr', ['$scope', '$stateParams', '$filter', '$state', '$
bookmarkService.resetPassword(parmes)
.then((data) => {
if (data.retCode == 0) {
toastr.success('密码更新成功', "提示");
toastr.success('密码更新成功,请重新登陆!', "提示");
// 注销登陆
bookmarkService.logout({})
.then((data) => {
console.log('logout..........', data)
pubSubService.publish('Common.menuActive', {
login: false,
index: 0
index: 1
});
$state.go('/', {});
$state.go('login', {})
})
.catch((err) => console.log('logout err', err));
} else {
toastr.error('密码更新失败。错误信息:' + data.msg, "错误");
}
@ -69,6 +82,33 @@ app.controller('settingsCtr', ['$scope', '$stateParams', '$filter', '$state', '$
}
}
$scope.updateDefaultShowStyle = function(showStyle) {
console.log(showStyle)
var parmes = {
showStyle: showStyle,
};
bookmarkService.updateShowStyle(parmes)
.then((data) => {
if (data.retCode == 0) {
toastr.success('书签默认显示风格配置更新成功', "提示");
} else {
toastr.error('书签默认显示风格配置。错误信息:' + data.msg, "错误");
}
})
.catch((err) => {
toastr.error('书签默认显示风格配置。错误信息:' + JSON.stringify(err), "错误");
});
}
function updateShowStyle(showStyle) {
setTimeout(function() {
if (showStyle) {
$('.js-default-show-style' + ' .radio.checkbox').checkbox('set unchecked');
$('.js-radio-default-' + showStyle).checkbox('set checked');
}
}, 100)
}
setTimeout(function() {
$("#fileuploader").uploadFile({
url: "/api/uploadBookmarkFile",
@ -95,7 +135,6 @@ app.controller('settingsCtr', ['$scope', '$stateParams', '$filter', '$state', '$
$(".ui.pointing.menu .item").removeClass("selected");
}, 500);
pubSubService.publish('Common.menuActive', {
login: true,
index: 3

View File

@ -300,6 +300,19 @@ app.factory('bookmarkService', ['$http', '$q', function($http, $q) {
});
return def.promise;
},
updateShowStyle: function(params) {
var def = $q.defer();
$http.post('/api/updateShowStyle/', {
params: params
})
.success(function(data) {
def.resolve(data);
})
.error(function(data) {
def.reject('updateShowStyle error');
});
return def.promise;
},
getAdvices: function getAdvices(params) {
var def = $q.defer();
$http.get('/api/advices/', {

View File

@ -47,6 +47,37 @@
<div class="ui divider"></div>
</div>
</div>
<div class="ui segment js-segment-costomTag" ng-if="showStyle === 'costomTag'">
<div class="ui container">
<div class="ui grid">
<div class="two wide column js-costomTag-label" ng-repeat="tag in costomTags">
<div class="ui small label" ng-class="{green:tag.clicked}" ng-click="updateCostomTagBookmarks(tag.index)">
{{ tag.name }}
</div>
</div>
</div>
</div>
<div class="ui divider"></div>
<div class="ui five column grid">
<div
class="column js-costomTag-item"
ng-class="{bookmarkNormalHover:bookmarkNormalHover, bookmark:(!bookmarkNormalHover)}"
ng-mouseover="bookmarkNormalHover=true"
ng-mouseleave="bookmarkNormalHover=false"
ng-repeat="bookmark in bookmarks"
ng-click="jumpToUrl(bookmark.url, bookmark.id)"
title="{{ bookmark.title }}"
id="{{bookmark.id}}">
<img
class="ui ui middle aligned tiny image bookmarkInfo"
ng-src="http://g.soz.im/{{bookmark.url}}/cdn.ico"
style="width:16px;height:16px;"
ng-click="detailBookmark(bookmark);$event.stopPropagation()"
favicon-err="./images/favicon/{{bookmark.id}}.ico">
<span>{{ bookmark.title}}</span>
</div>
</div>
</div>
<table class="ui selectable sortable celled table js-table-bookmarks" ng-if="showStyle === 'table'">
<thead>
<tr>

View File

@ -7,19 +7,25 @@
<div class="menu js-menu-option">
<div class="header">显示方式</div>
<div class="divider"></div>
<div class="field item" ng-click="updateShowStyle('navigate')">
<div class="ui radio checkbox checked js-radio-navigate">
<div class="field item js-field-navigate" ng-click="updateShowStyle('navigate')">
<div class="ui radio checkbox js-radio-navigate">
<input type="radio" name="show-style" checked="">
<label>导航</label>
</div>
</div>
<div class="field item" ng-click="updateShowStyle('table')">
<div class="field item js-field-costomTag" ng-click="updateShowStyle('costomTag')">
<div class="ui radio checkbox js-radio-costomTag">
<input type="radio" name="costomTag-style">
<label>标签</label>
</div>
</div>
<div class="field item js-field-table" ng-click="updateShowStyle('table')">
<div class="ui radio checkbox js-radio-table">
<input type="radio" name="show-style">
<label>表格</label>
</div>
</div>
<div class="field item" ng-click="updateShowStyle('card')">
<div class="field item js-field-card" ng-click="updateShowStyle('card')">
<div class="ui radio checkbox js-radio-card">
<input type="radio" name="show-style">
<label>卡片</label>

View File

@ -2,7 +2,7 @@
<div class="ui grid">
<div class="four wide stretched column">
<div class="ui secondary vertical pointing menu">
<a class="item" ng-class="{active:form[0]}" ng-click="changeForm(0)">重置密码
<a class="item" ng-class="{active:form[0]}" ng-click="changeForm(0)">系统设置
</a>
<a class="item" ng-class="{active:form[1]}" ng-click="changeForm(1)">我的信息
</a>
@ -14,6 +14,9 @@
</div>
<div class="twelve wide stretched column">
<form class="ui form" ng-show="form[0]">
<h4 class="ui horizontal divider header">
重置密码
</h4>
<div class="required field">
<label>原密码</label>
<input type="password" placeholder="" ng-model="passwordOrgin">
@ -27,6 +30,35 @@
<input type="password" placeholder="" ng-model="passwordNew2">
</div>
<button class="ui button" type="submit" ng-click="resetPassword()">重置密码</button>
<h4 class="ui horizontal divider header">
书签默认显示风格配置
</h4>
<div class="inline fields js-default-show-style">
<div class="field" ng-click="updateDefaultShowStyle('navigate')">
<div class="ui radio checkbox js-radio-default-navigate">
<input type="radio" name="default-show-style" checked="checked">
<label>导航</label>
</div>
</div>
<div class="field" ng-click="updateDefaultShowStyle('costomTag')">
<div class="ui radio checkbox js-radio-default-costomTag">
<input type="radio" name="default-show-style">
<label>标签</label>
</div>
</div>
<div class="field" ng-click="updateDefaultShowStyle('table')">
<div class="ui radio checkbox js-radio-default-table">
<input type="radio" name="default-show-style">
<label>表格</label>
</div>
</div>
<div class="field" ng-click="updateDefaultShowStyle('card')">
<div class="ui radio checkbox js-radio-default-card">
<input type="radio" name="default-show-style">
<label>卡片</label>
</div>
</div>
</div>
</form>
<div class="ui four statistics" style="margin-top:30px;" ng-show="form[1]">
<div class="statistic">

View File

@ -159,6 +159,41 @@ api.post('/resetPassword', function(req, res) {
});
});
api.post('/updateShowStyle', function(req, res) {
console.log("updateShowStyle");
if (!req.session.user) {
res.send(401);
return;
}
var params = req.body.params;
db.getUser(req.session.user.username)
.then((user) => {
if (user) {
return db.updateShowStyle(req.session.userId, params.showStyle)
} else {
return Promise.resolve(0)
}
})
.then((affectedRows) => {
res.json({
retCode: (affectedRows == 1 ? 0 : 1),
msg: req.session.username + " 更新书签默认显示风格配置成功!",
})
if (affectedRows) {
req.session.user.show_style = params.showStyle;
}
})
.catch((err) => {
console.log('resetPassword error', err);
res.json({
retCode: 2,
msg: req.session.username + " 更新书签默认显示风格配置失败!: " + JSON.stringify(err),
})
});
});
api.get('/autoLogin', function(req, res) {
var ret = {
logined: false,
@ -251,6 +286,7 @@ api.get('/bookmarks', function(req, res) {
}
var userId = req.session.user.id;
var params = req.query;
params.showStyle = params.showStyle || req.session.user.show_style; // 如果没有指定风格,那么用系统风格
if (params.showStyle === 'navigate') {
db.getTags(userId)
.then((tags) => db.getBookmarksNavigate(tags))
@ -298,6 +334,35 @@ api.get('/bookmarks', function(req, res) {
res.json(data);
})
.catch((err) => console.log('bookmarks navigate err', err));
} else if (params.showStyle === 'costomTag') {
var bookmarks = []
db.getBookmarksCostomTag(userId)
.then((_bookmarks) => {
bookmarks = _bookmarks;
var bookmarkIds = bookmarks.map((bookmark) => bookmark.id)
return db.getTagsBookmarks(bookmarkIds);
})
.then((tbs) => {
tagsBookmarks = tbs;
return db.getTags(userId);
})
.then((tags) => {
bookmarks.forEach(function(bookmark, index) {
var bookmarkTags = [];
tagsBookmarks.forEach(function(tb) {
if (tb.bookmark_id == bookmark.id) {
tags.forEach(function(tag) {
if (tb.tag_id == tag.id) {
bookmarkTags.push(tag)
}
})
}
});
bookmarks[index].tags = bookmarkTags;
})
res.json(bookmarks);
})
.catch((err) => console.log('bookmarks costomTag err', err))
} else {
var tagsBookmarks = [];
var sendData = {
@ -1076,19 +1141,19 @@ api.getHotBookmarksByTimer = function() {
if (response && response.statusCode == 200) {
var inserCnt = 0;
var data = JSON.parse(body).data;
var dateDate = new Date(data.date)
var dataDate = new Date(data.date)
console.log("getHotBookmarks success, date = ", dateDate.format("yyyyMMdd"), ', bookmarks = ', data.list.length);
// 因为有第二天很早的时候获取的是前一天的
if (data.list.length == 0 || (date.format("yyyyMMdd") != dateDate.format("yyyyMMdd"))) {
console.log("getHotBookmarks success, date = ", dataDate.format("yyyy-MM-dd hh:mm:ss"), ', bookmarks length = ', data.list.length);
if (data.list.length == 0) {
busy = false;
return;
}
var dateSql = parseInt(dataDate.format('yyyyMMdd'));
data.list.forEach((b) => {
var bookmark = {};
bookmark.id = b.articleId;
bookmark.date = parseInt(date.format('yyyyMMdd'));
bookmark.date = dateSql; // 因为有第二天很早的时候获取的是前一天的,所以用数据返回日期
bookmark.title = b.title;
bookmark.url = b.url;
bookmark.fav_count = b.favCount || 0;

View File

@ -7,6 +7,7 @@ CREATE TABLE `users` (
`email` varchar(255) DEFAULT NULL, -- 邮箱
`created_at` datetime DEFAULT now(), -- 创建时间
`last_login` datetime DEFAULT NULL, -- 最后一次登录时间
`show_style` char(16) NOT NULL DEFAULT 'navigate', -- 显示风格
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
UNIQUE KEY `email` (`email`)