[TOC]
## Angularjs
[百度百科](https://baike.baidu.com/item/AngularJS/7140293?fr=aladdin "百度吧")
## inspina
bootstrap比較好的后臺管理模板,本身就支持了Angularjs版本,jumpserver就是使用的inspina的jquery版本
## 登錄界面

### 登錄界面代碼
```html
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<div>
<h1 class="logo-name">SO</h1>
</div>
<h3>歡迎使用SmartOps</h3>
{{ errorMessage }}
<form class="m-t" ng-submit="login()">
<div class="form-group">
<input type="email" value="mail@shuaibo.wang" class="form-control" ng-model="loginForm.email" placeholder="登錄郵箱" required="">
</div>
<div class="form-group">
<input type="password" value="123456" class="form-control" placeholder="密碼" ng-model="loginForm.password" required="">
</div>
<button type="submit" class="btn btn-primary block full-width m-b">Login</button>
<a ui-sref="forgot_password"><small>忘記密碼?</small></a>
<p class="text-muted text-center"><small>沒有賬號?</small></p>
<a class="btn btn-sm btn-white btn-block" ui-sref="register">創建賬號</a>
</form>
<p class="m-t"> <small>SmartOps © 2018</small> </p>
</div>
</div>
```
### 關于Angularjs的一些解答
ng-submit: 可以理解為交給那個函數去處理
ng-model: 可以理解為函數需要的參數
這里使用了login函數
```js
function LoginCtrl($scope, $location, AuthService) {
$scope.login = function () {
AuthService.login($scope.loginForm.email,
$scope.loginForm.password
).then(function () {
$location.path('/')
}
).catch(function (reason) {
$scope.errorMessage = reason;
})
}
}
```
#### 認證服務
這里面有利用到了一個AuthService,這個可以理解成為一個認證服務,用來檢測用戶是否登錄沒有登錄就跳轉到登錄界面讓用戶去登錄,由于采用了JSONRPC這種開發模式,后端就不會控制前端去跳轉,所以只能靠前端代碼判斷是否登錄了
```
angular.module('inspinia').factory('AuthService',
['$q', '$timeout', 'jsonrpc',
function ($q, $timeout, jsonrpc) {
// 定義判斷用戶是否在線和token的變量
var user = null;
var token = null;
var next = 'index.main';
// return available functions for use in controllers
return ({
isLoggedIn: isLoggedIn,
login: login,
logout: logout,
register: register,
getUserStatus: getUserStatus
});
function isLoggedIn() {
if (user) {
return true;
} else {
return false;
}
}
function login(email, password) {
var deferred = $q.defer();
jsonrpc.request('user.verify', {
username: email,
password: password
})
.then(function (result) {
if (result.status == 0) {
// 如果用戶登錄成功,記錄其token,并將其設置成在線
token = result.token;
user = true;
deferred.resolve();
}
else {
user = false
deferred.reject();
}
})
.catch(function (error) {
user = false;
deferred.reject();
})
return deferred.promise;
}
function logout() {
return
}
function register(email, password) {
return
}
// 這里寫了一個用戶狀態的接口,這個接口需要token認證,認證通過了就判斷當前用戶可以請求資源
function getUserStatus() {
return jsonrpc.request('user.status', {token: token}).then(function (result) {
if (result.status == 0) {
user = true
}
else {
user = false
}
}).catch(function (reason) {
user=false
})
}
}]);
```
### 禁止沒登錄去訪問頁面
angularjs訪問每個頁面會觸發事件。這個需要在config.js去配置,比如訪問這個頁面需不需要認證,認證不通過然后控制其跳轉
```js
angular
.module('inspinia')
.config(config)
.run(function ($rootScope, $state, AuthService) {
$rootScope.$state = $state
$rootScope.$on('$stateChangeStart',
function (event, toState, toParams, fromState, fromParams) {
// 獲取用戶狀態
AuthService.getUserStatus().then(function () {
// 判斷這個頁面是不是需要登錄,需要登錄就判斷當前有沒有登錄,沒有登錄就跳轉到登錄界面
if (toState.access.restricted && !AuthService.isLoggedIn()) {
// 如果是從別的頁面跳轉過來的記錄一下跳轉之前的url,登錄成功之后還跳轉到之前的頁面
AuthService.next=toState.name
$state.go('login')
}
})
})
})
```
### angularjs自己的路由
angularjs擁有自己的路由功能通常的url是這樣的
```
index.html?#/模塊名
```
這個需要在config里面定義
```js
function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
$urlRouterProvider.otherwise("/index/main");
$ocLazyLoadProvider.config({
// Set to true if you want to see what and when is dynamically loaded
debug: true
});
$stateProvider
.state('index', {
abstract: true,
url: "/index",
templateUrl: "static/views/common/content.html",
})
.state('index.main', {
url: "/main",
templateUrl: "static/views/main.html",
data: {pageTitle: 'Example view'},
access: {restricted: true}
})
.state('index.minor', {
url: "/minor",
templateUrl: "static/views/minor.html",
data: {pageTitle: 'Example view'},
access: {restricted: true} //這個就是判斷需不需要登錄
})
.state('login', {
url: '/login',
access: {restricted: false}, //登錄界面就不要登錄
templateUrl: "static/views/login.html",
controller: 'LoginCtrl',
}
)
}
```
### angularjs自己的控制器
Angularjs還有一個概念那就是controller,我js有100個函數,但是這個頁面就需要1個,或者兩個頁面有相同的函數名但是功能不一樣,這樣做出來的項目很復雜,也容易混淆,協同起來也是有難度,這個控制器可以理解成一個個箱子把東西隔開了。
```js
.state('login', {
url: '/login',
access: {restricted: false}, //登錄界面就不要登錄
templateUrl: "static/views/login.html",
controller: 'LoginCtrl',
}
)
```
這里就是login使用longinCtrl
loginCtl里面包含了登錄界面需要使用的login函數
```
function LoginCtrl($scope, $state, AuthService) {
$scope.login = function () {
AuthService.login($scope.loginForm.email,
$scope.loginForm.password
).then(function () {
$state.go(AuthService.next)
}
).catch(function (reason) {
$scope.errorMessage = reason;
})
}
}
```
### 怎么加載到Angular里面
```
angular
.module('inspinia')
.config(function (jsonrpcConfigProvider) {
jsonrpcConfigProvider.set({
url: '/api',
returnHttpPromise: false
});
})
.controller('MainCtrl', MainCtrl)
.controller('LoginCtrl', ['$scope', '$location', 'AuthService', LoginCtrl])
```
這樣一個登錄的界面就做好了,別的頁面也差不多就這些概念
### Angularjs的插件
上面其實用到了一個插件[angular-jsonrpc-client](https://github.com/joostvunderink/angular-jsonrpc-client "angular-jsonrpc-client")
Angular的插件注冊需要在引用js的最上面
index.html
```html
<!-- Main Angular scripts-->
<script src="static/js/angular/angular.min.js"></script>
<script src="static/js/plugins/oclazyload/dist/ocLazyLoad.min.js"></script>
<script src="static/js/ui-router/angular-ui-router.min.js"></script>
<script src="static/js/plugins/angular-jsonrpc-client.js"></script>
<script src="static/js/bootstrap/ui-bootstrap-tpls-1.1.2.min.js"></script>
<!-- Anglar App Script -->
<script src="static/js/app.js"></script>
```
app.js
```
(function () {
angular.module('inspinia', [
'ui.router', // Routing
'oc.lazyLoad', // ocLazyLoad
'ui.bootstrap', // Ui Bootstrap
'angular-jsonrpc-client'
])
})();
```
## 登錄身份的有效期
之前實現的有點小瑕疵,就是按F5刷新之后自動跳到登錄界面,原因是因為service的token隨著頁面的刷新就被重置了。這里就需要做一些改動了,就是登錄成功之后不僅要把token重新賦值,還寫到cookie里面,然后刷新頁面token從cookie里取出來,而不是null導致重新登錄。需要改動的是services.js
這里需要用到了ngCookies自行app.js里面添加
services.js
```js
angular.module('inspinia').factory('AuthService',
['$q', '$timeout', 'jsonrpc', '$cookies',
function ($q, $timeout, jsonrpc, $cookies) {
....
// 刷新界面從cookie里面讀取回來
var token = $cookies.get('token');
.....
function login(email, password) {
// create a new instance of deferred
var deferred = $q.defer();
// send a post request to the server
jsonrpc.request('user.verify', {
username: email,
password: password
})
.then(function (result) {
if (result.status == 0) {
var expireDate = new Date();
expireDate.setDate(expireDate.getDate() + 1);
token = result.token;
// 登錄成功后設置token到cookie
$cookies.put("token",token,{'expires': expireDate});
user = true;
deferred.resolve();
}
else {
user = false
deferred.reject();
}
})
.catch(function (error) {
user = false;
deferred.reject();
})
// return promise object
return deferred.promise;
}
........
}]);
```
## 注銷功能
注銷功能相對是比較簡單的,只需要將cookie里的token刪除或者設置為空就可以
```js
function logout() {
// create a new instance of deferred
var deferred = $q.defer();
$cookies.remove('token')
// return promise object
return deferred.promise;
}
```