shadowsocks-manager
Version:
A shadowsocks manager tool for multi user and traffic control.
460 lines (446 loc) • 15.2 kB
JavaScript
const app = angular.module('app');
app
.controller('UserController', ['$scope', '$mdMedia', '$mdSidenav', '$state', '$http', '$interval', '$localStorage', 'userApi', 'configManager',
($scope, $mdMedia, $mdSidenav, $state, $http, $interval, $localStorage, userApi, configManager) => {
const config = configManager.getConfig();
if(config.status === 'admin') {
return $state.go('admin.index');
} else if(!config.status) {
return $state.go('home.index');
} else {
$scope.setMainLoading(false);
}
$scope.setConfig(config);
$scope.innerSideNav = true;
$scope.sideNavWidth = () => {
if($scope.innerSideNav) {
return {
width: '200px',
};
} else {
return {
width: '60px',
};
}
};
$scope.menuButton = function() {
if($scope.menuButtonIcon) {
return $scope.menuButtonClick();
}
if ($mdMedia('gt-sm')) {
$scope.innerSideNav = !$scope.innerSideNav;
} else {
$mdSidenav('left').toggle();
}
};
$scope.menus = [{
name: '首页',
icon: 'home',
click: 'user.index'
}, {
name: '账号',
icon: 'account_circle',
click: 'user.account'
}, {
name: '订单',
icon: 'attach_money',
click: 'user.order',
hide: true,
}, {
name: '设置',
icon: 'settings',
click: 'user.settings'
}, {
name: 'divider',
}, {
name: '退出',
icon: 'exit_to_app',
click: function() {
$http.post('/api/home/logout').then(() => {
$localStorage.home = {};
$localStorage.user = {};
configManager.deleteConfig();
$state.go('home.index');
});
},
}];
$scope.menuClick = index => {
$mdSidenav('left').close();
if(typeof $scope.menus[index].click === 'function') {
$scope.menus[index].click();
} else {
$state.go($scope.menus[index].click);
}
};
$http.get('/api/user/order').then(success => {
if(success.data.length) {
$scope.menus[2].hide = false;
};
});
$scope.menuButtonIcon = '';
$scope.menuButtonClick = () => {};
$scope.setMenuButton = (icon, to) => {
$scope.menuButtonIcon = icon;
$scope.menuButtonClick = () => {
$state.go(to);
};
};
$scope.title = '';
$scope.setTitle = str => { $scope.title = str; };
$scope.fabButton = false;
$scope.fabButtonIcon = '';
$scope.fabButtonClick = () => {};
$scope.setFabButton = (fn, icon = '') => {
$scope.fabButtonIcon = icon;
if(!fn) {
$scope.fabButton = false;
$scope.fabButtonClick = () => {};
return;
}
$scope.fabButton = true;
$scope.fabButtonClick = fn;
};
$scope.interval = null;
$scope.setInterval = interval => {
$scope.interval = interval;
};
$scope.$on('$stateChangeStart', function(event, toUrl, fromUrl) {
$scope.fabButton = false;
$scope.fabButtonIcon = '';
$scope.title = '';
$scope.interval && $interval.cancel($scope.interval);
$scope.menuButtonIcon = '';
});
if(!$localStorage.user.serverInfo && !$localStorage.user.accountInfo) {
userApi.getUserAccount().then(success => {
$localStorage.user.serverInfo = {
data: success.servers,
time: Date.now(),
};
$localStorage.user.accountInfo = {
data: success.account,
time: Date.now(),
};
});
};
}
])
.controller('UserIndexController', ['$scope', '$state', 'userApi', 'markdownDialog', '$sessionStorage', 'autopopDialog',
($scope, $state, userApi, markdownDialog, $sessionStorage, autopopDialog) => {
$scope.setTitle('首页');
userApi.getNotice().then(success => {
$scope.notices = success;
if(!$sessionStorage.showNotice) {
$sessionStorage.showNotice = true;
const autopopNotice = $scope.notices.filter(notice => notice.autopop);
if(autopopNotice.length) {
autopopDialog.show(autopopNotice);
}
}
});
$scope.toMyAccount = () => {
$state.go('user.account');
};
$scope.showNotice = notice => {
markdownDialog.show(notice.title, notice.content);
};
$scope.toTelegram = () => {
$state.go('user.telegram');
};
$scope.toRef = () => {
$state.go('user.ref');
};
}
])
.controller('UserAccountController', ['$scope', '$http', '$mdMedia', 'userApi', 'alertDialog', 'payDialog', 'qrcodeDialog', '$interval', '$localStorage', 'changePasswordDialog', 'payByGiftCardDialog', 'subscribeDialog', '$q', '$state',
($scope, $http, $mdMedia, userApi, alertDialog, payDialog, qrcodeDialog, $interval, $localStorage, changePasswordDialog, payByGiftCardDialog, subscribeDialog, $q, $state) => {
$scope.setTitle('账号');
$scope.setFabButton($scope.config.multiAccount ? () => {
$scope.createOrder();
} : null);
$scope.flexGtSm = 100;
if(!$localStorage.user.serverInfo) {
$localStorage.user.serverInfo = {
time: Date.now(),
data: [],
};
}
$scope.servers = $localStorage.user.serverInfo.data;
if(!$localStorage.user.accountInfo) {
$localStorage.user.accountInfo = {
time: Date.now(),
data: [],
};
}
$scope.account = $localStorage.user.accountInfo.data;
if($scope.account.length >= 2) {
$scope.flexGtSm = 50;
}
const setAccountServerList = (account, server) => {
account.forEach(a => {
a.serverList = $scope.servers.filter(f => {
return !a.server || a.server.indexOf(f.id) >= 0;
});
});
};
setAccountServerList($scope.account, $scope.servers);
const getUserAccountInfo = () => {
userApi.getUserAccount().then(success => {
$scope.servers = success.servers;
if(success.account.map(m => m.id).join('') === $scope.account.map(m => m.id).join('')) {
success.account.forEach((a, index) => {
$scope.account[index].data = a.data;
$scope.account[index].password = a.password;
$scope.account[index].port = a.port;
$scope.account[index].type = a.type;
$scope.account[index].active = a.active;
});
} else {
$scope.account = success.account;
$scope.account.forEach(f => {
const serverId = $scope.servers.filter((server, index) => {
if(!f.server) { return index === 0; }
return f.server.indexOf(server.id) >= 0;
})[0].id;
$scope.getServerPortData(f, serverId);
});
}
setAccountServerList($scope.account, $scope.servers);
$localStorage.user.serverInfo.data = success.servers;
$localStorage.user.serverInfo.time = Date.now();
$localStorage.user.accountInfo.data = success.account;
$localStorage.user.accountInfo.time = Date.now();
if($scope.account.length >= 2) {
$scope.flexGtSm = 50;
}
});
};
getUserAccountInfo();
const base64Encode = str => {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
};
$scope.createQrCode = (method, password, host, port, serverName) => {
return 'ss://' + base64Encode(method + ':' + password + '@' + host + ':' + port);
};
$scope.getServerPortData = (account, serverId) => {
account.currentServerId = serverId;
// const server = $scope.servers.filter(f => f.id === serverId);
// const scale = server[0] ? server[0].scale : 1;
if(!account.isFlowOutOfLimit) { account.isFlowOutOfLimit = {}; }
userApi.getServerPortData(account, serverId).then(success => {
account.lastConnect = success.lastConnect;
account.serverPortFlow = success.flow;
if(account.data) {
account.isFlowOutOfLimit[serverId] = ((account.data.flow + account.data.flowPack) <= account.serverPortFlow);
}
});
account.serverInfo = $scope.servers.filter(f => {
return f.id === serverId;
})[0];
};
$scope.$on('visibilitychange', (event, status) => {
if(status === 'visible') {
if($localStorage.user.accountInfo && Date.now() - $localStorage.user.accountInfo.time >= 10 * 1000) {
// $q.all($scope.account.map(a => {
// return $scope.getServerPortData(a, a.currentServerId);
// }));
getUserAccountInfo();
}
}
});
$scope.setInterval($interval(() => {
if(Date.now() - $localStorage.user.accountInfo.time <= 15 * 1000) { return; }
getUserAccountInfo();
// userApi.updateAccount($scope.account)
// .then(() => {
// setAccountServerList($scope.account, $scope.servers);
// });
$scope.account.forEach(a => {
const currentServerId = a.currentServerId;
userApi.getServerPortData(a, a.currentServerId, a.port).then(success => {
if(currentServerId !== a.currentServerId) { return; }
a.lastConnect = success.lastConnect;
a.serverPortFlow = success.flow;
});
});
}, 60 * 1000));
$scope.getQrCodeSize = () => {
if($mdMedia('xs')) {
return 230;
}
return 180;
};
$scope.showChangePasswordDialog = (accountId, password) => {
changePasswordDialog.show(accountId, password).then(() => {
getUserAccountInfo();
});
};
$scope.subscribe = accountId => {
subscribeDialog.show(accountId);
};
$scope.createOrder = account => {
payDialog.choosePayType(account).then(success => {
getUserAccountInfo();
});
};
$scope.useGiftCard = (accountId) => {
payByGiftCardDialog.show(accountId).then(() => getUserAccountInfo());
};
$scope.fontColor = account => {
if(account.data.expire >= Date.now()) {
return {
color: '#333',
};
}
return {
color: '#a33',
};
};
$scope.isAccountOutOfDate = account => {
if(account.type >=2 && account.type <= 5) {
return Date.now() >= account.data.expire;
} else {
return false;
}
};
$scope.showQrcodeDialog = (method, password, host, port, serverName) => {
const ssAddress = $scope.createQrCode(method, password, host, port, serverName);
qrcodeDialog.show(serverName, ssAddress);
};
$scope.cycleStyle = account => {
let percent = 0;
if(account.type !== 1) {
percent = ((Date.now() - account.data.from) / (account.data.to - account.data.from) * 100).toFixed(0);
}
if(percent > 100) {
percent = 100;
}
return {
background: `linear-gradient(90deg, rgba(0,0,0,0.12) ${ percent }%, rgba(0,0,0,0) 0%)`
};
};
$scope.activeAccount = account => {
$http.put(`/api/user/account/${ account.id }/active`).then(success => {
// account.active = 1;
getUserAccountInfo();
});
};
$scope.isBlur = account => {
if(account.active) { return {}; }
return {
filter: 'blur(4px)'
};
};
}
])
.controller('UserSettingsController', ['$scope', '$state',
($scope, $state) => {
$scope.setTitle('设置');
$scope.toPassword = () => {
$state.go('user.changePassword');
};
$scope.toTelegram = () => {
$state.go('user.telegram');
};
$scope.toRef = () => {
$state.go('user.ref');
};
$scope.toMac = () => {
$state.go('user.macAddress');
};
}
])
.controller('UserChangePasswordController', ['$scope', '$state', 'userApi', 'alertDialog', '$http', '$localStorage',
($scope, $state, userApi, alertDialog, $http, $localStorage) => {
$scope.setTitle('修改密码');
$scope.setMenuButton('arrow_back', 'user.settings');
$scope.data = {
password: '',
newPassword: '',
newPasswordAgain: '',
};
$scope.confirm = () => {
alertDialog.loading();
userApi.changePassword($scope.data.password, $scope.data.newPassword).then(success => {
alertDialog.show('修改密码成功,请重新登录', '确定')
.then(() => {
return $http.post('/api/home/logout');
}).then(() => {
$localStorage.home = {};
$localStorage.user = {};
$state.go('home.index');
});
}).catch(err => {
alertDialog.show('修改密码失败', '确定');
});
};
}
])
.controller('UserTelegramController', ['$scope', '$http', '$interval',
($scope, $http, $interval) => {
$scope.setTitle('绑定Telegram');
$scope.setMenuButton('arrow_back', 'user.settings');
$scope.isLoading = true;
$scope.code = {};
const getCode = () => {
$http.get('/api/user/telegram/code').then(success => {
$scope.code = success.data;
$scope.isLoading = false;
});
};
$scope.setInterval($interval(() => {
getCode();
}, 5 * 1000));
getCode();
$scope.unbind = () => {
$scope.isLoading = true;
$http.post('/api/user/telegram/unbind');
};
}
])
.controller('UserRefController', ['$scope', '$http',
($scope, $http) => {
$scope.setTitle('邀请码');
$scope.setMenuButton('arrow_back', 'user.settings');
$http.get('/api/user/ref/code').then(success => { $scope.code = success.data; });
$http.get('/api/user/ref/user').then(success => { $scope.user = success.data; });
$scope.getRefUrl = code => `${ $scope.config.site }/home/ref/${ code }`;
$scope.clipboardSuccess = event => {
$scope.toast('邀请链接已复制到剪贴板');
};
}
])
.controller('UserOrderController', ['$scope', '$http',
($scope, $http) => {
$scope.setTitle('我的订单');
$http.get('/api/user/order').then(success => {
$scope.orders = success.data;
});
}
])
.controller('UserMacAddressController', ['$scope', '$state', '$http', 'addMacAccountDialog',
($scope, $state, $http, addMacAccountDialog) => {
$scope.setTitle('MAC地址');
$scope.setMenuButton('arrow_back', 'user.settings');
const getMacAccount = () => {
$http.get('/api/user/account/mac').then(success => {
$scope.macAccounts = success.data;
if(!$scope.macAccounts.length) {
$scope.setFabButton(() => {
addMacAccountDialog.show().then(() => {
getMacAccount();
}).catch(err => {
getMacAccount();
});
});
} else {
$scope.setFabButton();
}
});
};
getMacAccount();
}
])
;