Unverified Commit 33d73edb authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #129 from jumpserver/dev

Dev
parents 9388e27a 99ab8e18
...@@ -19,14 +19,15 @@ ...@@ -19,14 +19,15 @@
"assets": [ "assets": [
"src/assets", "src/assets",
"src/static", "src/static",
"src/theme/default",
"src/favicon.ico" "src/favicon.ico"
], ],
"styles": [ "styles": [
"node_modules/animate.css/animate.min.css", "node_modules/animate.css/animate.min.css",
"node_modules/xterm/dist/xterm.css", "node_modules/xterm/dist/xterm.css",
"node_modules/ngx-toastr/toastr.css",
"src/sass/style.scss", "src/sass/style.scss",
"src/styles.css", "src/styles.css",
"src/theme.scss",
"src/assets/ztree/awesomeStyle/awesome.css" "src/assets/ztree/awesomeStyle/awesome.css"
], ],
"scripts": [ "scripts": [
......
...@@ -8906,6 +8906,14 @@ ...@@ -8906,6 +8906,14 @@
"vlq": "^1.0.0" "vlq": "^1.0.0"
} }
}, },
"ngx-toastr": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-10.2.0.tgz",
"integrity": "sha512-6ASr5bcvQmtNKb4D2VEsQjCXyROq6GwberBWO0bVt+xcBYPUea4aRTgX8in9apX9buaTafzG+h3HlnIraspoPg==",
"requires": {
"tslib": "^1.9.0"
}
},
"nice-try": { "nice-try": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
"utf-8-validate": "^5.0.2" "utf-8-validate": "^5.0.2"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "~7.2.0", "@angular/animations": "^7.2.0",
"@angular/cdk": "^7.3.7", "@angular/cdk": "^7.3.7",
"@angular/common": "~7.2.0", "@angular/common": "~7.2.0",
"@angular/compiler": "~7.2.0", "@angular/compiler": "~7.2.0",
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
"neffos.js": "^0.1.19", "neffos.js": "^0.1.19",
"ngx-cookie-service": "^1.0.10", "ngx-cookie-service": "^1.0.10",
"ngx-logger": "4.0.4", "ngx-logger": "4.0.4",
"ngx-toastr": "^10.2.0",
"popper.js": "^1.14.7", "popper.js": "^1.14.7",
"requirejs": "^2.3.5", "requirejs": "^2.3.5",
"rxjs": "~6.3.3", "rxjs": "~6.3.3",
......
...@@ -4,6 +4,8 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms'; // <-- NgModel ...@@ -4,6 +4,8 @@ import {FormsModule, ReactiveFormsModule} from '@angular/forms'; // <-- NgModel
import {NGXLogger} from 'ngx-logger'; import {NGXLogger} from 'ngx-logger';
import {HttpClientModule} from '@angular/common/http'; import {HttpClientModule} from '@angular/common/http';
import {CookieService} from 'ngx-cookie-service'; import {CookieService} from 'ngx-cookie-service';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {ToastrModule} from 'ngx-toastr';
import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material'; import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material';
// service // service
...@@ -26,8 +28,10 @@ import {AssetTreeDialogComponent, ManualPasswordDialogComponent} from './element ...@@ -26,8 +28,10 @@ import {AssetTreeDialogComponent, ManualPasswordDialogComponent} from './element
BrowserModule, BrowserModule,
FormsModule, FormsModule,
HttpClientModule, HttpClientModule,
BrowserAnimationsModule,
ReactiveFormsModule, ReactiveFormsModule,
AppRouterModule, AppRouterModule,
ToastrModule.forRoot(),
...PluginModules ...PluginModules
], ],
declarations: [ declarations: [
......
...@@ -3,6 +3,7 @@ import {MatDialog} from '@angular/material'; ...@@ -3,6 +3,7 @@ import {MatDialog} from '@angular/material';
import {BehaviorSubject, Subject} from 'rxjs'; import {BehaviorSubject, Subject} from 'rxjs';
import {takeUntil} from 'rxjs/operators'; import {takeUntil} from 'rxjs/operators';
import {ActivatedRoute} from '@angular/router'; import {ActivatedRoute} from '@angular/router';
import {ToastrService} from 'ngx-toastr';
import {groupBy} from '@app/utils/common'; import {groupBy} from '@app/utils/common';
import {AppService, HttpService, LogService, NavService, SettingService, TreeFilterService} from '@app/services'; import {AppService, HttpService, LogService, NavService, SettingService, TreeFilterService} from '@app/services';
...@@ -48,6 +49,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -48,6 +49,7 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
isLoadTreeAsync: boolean; isLoadTreeAsync: boolean;
filterAssetCancel$: Subject<boolean> = new Subject(); filterAssetCancel$: Subject<boolean> = new Subject();
loading = true; loading = true;
favoriteAssets = [];
constructor(private _appSvc: AppService, constructor(private _appSvc: AppService,
private _treeFilterSvc: TreeFilterService, private _treeFilterSvc: TreeFilterService,
...@@ -55,7 +57,8 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -55,7 +57,8 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
public _logger: LogService, public _logger: LogService,
private activatedRoute: ActivatedRoute, private activatedRoute: ActivatedRoute,
private _http: HttpService, private _http: HttpService,
private settingSvc: SettingService private settingSvc: SettingService,
private toastr: ToastrService
) {} ) {}
ngOnInit() { ngOnInit() {
...@@ -105,6 +108,10 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -105,6 +108,10 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
}; };
} }
this._http.getFavoriteAssets().subscribe(resp => {
this.favoriteAssets = resp.map(i => i.asset);
});
this.loading = true; this.loading = true;
this._http.getMyGrantedNodes(this.isLoadTreeAsync, refresh).subscribe(resp => { this._http.getMyGrantedNodes(this.isLoadTreeAsync, refresh).subscribe(resp => {
this.loading = false; this.loading = false;
...@@ -206,6 +213,15 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -206,6 +213,15 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
return findSSHProtocol; return findSSHProtocol;
} }
isAssetFavorite() {
const host = this.rightClickSelectNode.meta.asset;
if (!host) {
return false;
}
const assetId = host.id;
return this.favoriteAssets.indexOf(assetId) !== -1;
}
get RMenuList() { get RMenuList() {
const menuList = [{ const menuList = [{
'id': 'new-connection', 'id': 'new-connection',
...@@ -219,6 +235,18 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -219,6 +235,18 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
'fa': 'fa-file', 'fa': 'fa-file',
'hide': !this.nodeSupportSSH(), 'hide': !this.nodeSupportSSH(),
'click': this.connectFileManager.bind(this) 'click': this.connectFileManager.bind(this)
}, {
'id': 'favorite',
'name': 'Favorite',
'fa': 'fa-star-o',
'hide': this.isAssetFavorite(),
'click': this.favoriteAsset.bind(this)
}, {
'id': 'disfavor',
'name': 'Disfavor',
'fa': 'fa-star',
'hide': !this.isAssetFavorite(),
'click': this.favoriteAsset.bind(this)
}]; }];
if (!this.rightClickSelectNode) { if (!this.rightClickSelectNode) {
return []; return [];
...@@ -265,6 +293,26 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy { ...@@ -265,6 +293,26 @@ export class ElementAssetTreeComponent implements OnInit, OnDestroy {
window.open(url, '_blank'); window.open(url, '_blank');
} }
favoriteAsset() {
const host = this.rightClickSelectNode.meta.asset;
if (!host) {
return false;
}
const assetId = host.id;
if (this.isAssetFavorite()) {
this._http.favoriteAsset(assetId, false).subscribe(() => {
const i = this.favoriteAssets.indexOf(assetId);
this.favoriteAssets.splice(i, 1);
this.toastr.success(translate('Disfavor') + ' ' + translate('success'), '', {timeOut: 2000});
});
} else {
this._http.favoriteAsset(assetId, true).subscribe(() => {
this.favoriteAssets.push(assetId);
this.toastr.success(translate('Favorite') + ' ' + translate('success'), '', {timeOut: 2000});
});
}
}
filterAssets(keyword) { filterAssets(keyword) {
if (this.isLoadTreeAsync) { if (this.isLoadTreeAsync) {
this._logger.debug('Filter assets server'); this._logger.debug('Filter assets server');
......
...@@ -107,8 +107,8 @@ export class ElementConnectComponent implements OnInit, OnDestroy { ...@@ -107,8 +107,8 @@ export class ElementConnectComponent implements OnInit, OnDestroy {
if (systemUsers.length > 1) { if (systemUsers.length > 1) {
return new Promise<SystemUser>(resolve => { return new Promise<SystemUser>(resolve => {
const dialogRef = this._dialog.open(AssetTreeDialogComponent, { const dialogRef = this._dialog.open(AssetTreeDialogComponent, {
height: '200px', height: '250px',
width: '300px', width: '500px',
data: {users: systemUserMaxPriority} data: {users: systemUserMaxPriority}
}); });
......
<h1 mat-dialog-title>{{"Found"|trans}} {{data.users.length}} {{"Users "|trans}}</h1> <h1 mat-dialog-title>{{"Found"|trans}} {{data.users.length}} {{"Users "|trans}}</h1>
<mat-form-field style="width: 100%"> <div style="height: 110px">
<mat-select [(value)]="selected" <div *ngIf="data.users.length < 5">
[compareWith]="compareFn" <div>
[formControl]="UserSelectControl" <label>{{'Choose a User'|trans}}: </label>
placeholder="{{'Choose a User'|trans}}" required> </div>
<mat-option *ngFor="let u of data.users" value="{{u.id}}">{{u.name}}</mat-option> <mat-radio-group required [formControl]="UserSelectControl" [(ngModel)]="selected">
</mat-select> <mat-radio-button *ngFor="let u of data.users" value="{{u.id}}"
style="padding-right: 10px">{{u.name}}</mat-radio-button>
</mat-radio-group>
</div>
<div *ngIf="data.users.length >= 5">
<mat-form-field style="width: 100%" >
<mat-select [(value)]="selected"
[compareWith]="compareFn"
[formControl]="UserSelectControl"
placeholder="{{'Choose a User'|trans}}" required>
<mat-option *ngFor="let u of data.users" value="{{u.id}}">{{u.name}}</mat-option>
</mat-select>
</mat-form-field>
</div>
<mat-error *ngIf="UserSelectControl.hasError('required')">{{"Please choose a User"|trans}}</mat-error> <mat-error *ngIf="UserSelectControl.hasError('required')">{{"Please choose a User"|trans}}</mat-error>
</mat-form-field> </div>
<div style="float: right"> <div style="float: right">
<button mat-raised-button (click)="onNoClick()">{{"Cancel"|trans}}</button> <button mat-raised-button (click)="onNoClick()">{{"Cancel"|trans}}</button>
<button mat-raised-button color="primary" [mat-dialog-close]="selected" cdkFocusInitial>{{"Confirm"|trans}}</button> <button mat-raised-button color="primary" [mat-dialog-close]="selected" cdkFocusInitial>{{"Confirm"|trans}}</button>
......
import {NgModule} from '@angular/core'; import {NgModule} from '@angular/core';
import { import {
// MatAutocompleteModule, MatAutocompleteModule,
MatButtonModule, MatButtonModule,
// MatButtonToggleModule, MatButtonToggleModule,
MatCardModule, MatCardModule,
// MatCheckboxModule, MatCheckboxModule,
MatChipsModule, MatChipsModule,
// MatDatepickerModule, MatDatepickerModule,
MatDialogModule, MatDialogModule,
// MatExpansionModule, MatExpansionModule,
// MatGridListModule, MatGridListModule,
// MatIconModule, MatIconModule,
MatInputModule, MatInputModule,
// MatListModule, MatListModule,
// MatMenuModule, MatMenuModule,
// MatNativeDateModule, MatNativeDateModule,
// MatPaginatorModule, MatPaginatorModule,
// MatProgressBarModule, MatProgressBarModule,
// MatProgressSpinnerModule, MatProgressSpinnerModule,
MatRadioModule, MatRadioModule,
// MatRippleModule, MatRippleModule,
MatSelectModule, MatSelectModule,
// MatSidenavModule, MatSidenavModule,
// MatSliderModule, MatSliderModule,
// MatSlideToggleModule, MatSlideToggleModule,
// MatSnackBarModule, MatSnackBarModule,
// MatSortModule, MatSortModule,
// MatTableModule, MatTableModule,
// MatTabsModule, MatTabsModule,
// MatToolbarModule, MatToolbarModule,
// MatTooltipModule, MatTooltipModule,
// MatStepperModule, MatStepperModule,
} from '@angular/material'; } from '@angular/material';
import {CdkTableModule} from '@angular/cdk/table'; import {CdkTableModule} from '@angular/cdk/table';
@NgModule({ @NgModule({
exports: [ exports: [
CdkTableModule, CdkTableModule,
// MatAutocompleteModule, MatAutocompleteModule,
MatButtonModule, MatButtonModule,
// MatButtonToggleModule, MatButtonToggleModule,
MatCardModule, MatCardModule,
// MatCheckboxModule, MatCheckboxModule,
MatChipsModule, MatChipsModule,
// MatStepperModule, MatStepperModule,
// MatDatepickerModule, MatDatepickerModule,
MatDialogModule, MatDialogModule,
// MatExpansionModule, MatExpansionModule,
// MatGridListModule, MatGridListModule,
// MatIconModule, MatIconModule,
MatInputModule, MatInputModule,
// MatListModule, MatListModule,
// MatMenuModule, MatMenuModule,
// MatNativeDateModule, MatNativeDateModule,
// MatPaginatorModule, MatPaginatorModule,
// MatProgressBarModule, MatProgressBarModule,
// MatProgressSpinnerModule, MatProgressSpinnerModule,
MatRadioModule, MatRadioModule,
// MatRippleModule, MatRippleModule,
MatSelectModule, MatSelectModule,
// MatSidenavModule, MatSidenavModule,
// MatSliderModule, MatSliderModule,
// MatSlideToggleModule, MatSlideToggleModule,
// MatSnackBarModule, MatSnackBarModule,
// MatSortModule, MatSortModule,
// MatTableModule, MatTableModule,
// MatTabsModule, MatTabsModule,
// MatToolbarModule, MatToolbarModule,
// MatTooltipModule, MatTooltipModule,
] ]
}) })
export class MaterialModule { export class MaterialModule {
......
...@@ -3,6 +3,7 @@ import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http'; ...@@ -3,6 +3,7 @@ import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import {Browser, DataStore} from '@app/globals'; import {Browser, DataStore} from '@app/globals';
import {GuacObjAddResp, SystemUser, TreeNode, User as _User} from '@app/model'; import {GuacObjAddResp, SystemUser, TreeNode, User as _User} from '@app/model';
import {SettingService} from './setting'; import {SettingService} from './setting';
import {getCookie} from '@app/utils/common';
@Injectable() @Injectable()
...@@ -12,23 +13,43 @@ export class HttpService { ...@@ -12,23 +13,43 @@ export class HttpService {
constructor(private http: HttpClient, private settingSrv: SettingService) { constructor(private http: HttpClient, private settingSrv: SettingService) {
} }
setOptionsCSRFToken(options) {
const csrfToken = getCookie('csrftoken');
let headers;
if (!options) {
options = {};
}
if (!options.headers) {
headers = new HttpHeaders();
} else {
headers = options.headers;
}
headers = headers.set('X-CSRFToken', csrfToken);
options.headers = headers;
return options;
}
get(url: string, options?: any) { get(url: string, options?: any) {
return this.http.get(url, options); return this.http.get(url, options);
} }
post(url: string, options?: any) { post(url: string, body: any, options?: any) {
return this.http.post(url, options); options = this.setOptionsCSRFToken(options);
return this.http.post(url, body, options);
} }
put(url: string, options?: any) { put(url: string, options?: any) {
options = this.setOptionsCSRFToken(options);
return this.http.put(url, options); return this.http.put(url, options);
} }
delete(url: string, options?: any) { delete(url: string, options?: any) {
options = this.setOptionsCSRFToken(options);
return this.http.delete(url, options); return this.http.delete(url, options);
} }
patch(url: string, options?: any) { patch(url: string, options?: any) {
options = this.setOptionsCSRFToken(options);
return this.http.patch(url, options); return this.http.patch(url, options);
} }
...@@ -88,6 +109,25 @@ export class HttpService { ...@@ -88,6 +109,25 @@ export class HttpService {
return this.http.get<Array<SystemUser>>(url); return this.http.get<Array<SystemUser>>(url);
} }
favoriteAsset(assetId: string, favorite: boolean) {
let url: string;
if (favorite) {
url = `/api/v1/assets/favorite-assets/`;
const data = {
asset: assetId
};
return this.post(url, data);
} else {
url = `/api/v1/assets/favorite-assets/?asset=${assetId}`;
return this.delete(url);
}
}
getFavoriteAssets() {
const url = '/api/v1/assets/favorite-assets/';
return this.http.get<Array<any>>(url);
}
getGuacamoleToken(user_id: string, authToken: string) { getGuacamoleToken(user_id: string, authToken: string) {
const body = new HttpParams() const body = new HttpParams()
.set('username', user_id) .set('username', user_id)
......
...@@ -31,3 +31,19 @@ export function newTerminal(fontSize?: number) { ...@@ -31,3 +31,19 @@ export function newTerminal(fontSize?: number) {
} }
}); });
} }
export function getCookie(name: string): string {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
...@@ -76,5 +76,8 @@ ...@@ -76,5 +76,8 @@
"yes": "是", "yes": "是",
"no": "否", "no": "否",
"cols": "列数", "cols": "列数",
"rows": "行数" "rows": "行数",
"favorite": "收藏",
"disfavor": "取消收藏",
"success": "成功"
} }
...@@ -124,3 +124,17 @@ body ::-webkit-scrollbar-thumb { ...@@ -124,3 +124,17 @@ body ::-webkit-scrollbar-thumb {
display: inline-block; display: inline-block;
font: normal normal normal 14px/1 FontAwesome !important; font: normal normal normal 14px/1 FontAwesome !important;
} }
#toast-container > .toast-warning:before {
}
#toast-container > .toast-error:before {
}
#toast-container > .toast-info:before {
}
#toast-container > .toast-success:before {
content: "";
}
@import '~@angular/material/theming';
@include mat-core();
$my-teal: (
50: #e0f2f1,
100: #b2dfdb,
200: #80cbc4,
300: #4db6ac,
400: #26a69a,
500: #1ab394,
600: #00897b,
700: #00796b,
800: #00695c,
900: #004d40,
A100: #a7ffeb,
A200: #64ffda,
A400: #1de9b6,
A700: #00bfa5,
contrast: (
50: $dark-primary-text,
100: $dark-primary-text,
200: $dark-primary-text,
300: $dark-primary-text,
400: $dark-primary-text,
500: $light-primary-text,
600: $light-primary-text,
700: $light-primary-text,
800: $light-primary-text,
900: $light-primary-text,
A100: $dark-primary-text,
A200: $dark-primary-text,
A400: $dark-primary-text,
A700: $dark-primary-text,
)
);
$candy-app-primary: mat-palette($my-teal, 500);
$candy-app-accent: mat-palette($my-teal, 500);
// The warn palette is optional (defaults to red).
$candy-app-warn: mat-palette($mat-red);
// Create the theme object (a Sass map containing all of the palettes).
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($candy-app-theme);
.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}html #layuicss-layer{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;border-radius:2px;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layer-anim{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-00{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 15px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:5px 5px 0;padding:0 15px;border:1px solid #dedede;background-color:#fff;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#1E9FFF;background-color:#1E9FFF;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:8px 15px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:5px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#E9E7E7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:230px;height:36px;margin:0 auto;line-height:30px;padding-left:10px;border:1px solid #e6e6e6;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px;padding:6px 10px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;overflow:hidden;cursor:pointer}.layui-layer-tab .layui-layer-title span.layui-this{height:43px;border-left:1px solid #eee;border-right:1px solid #eee;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment