├── src ├── assets │ ├── .gitkeep │ └── config.json ├── app │ ├── user │ │ ├── log │ │ │ ├── log.component.less │ │ │ ├── log.component.html │ │ │ └── log.component.ts │ │ ├── user.component.less │ │ ├── user.component.ts │ │ ├── base-setting │ │ │ ├── base-setting.component.less │ │ │ ├── base-setting.component.html │ │ │ └── base-setting.component.ts │ │ └── user.component.html │ ├── auth │ │ ├── outlook │ │ │ ├── outlook.component.less │ │ │ ├── outlook.component.html │ │ │ └── outlook.component.ts │ │ ├── github │ │ │ ├── github.component.less │ │ │ ├── github.component.html │ │ │ └── github.component.ts │ │ └── auth.guard.ts │ ├── component │ │ └── page404 │ │ │ ├── page404.component.less │ │ │ ├── page404.component.html │ │ │ ├── page404.component.ts │ │ │ └── page404.component.spec.ts │ ├── index │ │ ├── index.component.less │ │ ├── index.component.ts │ │ └── index.component.html │ ├── login │ │ ├── login.component.html │ │ ├── login.component.less │ │ └── login.component.ts │ ├── http-interceptors │ │ ├── httpInterceptorProviders.ts │ │ └── noop-interceptor.ts │ ├── app.component.html │ ├── app.component.less │ ├── service │ │ ├── storage.service.ts │ │ ├── message.service.ts │ │ └── http-client.service.ts │ ├── app.component.ts │ ├── app-routing.module.ts │ └── app.module.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── index.html ├── main.ts ├── test.ts ├── polyfills.ts └── styles.less ├── .editorconfig ├── e2e ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts ├── tsconfig.json └── protractor.conf.js ├── tsconfig.app.json ├── tsconfig.spec.json ├── tsconfig.json ├── .gitignore ├── .browserslistrc ├── README.md ├── karma.conf.js ├── package.json ├── tslint.json └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/user/log/log.component.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/auth/outlook/outlook.component.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/component/page404/page404.component.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/index/index.component.less: -------------------------------------------------------------------------------- 1 | .index{ 2 | padding: 80px; 3 | } 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luoye663/e5-html/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/assets/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "heroesUrl": "api/heroes", 3 | "textfile": "assets/textfile.txt" 4 | } 5 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | apiUrl: '/api' 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/auth/github/github.component.less: -------------------------------------------------------------------------------- 1 | .example { 2 | text-align: center; 3 | //background: rgba(0, 0, 0, 0.05); 4 | border-radius: 4px; 5 | margin-bottom: 20px; 6 | padding: 30px 50px; 7 | margin: 20px 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/component/page404/page404.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 |
6 | -------------------------------------------------------------------------------- /src/app/login/login.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 | 8 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/login/login.component.less: -------------------------------------------------------------------------------- 1 | .icon { 2 | nz-spin { 3 | margin: 15% 50% 25% 50%; 4 | width: 6em; 5 | i { 6 | font-size: 6em; 7 | } 8 | } 9 | } 10 | 11 | nz-alert { 12 | margin-top: 10px; 13 | margin-bottom: 16px; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | E5续订 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo(): Promise { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/e2e", 6 | "module": "commonjs", 7 | "target": "es2018", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/index/index.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-index', 5 | templateUrl: './index.component.html', 6 | styleUrls: ['./index.component.less'] 7 | }) 8 | export class IndexComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /src/app/component/page404/page404.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page404', 5 | templateUrl: './page404.component.html', 6 | styleUrls: ['./page404.component.less'] 7 | }) 8 | export class Page404Component implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/http-interceptors/httpInterceptorProviders.ts: -------------------------------------------------------------------------------- 1 | /* "Barrel" of Http Interceptors */ 2 | import {HTTP_INTERCEPTORS} from '@angular/common/http'; 3 | 4 | import {NoopInterceptor} from './noop-interceptor'; 5 | 6 | /** Http interceptor providers in outside-in order */ 7 | export const httpInterceptorProviders = [ 8 | {provide: HTTP_INTERCEPTORS, useClass: NoopInterceptor, multi: true}, 9 | ]; 10 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/app/auth/github/github.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 8 |
9 | 10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 |
  • 首页
  • 6 |
  • 个人设置
  • 7 |
  • {{loginTitle}}
  • 8 |
9 |
10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/app/user/user.component.less: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 120px; 3 | height: 31px; 4 | background: rgba(255, 255, 255, 0.2); 5 | margin: 16px 30px 16px 0; 6 | float: left; 7 | } 8 | 9 | .header-menu { 10 | line-height: 64px; 11 | } 12 | 13 | .sider-menu { 14 | height: 100%; 15 | border-right: 0; 16 | } 17 | 18 | .inner-layout { 19 | padding: 0 24px 24px; 20 | } 21 | 22 | nz-breadcrumb { 23 | margin: 16px 0; 24 | } 25 | 26 | nz-content { 27 | background: #fff; 28 | padding: 24px; 29 | min-height: 280px; 30 | } 31 | -------------------------------------------------------------------------------- /src/app/auth/outlook/outlook.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 8 |
9 | 10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /src/app/user/user.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {NzMessageService} from 'ng-zorro-antd/message'; 3 | 4 | @Component({ 5 | selector: 'app-user', 6 | templateUrl: './user.component.html', 7 | styleUrls: ['./user.component.less'] 8 | }) 9 | export class UserComponent implements OnInit { 10 | 11 | constructor(private message: NzMessageService) { 12 | } 13 | 14 | ngOnInit(): void { 15 | } 16 | 17 | showMsg(): void { 18 | this.message.create('warning', `此功能正在测试中......`); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "downlevelIteration": true, 10 | "experimentalDecorators": true, 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "module": "es2020", 15 | "lib": [ 16 | "es2018", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/app.component.less: -------------------------------------------------------------------------------- 1 | .logo { 2 | width: 120px; 3 | height: 31px; 4 | background: rgba(255, 255, 255, 0.2); 5 | margin: 16px 30px 16px 0; 6 | float: left; 7 | color: #ffffff; 8 | background: #001529; 9 | font-size: 20px; 10 | text-align: center; 11 | line-height: 30px; 12 | } 13 | 14 | .header-menu { 15 | line-height: 64px; 16 | } 17 | 18 | .sider-menu { 19 | height: 100%; 20 | border-right: 0; 21 | } 22 | 23 | .inner-layout { 24 | padding: 0 24px 24px; 25 | } 26 | 27 | nz-breadcrumb { 28 | margin: 16px 0; 29 | } 30 | 31 | nz-content { 32 | background: #fff; 33 | padding: 24px; 34 | min-height: 280px; 35 | } 36 | -------------------------------------------------------------------------------- /src/app/service/storage.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class StorageService { 7 | constructor() { 8 | } 9 | 10 | set(key, value): any { 11 | localStorage.setItem(key, value); 12 | } 13 | 14 | get(key): any { 15 | return localStorage.getItem(key); 16 | } 17 | 18 | remove(key): void { 19 | localStorage.removeItem(key); 20 | } 21 | 22 | isLogin(): boolean { 23 | if (this.get('token') != null) { 24 | return true; 25 | } 26 | return false; 27 | } 28 | 29 | signOut(): void { 30 | this.remove('token'); 31 | this.remove('expire'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/user/base-setting/base-setting.component.less: -------------------------------------------------------------------------------- 1 | .input { 2 | padding-top: 10px; 3 | 4 | button { 5 | margin: 0em 0em 0em 0.5em; 6 | } 7 | } 8 | 9 | .card { 10 | 11 | div { 12 | //padding: 0 0 10% 0; 13 | } 14 | } 15 | .steps-content { 16 | margin-top: 16px; 17 | border: 1px dashed #e9e9e9; 18 | border-radius: 6px; 19 | background-color: #fafafa; 20 | min-height: 200px; 21 | text-align: center; 22 | padding-top: 80px; 23 | div{ 24 | padding: 0 20px 0 20px; 25 | } 26 | } 27 | 28 | .steps-action { 29 | margin-top: 24px; 30 | } 31 | 32 | button { 33 | margin-right: 8px; 34 | } 35 | .right { 36 | //position: absolute; 37 | right: 0px; 38 | //border: 3px solid #73AD21; 39 | //padding: 10px; 40 | } 41 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('e5-html app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/component/page404/page404.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Page404Component } from './page404.component'; 4 | 5 | describe('Page404Component', () => { 6 | let component: Page404Component; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ Page404Component ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(Page404Component); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false, 7 | apiUrl: 'http://127.0.0.1:8081' 8 | }; 9 | 10 | /* 11 | * For easier debugging in development mode, you can import the following file 12 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 13 | * 14 | * This import should be commented out in production mode because it will have a negative impact 15 | * on performance if an error is thrown. 16 | */ 17 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /src/app/user/user.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |
  • 5 |
      6 |
    • 基础配置
    • 7 |
    • 日志查看
    • 8 |
    • 消息通知(待上线)
    • 9 |
    10 |
  • 11 |
12 |
13 | 14 | 15 | Home 16 | List 17 | App 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line. 18 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line. 19 | -------------------------------------------------------------------------------- /src/app/service/message.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {NzNotificationService} from 'ng-zorro-antd/notification'; 3 | import {NzMessageService} from 'ng-zorro-antd/message'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class MessageService { 9 | 10 | constructor(private notification: NzNotificationService, private message: NzMessageService) { 11 | } 12 | 13 | createNotification(type: string, msg: string): void { 14 | this.notification.create( 15 | type, 16 | '信息', 17 | msg, 18 | {nzDuration: 6 * 1000} 19 | ); 20 | } 21 | 22 | createBasicMessageSuccess(msg: string): void { 23 | this.message.success(msg, { 24 | nzDuration: 3000 25 | }); 26 | } 27 | createBasicMessageError(msg: string): void { 28 | this.message.error(msg, { 29 | nzDuration: 3000 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ 31 | spec: { 32 | displayStacktrace: StacktraceOption.PRETTY 33 | } 34 | })); 35 | } 36 | }; -------------------------------------------------------------------------------- /src/app/user/log/log.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 8 | 9 |
10 |
11 | 12 | {{item.callTime | date: 'yyyy-MM-dd HH:mm:ss'}} | 13 |  {{item.originalMsg}} 14 | 失败 16 |  成功 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {Router} from '@angular/router'; 3 | import {StorageService} from './service/storage.service'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | templateUrl: './app.component.html', 8 | styleUrls: ['./app.component.less'] 9 | }) 10 | export class AppComponent { 11 | title = 'e5-html'; 12 | loginTitle: string; 13 | isLogin = false; 14 | 15 | constructor(private router: Router, private storage: StorageService) { 16 | if (!this.storage.isLogin()) { 17 | this.loginTitle = '登录'; 18 | this.isLogin = false; 19 | } else { 20 | this.loginTitle = '退出'; 21 | this.isLogin = true; 22 | } 23 | } 24 | 25 | gotoLogin(): void { 26 | // window.location.href = '/login'; 27 | if (!this.isLogin) { 28 | this.router.navigateByUrl('/login'); 29 | } else { 30 | this.storage.signOut(); 31 | this.router.navigateByUrl('/login'); 32 | console.log('点击了退出'); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # E5Html 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/e5-html'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e5-html", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build --prod --build-optimizer", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~10.2.0", 15 | "@angular/common": "~10.2.0", 16 | "@angular/compiler": "~10.2.0", 17 | "@angular/core": "~10.2.0", 18 | "@angular/forms": "~10.2.0", 19 | "@angular/platform-browser": "~10.2.0", 20 | "@angular/platform-browser-dynamic": "~10.2.0", 21 | "@angular/router": "~10.2.0", 22 | "ng-zorro-antd": "^10.1.2", 23 | "rxjs": "~6.6.0", 24 | "tslib": "^2.0.0", 25 | "zone.js": "~0.10.2" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "~0.1002.0", 29 | "@angular/cli": "~10.2.0", 30 | "@angular/compiler-cli": "~10.2.0", 31 | "@types/node": "^12.11.1", 32 | "@types/jasmine": "~3.5.0", 33 | "@types/jasminewd2": "~2.0.3", 34 | "codelyzer": "^6.0.0", 35 | "jasmine-core": "~3.6.0", 36 | "jasmine-spec-reporter": "~5.0.0", 37 | "karma": "~5.0.0", 38 | "karma-chrome-launcher": "~3.1.0", 39 | "karma-coverage-istanbul-reporter": "~3.0.2", 40 | "karma-jasmine": "~4.0.0", 41 | "karma-jasmine-html-reporter": "^1.5.0", 42 | "protractor": "~7.0.0", 43 | "ts-node": "~8.3.0", 44 | "tslint": "~6.1.0", 45 | "typescript": "~4.0.2" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/auth/auth.guard.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router} from '@angular/router'; 3 | import {Observable} from 'rxjs'; 4 | import {StorageService} from '../service/storage.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AuthGuard implements CanActivate { 10 | 11 | constructor(private storage: StorageService, private router: Router) { 12 | } 13 | 14 | canActivate( 15 | route: ActivatedRouteSnapshot, 16 | state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree { 17 | console.log('路由', state.url); 18 | const b = this.checkLogin(state.url); 19 | return b; 20 | } 21 | 22 | checkLogin(url): boolean { 23 | console.log('守卫', url); 24 | if (this.storage.get('token') == null) { 25 | console.log('token不存在'); 26 | this.router.navigate(['/login'], {queryParams: {errorText: '未登陆!'}}); 27 | return false; 28 | } 29 | const expire = this.storage.get('expire'); 30 | if (expire == null || expire - (Date.parse(new Date().toISOString()) / 1000) < 0) { 31 | console.log('到期时间不存在或已到期!', expire, expire - (Date.parse(new Date().toISOString()) / 1000)); 32 | this.router.navigate(['/login'], {queryParams: {errorText: '会话已超时,请重新登录!'}}); 33 | this.storage.signOut(); 34 | return false; 35 | } 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/app/index/index.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

说明

5 |
    6 |
  1. 此程序部署在我的服务器上,每隔2小时会自动调用outlook api 获取邮件列表
  2. 7 |
  3. 对于信息: 只会保存必要的 client_id、client_secret,其他任何内容都不会保存,
  4. 8 |
  5. 会读取授权的outlook账号邮箱邮件,但不会保存任何信息,仅仅是调用api。
  6. 9 |
  7. 请单独创建一个同域 E5 子账号进行授权,不要使用此账号进行发送、接收个人邮件,以免发生误会
  8. 10 |
11 |

12 | 用到技术或框架 13 |

14 |
15 |

spring boot

16 |

rabbitMq

17 | 18 | 需要安装rabbitmq_delayed_message_exchange插件 19 | 同时新建一个用户来对接此程序,由于 20 | 21 |

Redis

22 | 默认用1库,可自行在配置文件修改 23 |

Mysql5.7

24 | 自行导入sql 25 | 没有写清空日志功能,后面加上。 26 | 按道理说日志因该存到MongoDB里,所以? 27 |

Mybatis Plus

28 |

Spring Security

29 | 权限配置由于就那么几个,所以就没写到mysql里面。 30 |

log4j2

31 | 日志框架 32 | 33 |

Anguale

34 |

前端框架

35 |
36 |
37 |
38 |
39 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | 4 | import {LoginComponent} from './login/login.component'; 5 | import {BaseSettingComponent} from './user/base-setting/base-setting.component'; 6 | import {LogComponent} from './user/log/log.component'; 7 | import {UserComponent} from './user/user.component'; 8 | import {IndexComponent} from './index/index.component'; 9 | import {Page404Component} from './component/page404/page404.component'; 10 | import {AuthGuard} from './auth/auth.guard'; 11 | import {GithubComponent} from './auth/github/github.component'; 12 | import {OutlookComponent} from './auth/outlook/outlook.component'; 13 | 14 | const routes: Routes = [ 15 | /*首页*/ 16 | { 17 | path: '', component: IndexComponent 18 | }, 19 | /*登录*/ 20 | { 21 | path: 'login', component: LoginComponent 22 | }, 23 | /*用户*/ 24 | { 25 | path: 'user', component: UserComponent, 26 | canActivate: [AuthGuard], 27 | children: [ 28 | { 29 | path: 'baseSetting', component: BaseSettingComponent 30 | }, 31 | { 32 | path: 'log', component: LogComponent 33 | }, 34 | { 35 | path: 'login', component: LoginComponent 36 | }, 37 | ] 38 | }, 39 | /*github授权结果页*/ 40 | { 41 | path: 'auth2/receive', component: GithubComponent 42 | }, 43 | /*outlook授权结果页*/ 44 | { 45 | path: 'outlook/auth2/:userId/receive', component: OutlookComponent 46 | }, 47 | { 48 | path: 'outlook/auth2/receive', component: OutlookComponent 49 | }, 50 | /*404*/ 51 | { 52 | path: '404', component: Page404Component 53 | }, 54 | /*没有的页面默认进404*/ 55 | { 56 | path: '**', redirectTo: '404' 57 | } 58 | ]; 59 | 60 | @NgModule({ 61 | imports: [RouterModule.forRoot(routes)], 62 | exports: [RouterModule] 63 | }) 64 | export class AppRoutingModule { 65 | } 66 | -------------------------------------------------------------------------------- /src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {NavigationExtras, Route, Router} from '@angular/router'; 3 | import {ActivatedRoute} from '@angular/router'; 4 | import {HttpClientService} from '../service/http-client.service'; 5 | import {NzNotificationService} from 'ng-zorro-antd/notification'; 6 | import {MessageService} from '../service/message.service'; 7 | import {NzModalService} from 'ng-zorro-antd/modal'; 8 | 9 | @Component({ 10 | selector: 'app-login', 11 | templateUrl: './login.component.html', 12 | styleUrls: ['./login.component.less'] 13 | }) 14 | export class LoginComponent implements OnInit { 15 | isSpin = true; 16 | errorText = ''; 17 | loginUrl = ''; 18 | 19 | constructor(public route: ActivatedRoute, public router: Router, 20 | public http: HttpClientService, private notification: NzNotificationService, private modal: NzModalService) { 21 | route.queryParams.subscribe(value => { 22 | this.errorText = value.errorText; 23 | if (value.errorText != null) { 24 | this.createNotification('error', value.errorText); 25 | } 26 | }); 27 | http.get('/auth2/getGithubUrl', {}, value => { 28 | this.loginUrl = value.data; 29 | this.isSpin = false; 30 | setTimeout(() => { 31 | this.modal.create({ 32 | nzTitle: '温馨提示', 33 | nzContent: '客官,我看你停留在此页面挺久了,是不是不知道怎么登录?点击 屏幕中间 的小猫猫头像进行登录。', 34 | nzClosable: false 35 | }); 36 | }, 10000); 37 | }); 38 | // console.log('http返回请求', ht); 39 | } 40 | 41 | ngOnInit(): void { 42 | } 43 | 44 | goGithub(): void { 45 | window.location.href = this.loginUrl; 46 | } 47 | 48 | createNotification(type: string, msg: string): void { 49 | this.notification.create( 50 | type, 51 | '信息', 52 | msg, 53 | {nzDuration: 6 * 1000} 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/app/http-interceptors/noop-interceptor.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import { environment } from '../../environments/environment'; 3 | import { 4 | HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse 5 | } from '@angular/common/http'; 6 | 7 | import {Observable} from 'rxjs'; 8 | import {StorageService} from '../service/storage.service'; 9 | import {tap} from 'rxjs/operators'; 10 | import {MessageService} from '../service/message.service'; 11 | 12 | /** Pass untouched request through to the next request handler. */ 13 | @Injectable() 14 | export class NoopInterceptor implements HttpInterceptor { 15 | 16 | 17 | constructor(private storage: StorageService, private msg: MessageService) { 18 | } 19 | 20 | intercept(req: HttpRequest, next: HttpHandler): Observable> { 21 | const tokens = this.storage.get('token'); 22 | let httpRequest; 23 | // console.log(environment.apiUrl); 24 | const apiHost = environment.apiUrl; 25 | if (tokens) { 26 | httpRequest = req.clone({ 27 | // url: 'https://api.e5.qyi.io' + req.url 28 | url: apiHost + req.url, 29 | setHeaders: {token: tokens} 30 | }); 31 | } else { 32 | httpRequest = req.clone({ 33 | // url: 'https://api.e5.qyi.io' + req.url 34 | url: apiHost + req.url 35 | }); 36 | } 37 | return next.handle(httpRequest); 38 | /*return next.handle(httpRequest).pipe(tap( 39 | event => { 40 | if (event instanceof HttpResponse) { 41 | if (event.body.code !== 0) { 42 | this.msg.createNotification('error', event.body.msg); 43 | return; 44 | } 45 | } 46 | }, 47 | e => { 48 | switch (e.status) { 49 | case 403: 50 | this.msg.createNotification('error', '当前登录用户无权限,请检查会话是否过期!'); 51 | break; 52 | case 500: 53 | this.msg.createNotification('error', '服务端出错啦......请联系管理员。'); 54 | break; 55 | default: 56 | this.msg.createNotification('error', '请求服务端异常,请稍后重试!'); 57 | } 58 | } 59 | ));*/ 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/auth/outlook/outlook.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {HttpClientService} from '../../service/http-client.service'; 4 | import {DatePipe} from '@angular/common'; 5 | import {StorageService} from '../../service/storage.service'; 6 | 7 | @Component({ 8 | selector: 'app-outlook', 9 | templateUrl: './outlook.component.html', 10 | styleUrls: ['./outlook.component.less'] 11 | }) 12 | export class OutlookComponent implements OnInit { 13 | info = {status: '', title: '', subTitle: ''}; 14 | subInfo = {code: '', state: '', error: ''}; 15 | isSpinShow = true; 16 | 17 | constructor(private route: ActivatedRoute, private http: HttpClientService, datePipe: DatePipe, storage: StorageService) { 18 | route.queryParams.subscribe(value => { 19 | console.log(value); 20 | this.subInfo.code = value.code; 21 | this.subInfo.state = value.state; 22 | this.subInfo.error = value.error_description; 23 | }); 24 | /*授权失败!*/ 25 | if (this.subInfo.error !== undefined) { 26 | this.info.status = 'error'; 27 | this.info.title = '授权失败'; 28 | this.info.subTitle = this.subInfo.error; 29 | this.closeSpin(); 30 | return; 31 | } 32 | /*缺少参数*/ 33 | if (this.subInfo.code == null || this.subInfo.state == null || this.subInfo.code.length < 1 || this.subInfo.state.length < 1) { 34 | this.info.status = 'error'; 35 | this.info.title = '缺少参数'; 36 | this.info.subTitle = '从微软返回的信息中缺少 code 或 state 参数!'; 37 | this.closeSpin(); 38 | return; 39 | } 40 | const data = { 41 | code: this.subInfo.code, 42 | state: this.subInfo.state 43 | }; 44 | const userId = this.route.snapshot.params.userId; 45 | console.log('userid:', userId); 46 | http.get('/outlook/auth2/' + userId + '/receive', {params: data}, value => { 47 | console.log(value); 48 | this.info.status = 'success'; 49 | this.info.title = '授权成功!'; 50 | this.closeSpin(); 51 | }, msg => { 52 | this.info.status = 'error'; 53 | this.info.title = '授权失败'; 54 | this.info.subTitle = msg; 55 | this.closeSpin(); 56 | }); 57 | } 58 | 59 | ngOnInit(): void { 60 | } 61 | 62 | closeSpin(): void { 63 | this.isSpinShow = false; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/app/user/log/log.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {StorageService} from '../../service/storage.service'; 4 | import {HttpClientService} from '../../service/http-client.service'; 5 | import {MessageService} from '../../service/message.service'; 6 | 7 | @Component({ 8 | selector: 'app-log', 9 | templateUrl: './log.component.html', 10 | styleUrls: ['./log.component.less'] 11 | }) 12 | export class LogComponent implements OnInit { 13 | reverse = false; 14 | radioValue = 'C'; 15 | /*是否选中*/ 16 | radioModelArr = {}; 17 | listOfData = []; 18 | log = []; 19 | 20 | constructor(public router: ActivatedRoute, 21 | private storage: StorageService, 22 | private http: HttpClientService, 23 | private msg: MessageService) { 24 | let id; 25 | router.queryParams.subscribe(value => { 26 | console.log(value, value.id); 27 | id = value.id; 28 | }); 29 | if (id) { 30 | this.getLog(id); 31 | this.getOutlookListToRadio(true, id); 32 | } else { 33 | this.getOutlookListToRadio(true); 34 | } 35 | } 36 | 37 | ngOnInit(): void { 38 | } 39 | 40 | toggleReverse(): void { 41 | this.reverse = !this.reverse; 42 | } 43 | 44 | getOutlookListToRadio(isEmpty, key?): void { 45 | if (isEmpty) { 46 | this.listOfData = []; 47 | } 48 | this.http.get('/outlook/outlook/getOutlookList', {}, value => { 49 | value.data.forEach((v: any) => { 50 | this.radioModelArr['rm_' + v.id] = false; 51 | this.listOfData.push({ 52 | key: v.id, 53 | name: v.name, 54 | }); 55 | }); 56 | if (key) { 57 | this.radioModelArr['rm_' + key] = true; 58 | } 59 | }); 60 | } 61 | 62 | handelRadio(va): void { 63 | this.getLog(va); 64 | } 65 | 66 | /*获取日志*/ 67 | getLog(id): void { 68 | this.http.get('/outlookLog/findLog', {params: {outlookId: id}}, value => { 69 | this.log.splice(0, this.log.length); 70 | value.data.forEach((v: any) => { 71 | this.log.push({ 72 | callTime: v.callTime, 73 | result: v.result, 74 | msg: v.msg, 75 | originalMsg: v.originalMsg, 76 | }); 77 | }); 78 | }); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/app/service/http-client.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpClient} from '@angular/common/http'; 3 | import {Observable, throwError} from 'rxjs'; 4 | import {catchError, retry} from 'rxjs/operators'; 5 | import {MessageService} from './message.service'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class HttpClientService { 11 | configUrl = 'assets/config.json'; 12 | 13 | constructor(private http: HttpClient, private msg: MessageService) { 14 | } 15 | 16 | getConfig(): any { 17 | return this.http.get(this.configUrl); 18 | } 19 | 20 | get(url, options, cb?: (value) => any, errorHandel?: (ErrMsg) => any): any { 21 | /*if (options) { 22 | options = {}; 23 | }*/ 24 | return this.http.get(url, options).subscribe((value: any) => { 25 | if (value.code !== 0) { 26 | this.msg.createNotification('error', value.msg); 27 | if (errorHandel) { 28 | errorHandel(value.msg); 29 | } 30 | return; 31 | } 32 | if (cb) { 33 | cb(value); 34 | } 35 | }, e => { 36 | switch (e.status) { 37 | case 403: 38 | this.msg.createNotification('error', '当前登录用户无权限,请检查会话是否过期!'); 39 | break; 40 | case 404: 41 | this.msg.createNotification('error', '此接口不存在!'); 42 | break; 43 | case 500: 44 | this.msg.createNotification('error', '服务端出错啦......请联系管理员。' + e.msg); 45 | break; 46 | default: 47 | this.msg.createNotification('error', '请求服务端异常,请稍后重试! 错误码:' + e.status); 48 | } 49 | }); 50 | } 51 | 52 | post(url, body, cb?: (value) => any): any { 53 | return this.http.post(url, body).subscribe((value: any) => { 54 | if (value.code !== 0) { 55 | this.msg.createNotification('error', value.msg); 56 | return; 57 | } 58 | if (cb) { 59 | cb(value); 60 | } 61 | }, e => { 62 | switch (e.status) { 63 | case 403: 64 | this.msg.createNotification('error', '当前登录用户无权限,请检查会话是否过期!'); 65 | break; 66 | case 500: 67 | this.msg.createNotification('error', '服务端出错啦......请联系管理员。'); 68 | break; 69 | default: 70 | this.msg.createNotification('error', '请求服务端异常,请稍后重试!'); 71 | } 72 | }); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/auth/github/github.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ActivatedRoute} from '@angular/router'; 3 | import {HttpClientService} from '../../service/http-client.service'; 4 | import {HttpClient} from '@angular/common/http'; 5 | import {DatePipe} from '@angular/common'; 6 | import {StorageService} from '../../service/storage.service'; 7 | 8 | @Component({ 9 | selector: 'app-github', 10 | templateUrl: './github.component.html', 11 | styleUrls: ['./github.component.less'] 12 | }) 13 | export class GithubComponent implements OnInit { 14 | info = {status: '', title: '', subTitle: ''}; 15 | subInfo = {code: '', state: ''}; 16 | isSpinShow = true; 17 | 18 | constructor(private route: ActivatedRoute, private http: HttpClientService, datePipe: DatePipe, storage: StorageService) { 19 | route.queryParams.subscribe(value => { 20 | console.log(value); 21 | this.subInfo.code = value.code; 22 | this.subInfo.state = value.state; 23 | }); 24 | /*缺少参数*/ 25 | if (this.subInfo.code == null || this.subInfo.state == null || this.subInfo.code.length < 1 || this.subInfo.state.length < 1) { 26 | this.info.status = 'error'; 27 | this.info.title = '缺少参数'; 28 | this.info.subTitle = '从github返回的信息中缺少 code 或 state 参数!'; 29 | this.closeSpin(); 30 | return; 31 | } 32 | const data = { 33 | code: this.subInfo.code, 34 | state: this.subInfo.state 35 | }; 36 | http.get('/auth2/receive', {params: data}, value => { 37 | console.log(value); 38 | switch (value.code) { 39 | case 0: 40 | storage.set('authority', value.data.authority); 41 | storage.set('expire', (Date.parse(new Date().toISOString()) / 1000) + value.data.expire); 42 | storage.set('token', value.data.token); 43 | storage.set('username', value.data.username); 44 | this.info.status = 'success'; 45 | this.info.title = '登录成功!'; 46 | this.closeSpin(); 47 | break; 48 | case -1: 49 | this.info.status = 'error'; 50 | this.info.title = '登录失败'; 51 | this.closeSpin(); 52 | break; 53 | default: 54 | this.info.status = 'error'; 55 | this.info.title = '登录失败'; 56 | this.info.subTitle = value.msg + ',时间:' + datePipe.transform(value.data, 'yyyy-MM-dd HH:mm:ss'); 57 | this.closeSpin(); 58 | } 59 | }); 60 | } 61 | 62 | ngOnInit(): void { 63 | } 64 | 65 | closeSpin(): void { 66 | this.isSpinShow = false; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "align": { 8 | "options": [ 9 | "parameters", 10 | "statements" 11 | ] 12 | }, 13 | "array-type": false, 14 | "arrow-return-shorthand": true, 15 | "curly": true, 16 | "deprecation": { 17 | "severity": "warning" 18 | }, 19 | "eofline": true, 20 | "import-blacklist": [ 21 | true, 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": { 26 | "options": [ 27 | "spaces" 28 | ] 29 | }, 30 | "max-classes-per-file": false, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-empty": false, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-non-null-assertion": true, 60 | "no-redundant-jsdoc": true, 61 | "no-switch-case-fall-through": true, 62 | "no-var-requires": false, 63 | "object-literal-key-quotes": [ 64 | true, 65 | "as-needed" 66 | ], 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "semicolon": { 72 | "options": [ 73 | "always" 74 | ] 75 | }, 76 | "space-before-function-paren": { 77 | "options": { 78 | "anonymous": "never", 79 | "asyncArrow": "always", 80 | "constructor": "never", 81 | "method": "never", 82 | "named": "never" 83 | } 84 | }, 85 | "typedef": [ 86 | true, 87 | "call-signature" 88 | ], 89 | "typedef-whitespace": { 90 | "options": [ 91 | { 92 | "call-signature": "nospace", 93 | "index-signature": "nospace", 94 | "parameter": "nospace", 95 | "property-declaration": "nospace", 96 | "variable-declaration": "nospace" 97 | }, 98 | { 99 | "call-signature": "onespace", 100 | "index-signature": "onespace", 101 | "parameter": "onespace", 102 | "property-declaration": "onespace", 103 | "variable-declaration": "onespace" 104 | } 105 | ] 106 | }, 107 | "variable-name": { 108 | "options": [ 109 | "ban-keywords", 110 | "check-format", 111 | "allow-pascal-case" 112 | ] 113 | }, 114 | "whitespace": { 115 | "options": [ 116 | "check-branch", 117 | "check-decl", 118 | "check-operator", 119 | "check-separator", 120 | "check-type", 121 | "check-typecast" 122 | ] 123 | }, 124 | "component-class-suffix": true, 125 | "contextual-lifecycle": true, 126 | "directive-class-suffix": true, 127 | "no-conflicting-lifecycle": true, 128 | "no-host-metadata-property": true, 129 | "no-input-rename": true, 130 | "no-inputs-metadata-property": true, 131 | "no-output-native": true, 132 | "no-output-on-prefix": true, 133 | "no-output-rename": true, 134 | "no-outputs-metadata-property": true, 135 | "template-banana-in-box": true, 136 | "template-no-negated-async": true, 137 | "use-lifecycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "directive-selector": [ 140 | true, 141 | "attribute", 142 | "app", 143 | "camelCase" 144 | ], 145 | "component-selector": [ 146 | true, 147 | "element", 148 | "app", 149 | "kebab-case" 150 | ] 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {NgModule} from '@angular/core'; 3 | 4 | import {AppRoutingModule} from './app-routing.module'; 5 | import {AppComponent} from './app.component'; 6 | import {LoginComponent} from './login/login.component'; 7 | import {FormsModule} from '@angular/forms'; 8 | import {HttpClientModule} from '@angular/common/http'; 9 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 10 | import {NZ_I18N} from 'ng-zorro-antd/i18n'; 11 | import {zh_CN} from 'ng-zorro-antd/i18n'; 12 | import {CommonModule, DatePipe, registerLocaleData} from '@angular/common'; 13 | import zh from '@angular/common/locales/zh'; 14 | import {NzButtonModule} from 'ng-zorro-antd/button'; 15 | import {NzLayoutModule} from 'ng-zorro-antd/layout'; 16 | import {NzBreadCrumbModule} from 'ng-zorro-antd/breadcrumb'; 17 | import {NzMenuModule} from 'ng-zorro-antd/menu'; 18 | import {BaseSettingComponent} from './user/base-setting/base-setting.component'; 19 | import {NzCardModule} from 'ng-zorro-antd/card'; 20 | import {NzGridModule} from 'ng-zorro-antd/grid'; 21 | import {NzInputModule} from 'ng-zorro-antd/input'; 22 | import {LogComponent} from './user/log/log.component'; 23 | import {NzTimelineModule} from 'ng-zorro-antd/timeline'; 24 | import {NzTagModule} from 'ng-zorro-antd/tag'; 25 | import {NzPopconfirmModule} from 'ng-zorro-antd/popconfirm'; 26 | import {UserComponent} from './user/user.component'; 27 | import {IndexComponent} from './index/index.component'; 28 | import {Page404Component} from './component/page404/page404.component'; 29 | import {NzResultModule} from 'ng-zorro-antd/result'; 30 | import {NzIconModule} from 'ng-zorro-antd/icon'; 31 | import {NzMessageModule} from 'ng-zorro-antd/message'; 32 | import {NzSpinModule} from 'ng-zorro-antd/spin'; 33 | import {NzPopoverModule} from 'ng-zorro-antd/popover'; 34 | import {HttpClientService} from './service/http-client.service'; 35 | import {NzTableModule} from 'ng-zorro-antd/table'; 36 | import {NzModalModule} from 'ng-zorro-antd/modal'; 37 | import {NzStepsModule} from 'ng-zorro-antd/steps'; 38 | import {NzToolTipModule} from 'ng-zorro-antd/tooltip'; 39 | import {NzRadioModule} from 'ng-zorro-antd/radio'; 40 | import {StorageService} from './service/storage.service'; 41 | import {NzAlertModule} from 'ng-zorro-antd/alert'; 42 | import {NzNotificationModule} from 'ng-zorro-antd/notification'; 43 | import {OutlookComponent} from './auth/outlook/outlook.component'; 44 | import {GithubComponent} from './auth/github/github.component'; 45 | import {httpInterceptorProviders} from './http-interceptors/httpInterceptorProviders'; 46 | import {MessageService} from './service/message.service'; 47 | import { NzTypographyModule } from 'ng-zorro-antd/typography'; 48 | registerLocaleData(zh); 49 | 50 | @NgModule({ 51 | declarations: [ 52 | AppComponent, 53 | LoginComponent, 54 | BaseSettingComponent, 55 | LogComponent, 56 | UserComponent, 57 | IndexComponent, 58 | Page404Component, 59 | OutlookComponent, 60 | GithubComponent, 61 | ], 62 | imports: [ 63 | BrowserModule, 64 | AppRoutingModule, 65 | FormsModule, 66 | HttpClientModule, 67 | BrowserAnimationsModule, 68 | NzButtonModule, 69 | NzLayoutModule, 70 | NzBreadCrumbModule, 71 | NzMenuModule, 72 | NzCardModule, 73 | NzGridModule, 74 | NzInputModule, 75 | NzTimelineModule, 76 | NzTagModule, 77 | NzPopconfirmModule, 78 | NzResultModule, 79 | NzIconModule, 80 | NzMessageModule, 81 | NzSpinModule, 82 | NzPopoverModule, 83 | NzTableModule, 84 | NzModalModule, 85 | NzStepsModule, 86 | NzToolTipModule, 87 | NzRadioModule, 88 | NzAlertModule, 89 | NzNotificationModule, 90 | CommonModule, 91 | NzTypographyModule, 92 | ], 93 | providers: [{provide: NZ_I18N, useValue: zh_CN}, DatePipe, HttpClientService, MessageService, StorageService, 94 | httpInterceptorProviders], 95 | bootstrap: [AppComponent] 96 | }) 97 | export class AppModule { 98 | } 99 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "e5-html": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "less" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/e5-html", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": true, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets", 29 | { 30 | "glob": "**/*", 31 | "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", 32 | "output": "/assets/" 33 | } 34 | ], 35 | "styles": [ 36 | "src/styles.less" 37 | ], 38 | "scripts": [] 39 | }, 40 | "configurations": { 41 | "production": { 42 | "fileReplacements": [ 43 | { 44 | "replace": "src/environments/environment.ts", 45 | "with": "src/environments/environment.prod.ts" 46 | } 47 | ], 48 | "optimization": true, 49 | "outputHashing": "all", 50 | "sourceMap": false, 51 | "extractCss": true, 52 | "namedChunks": false, 53 | "extractLicenses": true, 54 | "vendorChunk": false, 55 | "buildOptimizer": true, 56 | "budgets": [ 57 | { 58 | "type": "initial", 59 | "maximumWarning": "2mb", 60 | "maximumError": "5mb" 61 | }, 62 | { 63 | "type": "anyComponentStyle", 64 | "maximumWarning": "6kb", 65 | "maximumError": "10kb" 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "options": { 74 | "browserTarget": "e5-html:build" 75 | }, 76 | "configurations": { 77 | "production": { 78 | "browserTarget": "e5-html:build:production" 79 | } 80 | } 81 | }, 82 | "extract-i18n": { 83 | "builder": "@angular-devkit/build-angular:extract-i18n", 84 | "options": { 85 | "browserTarget": "e5-html:build" 86 | } 87 | }, 88 | "test": { 89 | "builder": "@angular-devkit/build-angular:karma", 90 | "options": { 91 | "main": "src/test.ts", 92 | "polyfills": "src/polyfills.ts", 93 | "tsConfig": "tsconfig.spec.json", 94 | "karmaConfig": "karma.conf.js", 95 | "assets": [ 96 | "src/favicon.ico", 97 | "src/assets" 98 | ], 99 | "styles": [ 100 | "src/styles.less" 101 | ], 102 | "scripts": [] 103 | } 104 | }, 105 | "lint": { 106 | "builder": "@angular-devkit/build-angular:tslint", 107 | "options": { 108 | "tsConfig": [ 109 | "tsconfig.app.json", 110 | "tsconfig.spec.json", 111 | "e2e/tsconfig.json" 112 | ], 113 | "exclude": [ 114 | "**/node_modules/**" 115 | ] 116 | } 117 | }, 118 | "e2e": { 119 | "builder": "@angular-devkit/build-angular:protractor", 120 | "options": { 121 | "protractorConfig": "e2e/protractor.conf.js", 122 | "devServerTarget": "e5-html:serve" 123 | }, 124 | "configurations": { 125 | "production": { 126 | "devServerTarget": "e5-html:serve:production" 127 | } 128 | } 129 | } 130 | } 131 | } 132 | }, 133 | "defaultProject": "e5-html", 134 | "cli": { 135 | "analytics": false 136 | } 137 | } -------------------------------------------------------------------------------- /src/app/user/base-setting/base-setting.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 7 | 8 | 10 | 13 | 14 | 15 | 16 | 17 | 名称 18 | 描述 19 | 客户端ID 20 | 客户端秘钥 21 | 调用时间范围 22 | 预计下次调用时间 23 | 状态 24 | 操作 25 | 26 | 27 | 28 | 29 | {{ data.name }} 30 | {{ data.describe }} 31 | {{ data.client_id }} 32 | {{ data.client_secret }} 33 | {{ data.time }} 34 | {{ data.next_time * 1000 | date: 'yyyy-MM-dd HH:mm:ss'}} 35 | 36 | 37 | {{ data.static }} 38 | 39 | 40 | 41 | 开始 42 | 暂停 43 | | 44 | 配置 45 | | 46 | 日志 47 | | 48 | 删除 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | 57 |
58 | 67 | 配置信息 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | 79 |
80 | 81 | 82 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 |
92 | 93 |
94 | 95 | 96 | 97 |
98 |
99 |
    100 |
  • 说明:单位 秒(最低调用频率为 60 秒,最高为6小时)
  • 101 |
  • 范围,例如: 30-60,代表在30秒-60秒之间随机调用一次
  • 102 |
103 |
104 |
105 | 106 |
107 |
108 |
109 |
    110 |
  • 记得使用子账户且没有敏感邮件
  • 111 |
  • 如果授权失败请翻译就能大概知道错在哪
  • 112 |
  • 还是看不懂错误的话请截图+错误页面的url到我的博客留言
  • 113 |
114 |
115 |
116 | 117 |
118 |
119 | 120 | 121 |
122 | 125 | 129 | 132 |
133 |
134 |
135 |
136 | 137 |
138 | 140 | 141 | 名称 142 | 143 |
144 |
145 | 描述 146 | 148 |
149 |
150 |
151 |
152 | 161 | 捐赠 162 | 163 |

撸代码不易,如果此项目帮助到你的话,请喝杯咖啡吧~~~

164 |

从此项目自2020年3月上线以来,目前已有6500+个API应用在调用,到目前服务器大概花费1000+

165 |

捐赠列表 时间排序,感谢各位的支持~

166 | 172 |
173 |
174 |
175 |
176 | -------------------------------------------------------------------------------- /src/app/user/base-setting/base-setting.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {StorageService} from '../../service/storage.service'; 3 | import {HttpClient} from '@angular/common/http'; 4 | import {MessageService} from '../../service/message.service'; 5 | import {HttpClientService} from '../../service/http-client.service'; 6 | import {NzModalService} from 'ng-zorro-antd/modal'; 7 | 8 | @Component({ 9 | selector: 'app-base-setting', 10 | templateUrl: './base-setting.component.html', 11 | styleUrls: ['./base-setting.component.less'] 12 | }) 13 | export class BaseSettingComponent implements OnInit { 14 | /*列表*/ 15 | listOfData: any = []; 16 | /*显示对话框*/ 17 | isVisible = false; 18 | current = 0; 19 | index = 'First-content'; 20 | isNewClient = false; 21 | isTableLoading = true; 22 | OkDisabled = false; 23 | donation = true; 24 | userReplyUrl = false; 25 | newFrom = { 26 | name: '', 27 | describe: '' 28 | }; 29 | stepsInfo = { 30 | id: 0, 31 | clientId: '', 32 | clientSecret: '', 33 | tenantId: '', 34 | cronTimeRandomStart: '', 35 | cronTimeRandomEnd: '', 36 | cronTimeRandom: '', 37 | isNextButton: false 38 | }; 39 | 40 | constructor(private storage: StorageService, private http: HttpClientService, private msg: MessageService, 41 | private modal: NzModalService) { 42 | this.getOutlookList(false); 43 | if (storage.get('donation')) { 44 | this.donation = false; 45 | } 46 | /*this.modal.create({ 47 | nzTitle: '关于续订程序出现授权出错问题', 48 | nzContent: '程序已更新,请查看最新的教程,弹窗于一周后自动关闭: https://qyi.io/archives/687.html', 49 | nzClosable: false, 50 | });*/ 51 | } 52 | 53 | getOutlookList(isEmpty): void { 54 | if (isEmpty) { 55 | this.listOfData = []; 56 | } 57 | this.isTableLoading = true; 58 | this.http.get('/outlook/outlook/getOutlookList', {}, value => { 59 | value.data.forEach((v: any) => { 60 | this.listOfData.push({ 61 | key: v.id, 62 | name: v.name, 63 | describe: v.describes, 64 | client_id: v.clientId, 65 | client_secret: v.clientSecret, 66 | static: this.getStatus(v.status), 67 | static_color: this.getStaticColor(v.status), 68 | time: v.cronTimeRandomStart + '-' + v.cronTimeRandomEnd, 69 | next_time: v.nextTime 70 | }); 71 | }); 72 | // this.listOfData.push(); 73 | this.isTableLoading = false; 74 | }); 75 | } 76 | 77 | /* 78 | * 状态: 1、等待配置 2、暂停 3、运行中 4、封禁 5、已停止(由于调用错误导致的停止)6、等待授权 7、授权失败 79 | * 8、配置时间 80 | * */ 81 | getStatus(status): string { 82 | let val: string; 83 | switch (status) { 84 | case 1: 85 | val = '等待配置'; 86 | break; 87 | case 2: 88 | val = '暂停'; 89 | break; 90 | case 3: 91 | val = '运行中'; 92 | break; 93 | case 4: 94 | val = '封禁'; 95 | break; 96 | case 5: 97 | val = '已停止'; 98 | break; 99 | case 6: 100 | val = '等待授权'; 101 | break; 102 | case 7: 103 | val = '授权失败'; 104 | break; 105 | case 8: 106 | val = '配置时间'; 107 | break; 108 | default: 109 | val = '未知'; 110 | } 111 | return val; 112 | } 113 | 114 | getStaticColor(status): string { 115 | let val: string; 116 | switch (status) { 117 | case 1: 118 | val = 'default'; 119 | break; 120 | case 2: 121 | /*暂停*/ 122 | val = 'red'; 123 | break; 124 | case 3: 125 | /*绿色*/ 126 | val = 'green'; 127 | break; 128 | case 4: 129 | val = '#108ee9'; 130 | break; 131 | case 5: 132 | val = 'red'; 133 | break; 134 | case 6: 135 | /*等待授权*/ 136 | val = 'orange'; 137 | break; 138 | case 7: 139 | val = '#108ee9'; 140 | break; 141 | case 8: 142 | val = 'geekblue'; 143 | break; 144 | default: 145 | val = '#108ee9'; 146 | } 147 | return val; 148 | } 149 | 150 | ngOnInit(): void { 151 | } 152 | 153 | handleNewClient(): void { 154 | if (this.listOfData.length > 4) { 155 | this.msg.createNotification('error', '目前只允许添加5个应用。'); 156 | return; 157 | } 158 | this.isNewClient = true; 159 | } 160 | 161 | handleNewClone(): void { 162 | this.isNewClient = false; 163 | } 164 | 165 | /*新建-ok*/ 166 | handleNewOK(): void { 167 | this.OkDisabled = true; 168 | // this.isNewClient = false; 169 | this.http.post('/outlook/outlook/insertOne', {name: this.newFrom.name, describe: this.newFrom.describe}, value => { 170 | console.log(value); 171 | if (value.code === 0) { 172 | this.msg.createNotification('success', '创建成功!'); 173 | this.isNewClient = false; 174 | this.getOutlookList(true); 175 | } else { 176 | this.msg.createNotification('error', value.data); 177 | } 178 | this.OkDisabled = false; 179 | }); 180 | } 181 | 182 | /*点击 配置时间*/ 183 | handelSetting(key): void { 184 | this.isVisible = true; 185 | this.http.get('/outlook/outlook/getOutlookInfo', {params: {id: key}}, value => { 186 | this.stepsInfo = value.data; 187 | this.stepsInfo.cronTimeRandom = value.data.cronTimeRandomStart + '-' + value.data.cronTimeRandomEnd; 188 | this.current = value.data.step; 189 | }); 190 | } 191 | 192 | /* 193 | * 设置暂停状态 194 | * */ 195 | handelSetPause(key): void { 196 | this.http.get('/outlook/outlook/setPause', {params: {id: key}}, dvalue => { 197 | this.msg.createBasicMessageSuccess('设置成功!'); 198 | this.getOutlookList(true); 199 | }); 200 | } 201 | 202 | /* 203 | * 设置开始状态(待授权) 204 | * */ 205 | handelSetStart(key): void { 206 | this.http.get('/outlook/outlook/setStart', {params: {id: key}}, dvalue => { 207 | this.msg.createBasicMessageSuccess('设置成功!'); 208 | this.getOutlookList(true); 209 | }); 210 | } 211 | 212 | handelAuthorize(key): void { 213 | this.http.get('/outlook/auth2/getAuthorizeUrl', {params: {id: key}}, value => { 214 | console.log(value); 215 | window.location.href = value.data; 216 | }); 217 | } 218 | 219 | handleCancel(): void { 220 | this.isVisible = !this.isVisible; 221 | this.getOutlookList(true); 222 | } 223 | 224 | /* 225 | * 获取调用时间 226 | * */ 227 | handelGetNextTime(ids): void { 228 | this.http.get('/outlook/auth2/getAuthorizeUrl', {params: {id: ids}}, value => { 229 | console.log(value); 230 | window.location.href = value.data; 231 | }); 232 | } 233 | 234 | /* 235 | * 删除 236 | * */ 237 | handelDelete(outlookId, name): void { 238 | this.modal.create({ 239 | nzTitle: '删除此项', 240 | nzContent: '将删除 ' + name + ' ?', 241 | nzClosable: false, 242 | nzOnOk: () => { 243 | this.http.get('/outlook/outlook/delete', {params: {id: outlookId}}, value => { 244 | this.msg.createBasicMessageSuccess('删除成功'); 245 | const chat = this; 246 | setTimeout(() => { 247 | this.getOutlookList(true); 248 | }, 1000); 249 | }); 250 | } 251 | }); 252 | } 253 | 254 | pre(): void { 255 | this.current -= 1; 256 | this.changeContent(); 257 | } 258 | 259 | next(): void { 260 | switch (this.current) { 261 | /*保存key*/ 262 | case 0: 263 | if (this.stepsInfo.clientId == null || 264 | this.stepsInfo.clientSecret == null || 265 | this.stepsInfo.clientId.length < 1 || 266 | this.stepsInfo.clientSecret.length < 1) { 267 | this.msg.createBasicMessageError('请不要留空'); 268 | return; 269 | } 270 | this.stepsInfo.isNextButton = true; 271 | this.http.post('/outlook/outlook/save', 272 | { 273 | client_id: this.stepsInfo.clientId, 274 | client_secret: this.stepsInfo.clientSecret, 275 | outlook_id: this.stepsInfo.id, 276 | tenant_id: this.stepsInfo.tenantId 277 | }, value => { 278 | this.current += 1; 279 | }); 280 | this.setNextButtonStatus(false); 281 | break; 282 | /*保存时间*/ 283 | case 1: 284 | const cronTime = this.stepsInfo.cronTimeRandom.split('-'); 285 | if (cronTime.length !== 2 || parseInt(cronTime[0], 10) < 1 || parseInt(cronTime[1], 10) < 1) { 286 | this.msg.createBasicMessageError('请正确填写时间范围'); 287 | return; 288 | } 289 | this.stepsInfo.isNextButton = true; 290 | this.http.post('/outlook/outlook/saveRandomTime', { 291 | outlookId: this.stepsInfo.id, 292 | cronTime: 0, 293 | crondomTime: this.stepsInfo.cronTimeRandom 294 | }, value => { 295 | this.current += 1; 296 | this.changeContent(); 297 | }); 298 | this.setNextButtonStatus(false); 299 | break; 300 | } 301 | } 302 | 303 | done(): void { 304 | console.log('done'); 305 | this.handelAuthorize(this.stepsInfo.id); 306 | } 307 | 308 | setNextButtonStatus(v): void { 309 | this.stepsInfo.isNextButton = v; 310 | } 311 | 312 | changeContent(): void { 313 | switch (this.current) { 314 | case 0: { 315 | this.index = 'ssss'; 316 | break; 317 | } 318 | case 1: { 319 | this.index = 'Second-content'; 320 | break; 321 | } 322 | case 2: { 323 | this.index = 'third-content'; 324 | break; 325 | } 326 | default: { 327 | this.index = 'error'; 328 | } 329 | } 330 | } 331 | 332 | handelDonation(bool): void { 333 | if (bool) { 334 | this.donation = true; 335 | } else { 336 | this.donation = false; 337 | } 338 | } 339 | 340 | getUserReplyUrlToOutlook(): void { 341 | this.http.get('/getUserReplyUrlToOutlook', {}, value => { 342 | this.modal.create({ 343 | nzTitle: '请勿泄露回调地址', 344 | nzContent: value.data, 345 | nzClosable: false, 346 | }); 347 | }); 348 | } 349 | 350 | donationClosePermanent(): void { 351 | this.donation = false; 352 | this.storage.set('donation', 1); 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /src/styles.less: -------------------------------------------------------------------------------- 1 | @import "../node_modules/ng-zorro-antd/ng-zorro-antd.less"; 2 | @theme: default; 3 | 4 | // The prefix to use on all css classes from ant. 5 | @ant-prefix: ant; 6 | 7 | // An override for the html selector for theme prefixes 8 | @html-selector: html; 9 | 10 | // -------- Colors ----------- 11 | @primary-color: @blue-6; 12 | @info-color: @primary-color; 13 | @success-color: @green-6; 14 | @processing-color: @blue-6; 15 | @error-color: @red-5; 16 | @highlight-color: @red-5; 17 | @warning-color: @gold-6; 18 | @normal-color: #d9d9d9; 19 | @white: #fff; 20 | @black: #000; 21 | 22 | // Color used by default to control hover and active backgrounds and for 23 | // alert info backgrounds. 24 | @primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) 25 | @primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) 26 | @primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused 27 | @primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused 28 | @primary-5: color( 29 | ~`colorPalette('@{primary-color}', 5) ` 30 | ); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) 31 | @primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color 32 | @primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) 33 | @primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused 34 | @primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused 35 | @primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused 36 | 37 | // Base Scaffolding Variables 38 | // --- 39 | 40 | // Background color for `` 41 | @body-background: #fff; 42 | // Base background color for most components 43 | @component-background: #fff; 44 | // Popover background color 45 | @popover-background: @component-background; 46 | @popover-customize-border-color: @border-color-split; 47 | @font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 48 | 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 49 | 'Noto Color Emoji'; 50 | @code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; 51 | @text-color: fade(@black, 85%); 52 | @text-color-secondary: fade(@black, 45%); 53 | @text-color-inverse: @white; 54 | @icon-color: inherit; 55 | @icon-color-hover: fade(@black, 75%); 56 | @heading-color: fade(@black, 85%); 57 | @text-color-dark: fade(@white, 85%); 58 | @text-color-secondary-dark: fade(@white, 65%); 59 | @text-selection-bg: @primary-color; 60 | @font-variant-base: tabular-nums; 61 | @font-feature-settings-base: 'tnum'; 62 | @font-size-base: 14px; 63 | @font-size-lg: @font-size-base + 2px; 64 | @font-size-sm: 12px; 65 | @heading-1-size: ceil(@font-size-base * 2.71); 66 | @heading-2-size: ceil(@font-size-base * 2.14); 67 | @heading-3-size: ceil(@font-size-base * 1.71); 68 | @heading-4-size: ceil(@font-size-base * 1.42); 69 | @heading-5-size: ceil(@font-size-base * 1.14); 70 | // https://github.com/ant-design/ant-design/issues/20210 71 | @line-height-base: 1.5715; 72 | @border-radius-base: 2px; 73 | @border-radius-sm: @border-radius-base; 74 | 75 | // vertical paddings 76 | @padding-lg: 24px; // containers 77 | @padding-md: 16px; // small containers and buttons 78 | @padding-sm: 12px; // Form controls and items 79 | @padding-xs: 8px; // small items 80 | @padding-xss: 4px; // more small 81 | 82 | // vertical padding for all form controls 83 | @control-padding-horizontal: @padding-sm; 84 | @control-padding-horizontal-sm: @padding-xs; 85 | 86 | // vertical margins 87 | @margin-lg: 24px; // containers 88 | @margin-md: 16px; // small containers and buttons 89 | @margin-sm: 12px; // Form controls and items 90 | @margin-xs: 8px; // small items 91 | @margin-xss: 4px; // more small 92 | 93 | // height rules 94 | @height-base: 32px; 95 | @height-lg: 40px; 96 | @height-sm: 24px; 97 | 98 | // The background colors for active and hover states for things like 99 | // list items or table cells. 100 | @item-active-bg: @primary-1; 101 | @item-hover-bg: #f5f5f5; 102 | 103 | // ICONFONT 104 | @iconfont-css-prefix: anticon; 105 | 106 | // LINK 107 | @link-color: @primary-color; 108 | @link-hover-color: color(~`colorPalette('@{link-color}', 5) `); 109 | @link-active-color: color(~`colorPalette('@{link-color}', 7) `); 110 | @link-decoration: none; 111 | @link-hover-decoration: none; 112 | @link-focus-decoration: none; 113 | @link-focus-outline: 0; 114 | 115 | // Animation 116 | @ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); 117 | @ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); 118 | @ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); 119 | @ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); 120 | @ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); 121 | @ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); 122 | @ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); 123 | @ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); 124 | @ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); 125 | @ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); 126 | @ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); 127 | @ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); 128 | @ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); 129 | @ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); 130 | 131 | // Border color 132 | @border-color-base: hsv(0, 0, 85%); // base border outline a component 133 | @border-color-split: hsv(0, 0, 94%); // split border inside a component 134 | @border-color-inverse: @white; 135 | @border-width-base: 1px; // width of the border for a component 136 | @border-style-base: solid; // style of a components border 137 | 138 | // Outline 139 | @outline-blur-size: 0; 140 | @outline-width: 2px; 141 | @outline-color: @primary-color; 142 | @outline-fade: 20%; 143 | 144 | @background-color-light: hsv(0, 0, 98%); // background of header and selected item 145 | @background-color-base: hsv(0, 0, 96%); // Default grey background color 146 | 147 | // Disabled states 148 | @disabled-color: fade(#000, 25%); 149 | @disabled-bg: @background-color-base; 150 | @disabled-color-dark: fade(#fff, 35%); 151 | 152 | // Shadow 153 | @shadow-color: rgba(0, 0, 0, 0.15); 154 | @shadow-color-inverse: @component-background; 155 | @box-shadow-base: @shadow-2; 156 | @shadow-1-up: 0 -6px 16px -8px rgba(0, 0, 0, 0.08), 0 -9px 28px 0 rgba(0, 0, 0, 0.05), 157 | 0 -12px 48px 16px rgba(0, 0, 0, 0.03); 158 | @shadow-1-down: 0 6px 16px -8px rgba(0, 0, 0, 0.08), 0 9px 28px 0 rgba(0, 0, 0, 0.05), 159 | 0 12px 48px 16px rgba(0, 0, 0, 0.03); 160 | @shadow-1-left: -6px 0 16px -8px rgba(0, 0, 0, 0.08), -9px 0 28px 0 rgba(0, 0, 0, 0.05), 161 | -12px 0 48px 16px rgba(0, 0, 0, 0.03); 162 | @shadow-1-right: 6px 0 16px -8px rgba(0, 0, 0, 0.08), 9px 0 28px 0 rgba(0, 0, 0, 0.05), 163 | 12px 0 48px 16px rgba(0, 0, 0, 0.03); 164 | @shadow-2: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 165 | 0 9px 28px 8px rgba(0, 0, 0, 0.05); 166 | 167 | // Buttons 168 | @btn-font-weight: 400; 169 | @btn-border-radius-base: @border-radius-base; 170 | @btn-border-radius-sm: @border-radius-base; 171 | @btn-border-width: @border-width-base; 172 | @btn-border-style: @border-style-base; 173 | @btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); 174 | @btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); 175 | @btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); 176 | 177 | @btn-primary-color: #fff; 178 | @btn-primary-bg: @primary-color; 179 | 180 | @btn-default-color: @text-color; 181 | @btn-default-bg: @component-background; 182 | @btn-default-border: @border-color-base; 183 | 184 | @btn-danger-color: #fff; 185 | @btn-danger-bg: @error-color; 186 | @btn-danger-border: @error-color; 187 | 188 | @btn-disable-color: @disabled-color; 189 | @btn-disable-bg: @disabled-bg; 190 | @btn-disable-border: @border-color-base; 191 | 192 | @btn-default-ghost-color: @component-background; 193 | @btn-default-ghost-bg: transparent; 194 | @btn-default-ghost-border: @component-background; 195 | 196 | @btn-font-size-lg: @font-size-lg; 197 | @btn-font-size-sm: @font-size-base; 198 | @btn-padding-horizontal-base: @padding-md - 1px; 199 | @btn-padding-horizontal-lg: @btn-padding-horizontal-base; 200 | @btn-padding-horizontal-sm: @padding-xs - 1px; 201 | 202 | @btn-height-base: @height-base; 203 | @btn-height-lg: @height-lg; 204 | @btn-height-sm: @height-sm; 205 | 206 | @btn-line-height: @line-height-base; 207 | 208 | @btn-circle-size: @btn-height-base; 209 | @btn-circle-size-lg: @btn-height-lg; 210 | @btn-circle-size-sm: @btn-height-sm; 211 | 212 | @btn-square-size: @btn-height-base; 213 | @btn-square-size-lg: @btn-height-lg; 214 | @btn-square-size-sm: @btn-height-sm; 215 | @btn-square-only-icon-size: @font-size-base + 2px; 216 | @btn-square-only-icon-size-sm: @font-size-base; 217 | @btn-square-only-icon-size-lg: @btn-font-size-lg + 2px; 218 | 219 | @btn-group-border: @primary-5; 220 | 221 | @btn-link-hover-bg: transparent; 222 | @btn-text-hover-bg: rgba(0, 0, 0, 0.018); 223 | 224 | // Checkbox 225 | @checkbox-size: 16px; 226 | @checkbox-color: @primary-color; 227 | @checkbox-check-color: #fff; 228 | @checkbox-check-bg: @checkbox-check-color; 229 | @checkbox-border-width: @border-width-base; 230 | @checkbox-group-item-margin-right: 8px; 231 | 232 | // Descriptions 233 | @descriptions-bg: #fafafa; 234 | @descriptions-title-margin-bottom: 20px; 235 | @descriptions-default-padding: @padding-md @padding-lg; 236 | @descriptions-middle-padding: @padding-sm @padding-lg; 237 | @descriptions-small-padding: @padding-xs @padding-md; 238 | @descriptions-item-padding-bottom: @padding-md; 239 | @descriptions-item-trailing-colon: true; 240 | @descriptions-item-label-colon-margin-right: 8px; 241 | @descriptions-item-label-colon-margin-left: 2px; 242 | @descriptions-extra-color: @text-color; 243 | 244 | // Divider 245 | @divider-text-padding: 1em; 246 | @divider-orientation-margin: 5%; 247 | @divider-color: rgba(0, 0, 0, 6%); 248 | 249 | // Dropdown 250 | @dropdown-selected-color: @primary-color; 251 | @dropdown-menu-submenu-disabled-bg: @component-background; 252 | 253 | // Empty 254 | @empty-font-size: @font-size-base; 255 | 256 | // Radio 257 | @radio-size: 16px; 258 | @radio-top: 0px; 259 | @radio-dot-color: @primary-color; 260 | @radio-dot-disabled-color: fade(@black, 20%); 261 | @radio-solid-checked-color: @component-background; 262 | 263 | // Radio buttons 264 | @radio-button-bg: @btn-default-bg; 265 | @radio-button-checked-bg: @btn-default-bg; 266 | @radio-button-color: @btn-default-color; 267 | @radio-button-hover-color: @primary-5; 268 | @radio-button-active-color: @primary-7; 269 | @radio-disabled-button-checked-bg: tint(@black, 90%); 270 | @radio-disabled-button-checked-color: @disabled-color; 271 | @radio-wrapper-margin-right: 8px; 272 | 273 | // Media queries breakpoints 274 | // Extra small screen / phone 275 | @screen-xs: 480px; 276 | @screen-xs-min: @screen-xs; 277 | 278 | // Small screen / tablet 279 | @screen-sm: 576px; 280 | @screen-sm-min: @screen-sm; 281 | 282 | // Medium screen / desktop 283 | @screen-md: 768px; 284 | @screen-md-min: @screen-md; 285 | 286 | // Large screen / wide desktop 287 | @screen-lg: 992px; 288 | @screen-lg-min: @screen-lg; 289 | 290 | // Extra large screen / full hd 291 | @screen-xl: 1200px; 292 | @screen-xl-min: @screen-xl; 293 | 294 | // Extra extra large screen / large desktop 295 | @screen-xxl: 1600px; 296 | @screen-xxl-min: @screen-xxl; 297 | 298 | // provide a maximum 299 | @screen-xs-max: (@screen-sm-min - 1px); 300 | @screen-sm-max: (@screen-md-min - 1px); 301 | @screen-md-max: (@screen-lg-min - 1px); 302 | @screen-lg-max: (@screen-xl-min - 1px); 303 | @screen-xl-max: (@screen-xxl-min - 1px); 304 | 305 | // Grid system 306 | @grid-columns: 24; 307 | 308 | // Layout 309 | @layout-body-background: #f0f2f5; 310 | @layout-header-background: #001529; 311 | @layout-header-height: 64px; 312 | @layout-header-padding: 0 50px; 313 | @layout-header-color: @text-color; 314 | @layout-footer-padding: 24px 50px; 315 | @layout-footer-background: @layout-body-background; 316 | @layout-sider-background: @layout-header-background; 317 | @layout-trigger-height: 48px; 318 | @layout-trigger-background: #002140; 319 | @layout-trigger-color: #fff; 320 | @layout-zero-trigger-width: 36px; 321 | @layout-zero-trigger-height: 42px; 322 | // Layout light theme 323 | @layout-sider-background-light: #fff; 324 | @layout-trigger-background-light: #fff; 325 | @layout-trigger-color-light: @text-color; 326 | 327 | // z-index list, order by `z-index` 328 | @zindex-badge: auto; 329 | @zindex-table-fixed: 2; 330 | @zindex-affix: 10; 331 | @zindex-back-top: 10; 332 | @zindex-picker-panel: 10; 333 | @zindex-popup-close: 10; 334 | @zindex-modal: 1000; 335 | @zindex-modal-mask: 1000; 336 | @zindex-message: 1010; 337 | @zindex-notification: 1010; 338 | @zindex-popover: 1030; 339 | @zindex-dropdown: 1050; 340 | @zindex-picker: 1050; 341 | @zindex-popoconfirm: 1060; 342 | @zindex-tooltip: 1070; 343 | @zindex-image: 1080; 344 | 345 | // Animation 346 | @animation-duration-slow: 0.3s; // Modal 347 | @animation-duration-base: 0.2s; 348 | @animation-duration-fast: 0.1s; // Tooltip 349 | 350 | //CollapsePanel 351 | @collapse-panel-border-radius: @border-radius-base; 352 | 353 | //Dropdown 354 | @dropdown-menu-bg: @component-background; 355 | @dropdown-vertical-padding: 5px; 356 | @dropdown-edge-child-vertical-padding: 4px; 357 | @dropdown-font-size: @font-size-base; 358 | @dropdown-line-height: 22px; 359 | 360 | // Form 361 | // --- 362 | @label-required-color: @highlight-color; 363 | @label-color: @heading-color; 364 | @form-warning-input-bg: @input-bg; 365 | @form-item-margin-bottom: 24px; 366 | @form-item-trailing-colon: true; 367 | @form-vertical-label-padding: 0 0 8px; 368 | @form-vertical-label-margin: 0; 369 | @form-item-label-font-size: @font-size-base; 370 | @form-item-label-height: @input-height-base; 371 | @form-item-label-colon-margin-right: 8px; 372 | @form-item-label-colon-margin-left: 2px; 373 | @form-error-input-bg: @input-bg; 374 | 375 | // Input 376 | // --- 377 | @input-height-base: @height-base; 378 | @input-height-lg: @height-lg; 379 | @input-height-sm: @height-sm; 380 | @input-padding-horizontal: @control-padding-horizontal - 1px; 381 | @input-padding-horizontal-base: @input-padding-horizontal; 382 | @input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; 383 | @input-padding-horizontal-lg: @input-padding-horizontal; 384 | @input-padding-vertical-base: max( 385 | round((@input-height-base - @font-size-base * @line-height-base) / 2 * 10) / 10 - 386 | @border-width-base, 387 | 3px 388 | ); 389 | @input-padding-vertical-sm: max( 390 | round((@input-height-sm - @font-size-base * @line-height-base) / 2 * 10) / 10 - @border-width-base, 391 | 0 392 | ); 393 | @input-padding-vertical-lg: ceil((@input-height-lg - @font-size-lg * @line-height-base) / 2 * 10) / 394 | 10 - @border-width-base; 395 | @input-placeholder-color: hsv(0, 0, 75%); 396 | @input-color: @text-color; 397 | @input-icon-color: @input-color; 398 | @input-border-color: @border-color-base; 399 | @input-bg: @component-background; 400 | @input-number-hover-border-color: @input-hover-border-color; 401 | @input-number-handler-active-bg: #f4f4f4; 402 | @input-number-handler-hover-bg: @primary-5; 403 | @input-number-handler-bg: @component-background; 404 | @input-number-handler-border-color: @border-color-base; 405 | @input-addon-bg: @background-color-light; 406 | @input-hover-border-color: @primary-5; 407 | @input-disabled-bg: @disabled-bg; 408 | @input-outline-offset: 0 0; 409 | @input-icon-hover-color: fade(@black, 85%); 410 | @input-disabled-color: @disabled-color; 411 | 412 | // Mentions 413 | // --- 414 | @mentions-dropdown-bg: @component-background; 415 | @mentions-dropdown-menu-item-hover-bg: @mentions-dropdown-bg; 416 | 417 | // Select 418 | // --- 419 | @select-border-color: @border-color-base; 420 | @select-item-selected-color: @text-color; 421 | @select-item-selected-font-weight: 600; 422 | @select-dropdown-bg: @component-background; 423 | @select-item-selected-bg: @primary-1; 424 | @select-item-active-bg: @item-hover-bg; 425 | @select-dropdown-vertical-padding: @dropdown-vertical-padding; 426 | @select-dropdown-font-size: @dropdown-font-size; 427 | @select-dropdown-line-height: @dropdown-line-height; 428 | @select-dropdown-height: 32px; 429 | @select-background: @component-background; 430 | @select-clear-background: @select-background; 431 | @select-selection-item-bg: @background-color-base; 432 | @select-selection-item-border-color: @border-color-split; 433 | @select-single-item-height-lg: 40px; 434 | @select-multiple-item-height: @input-height-base - @input-padding-vertical-base * 2; // Normal 24px 435 | @select-multiple-item-height-lg: 32px; 436 | @select-multiple-item-spacing-half: ceil(@input-padding-vertical-base / 2); 437 | @select-multiple-disabled-background: @input-disabled-bg; 438 | @select-multiple-item-disabled-color: #bfbfbf; 439 | @select-multiple-item-disabled-border-color: @select-border-color; 440 | 441 | // Cascader 442 | // --- 443 | @cascader-bg: @component-background; 444 | @cascader-item-selected-bg: @primary-1; 445 | @cascader-menu-bg: @component-background; 446 | @cascader-menu-border-color-split: @border-color-split; 447 | 448 | // Cascader 449 | // ---- 450 | @cascader-dropdown-vertical-padding: @dropdown-vertical-padding; 451 | @cascader-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding; 452 | @cascader-dropdown-font-size: @dropdown-font-size; 453 | @cascader-dropdown-line-height: @dropdown-line-height; 454 | 455 | // Anchor 456 | // --- 457 | @anchor-bg: @component-background; 458 | @anchor-border-color: @border-color-split; 459 | @anchor-link-top: 7px; 460 | @anchor-link-left: 16px; 461 | @anchor-link-padding: @anchor-link-top 0 @anchor-link-top @anchor-link-left; 462 | 463 | // Tooltip 464 | // --- 465 | // Tooltip max width 466 | @tooltip-max-width: 250px; 467 | // Tooltip text color 468 | @tooltip-color: #fff; 469 | // Tooltip background color 470 | @tooltip-bg: rgba(0, 0, 0, 0.75); 471 | // Tooltip arrow width 472 | @tooltip-arrow-width: 5px; 473 | // Tooltip distance with trigger 474 | @tooltip-distance: @tooltip-arrow-width - 1px + 4px; 475 | // Tooltip arrow color 476 | @tooltip-arrow-color: @tooltip-bg; 477 | 478 | // Popover 479 | // --- 480 | // Popover body background color 481 | @popover-bg: @component-background; 482 | // Popover text color 483 | @popover-color: @text-color; 484 | // Popover maximum width 485 | @popover-min-width: 177px; 486 | @popover-min-height: 32px; 487 | // Popover arrow width 488 | @popover-arrow-width: 6px; 489 | // Popover arrow color 490 | @popover-arrow-color: @popover-bg; 491 | // Popover outer arrow width 492 | // Popover outer arrow color 493 | @popover-arrow-outer-color: @popover-bg; 494 | // Popover distance with trigger 495 | @popover-distance: @popover-arrow-width + 4px; 496 | @popover-padding-horizontal: @padding-md; 497 | 498 | // Modal 499 | // -- 500 | @modal-header-padding-vertical: @padding-md; 501 | @modal-header-padding-horizontal: @padding-lg; 502 | @modal-body-padding: @padding-lg; 503 | @modal-header-bg: @component-background; 504 | @modal-header-padding: @modal-header-padding-vertical @modal-header-padding-horizontal; 505 | @modal-header-border-width: @border-width-base; 506 | @modal-header-border-style: @border-style-base; 507 | @modal-header-title-line-height: 22px; 508 | @modal-header-title-font-size: @font-size-lg; 509 | @modal-header-border-color-split: @border-color-split; 510 | @modal-header-close-size: 56px; 511 | @modal-content-bg: @component-background; 512 | @modal-heading-color: @heading-color; 513 | @modal-close-color: @text-color-secondary; 514 | @modal-footer-bg: transparent; 515 | @modal-footer-border-color-split: @border-color-split; 516 | @modal-footer-border-style: @border-style-base; 517 | @modal-footer-padding-vertical: 10px; 518 | @modal-footer-padding-horizontal: 16px; 519 | @modal-footer-border-width: @border-width-base; 520 | @modal-mask-bg: fade(@black, 45%); 521 | @modal-confirm-body-padding: 32px 32px 24px; 522 | 523 | // Progress 524 | // -- 525 | @progress-default-color: @processing-color; 526 | @progress-remaining-color: @background-color-base; 527 | @progress-text-color: @text-color; 528 | @progress-radius: 100px; 529 | @progress-steps-item-bg: #f3f3f3; 530 | @progress-text-font-size: 1em; 531 | @progress-circle-text-font-size: 1em; 532 | // Menu 533 | // --- 534 | @menu-inline-toplevel-item-height: 40px; 535 | @menu-item-height: 40px; 536 | @menu-item-group-height: @line-height-base; 537 | @menu-collapsed-width: 80px; 538 | @menu-bg: @component-background; 539 | @menu-popup-bg: @component-background; 540 | @menu-item-color: @text-color; 541 | @menu-highlight-color: @primary-color; 542 | @menu-highlight-danger-color: @error-color; 543 | @menu-item-active-bg: @primary-1; 544 | @menu-item-active-danger-bg: @red-1; 545 | @menu-item-active-border-width: 3px; 546 | @menu-item-group-title-color: @text-color-secondary; 547 | @menu-item-vertical-margin: 4px; 548 | @menu-item-font-size: @font-size-base; 549 | @menu-item-boundary-margin: 8px; 550 | @menu-item-padding: 0 20px; 551 | @menu-horizontal-line-height: 46px; 552 | @menu-icon-margin-right: 10px; 553 | @menu-icon-size: @menu-item-font-size; 554 | @menu-icon-size-lg: @font-size-lg; 555 | @menu-item-group-title-font-size: @menu-item-font-size; 556 | 557 | // dark theme 558 | @menu-dark-color: @text-color-secondary-dark; 559 | @menu-dark-danger-color: @error-color; 560 | @menu-dark-bg: @layout-header-background; 561 | @menu-dark-arrow-color: #fff; 562 | @menu-dark-submenu-bg: #000c17; 563 | @menu-dark-highlight-color: #fff; 564 | @menu-dark-item-active-bg: @primary-color; 565 | @menu-dark-item-active-danger-bg: @error-color; 566 | @menu-dark-selected-item-icon-color: @white; 567 | @menu-dark-selected-item-text-color: @white; 568 | @menu-dark-item-hover-bg: transparent; 569 | // Spin 570 | // --- 571 | @spin-dot-size-sm: 14px; 572 | @spin-dot-size: 20px; 573 | @spin-dot-size-lg: 32px; 574 | 575 | // Table 576 | // -- 577 | @table-bg: @component-background; 578 | @table-header-bg: @background-color-light; 579 | @table-header-color: @heading-color; 580 | @table-header-sort-bg: @background-color-base; 581 | @table-body-sort-bg: #fafafa; 582 | @table-row-hover-bg: @background-color-light; 583 | @table-selected-row-color: inherit; 584 | @table-selected-row-bg: @primary-1; 585 | @table-body-selected-sort-bg: @table-selected-row-bg; 586 | @table-selected-row-hover-bg: darken(@table-selected-row-bg, 2%); 587 | @table-expanded-row-bg: #fbfbfb; 588 | @table-padding-vertical: 16px; 589 | @table-padding-horizontal: 16px; 590 | @table-padding-vertical-md: @table-padding-vertical * 3 / 4; 591 | @table-padding-horizontal-md: @table-padding-horizontal / 2; 592 | @table-padding-vertical-sm: @table-padding-vertical / 2; 593 | @table-padding-horizontal-sm: @table-padding-horizontal / 2; 594 | @table-border-radius-base: @border-radius-base; 595 | @table-footer-bg: @background-color-light; 596 | @table-footer-color: @heading-color; 597 | @table-header-bg-sm: @table-header-bg; 598 | @table-font-size: @font-size-base; 599 | @table-font-size-md: @table-font-size; 600 | @table-font-size-sm: @table-font-size; 601 | // Sorter 602 | // Legacy: `table-header-sort-active-bg` is used for hover not real active 603 | @table-header-sort-active-bg: darken(@table-header-bg, 3%); 604 | // Filter 605 | @table-header-filter-active-bg: darken(@table-header-sort-active-bg, 5%); 606 | @table-filter-btns-bg: inherit; 607 | @table-filter-dropdown-bg: @component-background; 608 | @table-expand-icon-bg: @component-background; 609 | @table-selection-column-width: 60px; 610 | @table-selection-extra-right: 0; 611 | // Sticky 612 | @table-sticky-scroll-bar-bg: fade(#000, 35%); 613 | @table-sticky-scroll-bar-radius: 4px; 614 | 615 | // Tag 616 | // -- 617 | @tag-default-bg: @background-color-light; 618 | @tag-default-color: @text-color; 619 | @tag-font-size: @font-size-sm; 620 | @tag-line-height: 20px; 621 | 622 | // TimePicker 623 | // --- 624 | @picker-bg: @component-background; 625 | @picker-basic-cell-hover-color: @item-hover-bg; 626 | @picker-basic-cell-active-with-range-color: @primary-1; 627 | @picker-basic-cell-hover-with-range-color: lighten(@primary-color, 35%); 628 | @picker-basic-cell-disabled-bg: @disabled-bg; 629 | @picker-border-color: @border-color-split; 630 | @picker-date-hover-range-border-color: lighten(@primary-color, 20%); 631 | @picker-date-hover-range-color: @picker-basic-cell-hover-with-range-color; 632 | @picker-time-panel-cell-height: 28px; 633 | @picker-panel-cell-height: 24px; 634 | @picker-panel-cell-width: 36px; 635 | @picker-text-height: 40px; 636 | @picker-panel-without-time-cell-height: 66px; 637 | 638 | // Calendar 639 | // --- 640 | @calendar-bg: @component-background; 641 | @calendar-input-bg: @input-bg; 642 | @calendar-border-color: @border-color-inverse; 643 | @calendar-item-active-bg: @item-active-bg; 644 | @calendar-full-bg: @calendar-bg; 645 | @calendar-full-panel-bg: @calendar-full-bg; 646 | 647 | // Carousel 648 | // --- 649 | @carousel-dot-width: 16px; 650 | @carousel-dot-height: 3px; 651 | @carousel-dot-active-width: 24px; 652 | 653 | // Badge 654 | // --- 655 | @badge-height: 20px; 656 | @badge-height-sm: 14px; 657 | @badge-dot-size: 6px; 658 | @badge-font-size: @font-size-sm; 659 | @badge-font-size-sm: @font-size-sm; 660 | @badge-font-weight: normal; 661 | @badge-status-size: 6px; 662 | @badge-text-color: @component-background; 663 | @badge-color: @highlight-color; 664 | 665 | // Rate 666 | // --- 667 | @rate-star-color: @yellow-6; 668 | @rate-star-bg: @border-color-split; 669 | @rate-star-size: 20px; 670 | @rate-star-hover-scale: scale(1.1); 671 | 672 | // Card 673 | // --- 674 | @card-head-color: @heading-color; 675 | @card-head-background: transparent; 676 | @card-head-font-size: @font-size-lg; 677 | @card-head-font-size-sm: @font-size-base; 678 | @card-head-padding: 16px; 679 | @card-head-padding-sm: @card-head-padding / 2; 680 | @card-head-height: 48px; 681 | @card-head-height-sm: 36px; 682 | @card-inner-head-padding: 12px; 683 | @card-padding-base: 24px; 684 | @card-padding-base-sm: @card-padding-base / 2; 685 | @card-actions-background: @component-background; 686 | @card-actions-li-margin: 12px 0; 687 | @card-skeleton-bg: #cfd8dc; 688 | @card-background: @component-background; 689 | @card-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 690 | 0 5px 12px 4px rgba(0, 0, 0, 0.09); 691 | @card-radius: @border-radius-base; 692 | @card-head-tabs-margin-bottom: -17px; 693 | @card-head-extra-color: @text-color; 694 | 695 | // Comment 696 | // --- 697 | @comment-bg: inherit; 698 | @comment-padding-base: @padding-md 0; 699 | @comment-nest-indent: 44px; 700 | @comment-font-size-base: @font-size-base; 701 | @comment-font-size-sm: @font-size-sm; 702 | @comment-author-name-color: @text-color-secondary; 703 | @comment-author-time-color: #ccc; 704 | @comment-action-color: @text-color-secondary; 705 | @comment-action-hover-color: #595959; 706 | @comment-actions-margin-bottom: inherit; 707 | @comment-actions-margin-top: @margin-sm; 708 | @comment-content-detail-p-margin-bottom: inherit; 709 | 710 | // Tabs 711 | // --- 712 | @tabs-card-head-background: @background-color-light; 713 | @tabs-card-height: 40px; 714 | @tabs-card-active-color: @primary-color; 715 | @tabs-card-horizontal-padding: (@tabs-card-height - floor(@font-size-base * @line-height-base)) / 2 - 716 | @border-width-base @padding-md; 717 | @tabs-card-horizontal-padding-sm: 6px @padding-md; 718 | @tabs-card-horizontal-padding-lg: 7px @padding-md 6px; 719 | @tabs-title-font-size: @font-size-base; 720 | @tabs-title-font-size-lg: @font-size-lg; 721 | @tabs-title-font-size-sm: @font-size-base; 722 | @tabs-ink-bar-color: @primary-color; 723 | @tabs-bar-margin: 0 0 @margin-md 0; 724 | @tabs-horizontal-margin: 0 32px 0 0; 725 | @tabs-horizontal-margin-rtl: 0 0 0 32px; 726 | @tabs-horizontal-padding: @padding-sm 0; 727 | @tabs-horizontal-padding-lg: @padding-md 0; 728 | @tabs-horizontal-padding-sm: @padding-xs 0; 729 | @tabs-vertical-padding: @padding-xs @padding-lg; 730 | @tabs-vertical-margin: 0 0 @margin-md 0; 731 | @tabs-scrolling-size: 32px; 732 | @tabs-highlight-color: @primary-color; 733 | @tabs-hover-color: @primary-5; 734 | @tabs-active-color: @primary-7; 735 | @tabs-card-gutter: 2px; 736 | @tabs-card-tab-active-border-top: 2px solid transparent; 737 | 738 | // BackTop 739 | // --- 740 | @back-top-color: #fff; 741 | @back-top-bg: @text-color-secondary; 742 | @back-top-hover-bg: @text-color; 743 | 744 | // Avatar 745 | // --- 746 | @avatar-size-base: 32px; 747 | @avatar-size-lg: 40px; 748 | @avatar-size-sm: 24px; 749 | @avatar-font-size-base: 18px; 750 | @avatar-font-size-lg: 24px; 751 | @avatar-font-size-sm: 14px; 752 | @avatar-bg: #ccc; 753 | @avatar-color: #fff; 754 | @avatar-border-radius: @border-radius-base; 755 | @avatar-group-overlapping: -8px; 756 | @avatar-group-space: 3px; 757 | @avatar-group-border-color: #fff; 758 | 759 | // Switch 760 | // --- 761 | @switch-height: 22px; 762 | @switch-sm-height: 16px; 763 | @switch-min-width: 44px; 764 | @switch-sm-min-width: 28px; 765 | @switch-disabled-opacity: 0.4; 766 | @switch-color: @primary-color; 767 | @switch-bg: @component-background; 768 | @switch-shadow-color: fade(#00230b, 20%); 769 | @switch-padding: 2px; 770 | @switch-inner-margin-min: ceil(@switch-height * 0.3); 771 | @switch-inner-margin-max: ceil(@switch-height * 1.1); 772 | @switch-sm-inner-margin-min: ceil(@switch-sm-height * 0.3); 773 | @switch-sm-inner-margin-max: ceil(@switch-sm-height * 1.1); 774 | 775 | // Pagination 776 | // --- 777 | @pagination-item-bg: @component-background; 778 | @pagination-item-size: @height-base; 779 | @pagination-item-size-sm: 24px; 780 | @pagination-font-family: @font-family; 781 | @pagination-font-weight-active: 500; 782 | @pagination-item-bg-active: @component-background; 783 | @pagination-item-link-bg: @component-background; 784 | @pagination-item-disabled-color-active: @white; 785 | @pagination-item-disabled-bg-active: darken(@disabled-bg, 10%); 786 | @pagination-item-input-bg: @component-background; 787 | @pagination-mini-options-size-changer-top: 0px; 788 | 789 | // PageHeader 790 | // --- 791 | @page-header-padding: @padding-lg; 792 | @page-header-padding-vertical: @padding-md; 793 | @page-header-padding-breadcrumb: @padding-sm; 794 | @page-header-content-padding-vertical: @padding-sm; 795 | @page-header-back-color: #000; 796 | @page-header-ghost-bg: inherit; 797 | @page-header-heading-title: @heading-4-size; 798 | @page-header-heading-sub-title: 14px; 799 | @page-header-tabs-tab-font-size: 16px; 800 | 801 | // Breadcrumb 802 | // --- 803 | @breadcrumb-base-color: @text-color-secondary; 804 | @breadcrumb-last-item-color: @text-color; 805 | @breadcrumb-font-size: @font-size-base; 806 | @breadcrumb-icon-font-size: @font-size-base; 807 | @breadcrumb-link-color: @text-color-secondary; 808 | @breadcrumb-link-color-hover: @primary-5; 809 | @breadcrumb-separator-color: @text-color-secondary; 810 | @breadcrumb-separator-margin: 0 @padding-xs; 811 | 812 | // Slider 813 | // --- 814 | @slider-margin: 10px 6px 10px; 815 | @slider-rail-background-color: @background-color-base; 816 | @slider-rail-background-color-hover: #e1e1e1; 817 | @slider-track-background-color: @primary-3; 818 | @slider-track-background-color-hover: @primary-4; 819 | @slider-handle-border-width: 2px; 820 | @slider-handle-background-color: @component-background; 821 | @slider-handle-color: @primary-3; 822 | @slider-handle-color-hover: @primary-4; 823 | @slider-handle-color-focus: tint(@primary-color, 20%); 824 | @slider-handle-color-focus-shadow: fade(@primary-color, 12%); 825 | @slider-handle-color-tooltip-open: @primary-color; 826 | @slider-handle-size: 14px; 827 | @slider-handle-margin-top: -5px; 828 | @slider-handle-shadow: 0; 829 | @slider-dot-border-color: @border-color-split; 830 | @slider-dot-border-color-active: tint(@primary-color, 50%); 831 | @slider-disabled-color: @disabled-color; 832 | @slider-disabled-background-color: @component-background; 833 | 834 | // Tree 835 | // --- 836 | @tree-bg: @component-background; 837 | @tree-title-height: 24px; 838 | @tree-child-padding: 18px; 839 | @tree-directory-selected-color: #fff; 840 | @tree-directory-selected-bg: @primary-color; 841 | @tree-node-hover-bg: @item-hover-bg; 842 | @tree-node-selected-bg: @primary-2; 843 | 844 | // Collapse 845 | // --- 846 | @collapse-header-padding: @padding-sm @padding-md; 847 | @collapse-header-padding-extra: 40px; 848 | @collapse-header-bg: @background-color-light; 849 | @collapse-content-padding: @padding-md; 850 | @collapse-content-bg: @component-background; 851 | @collapse-header-arrow-left: 16px; 852 | 853 | // Skeleton 854 | // --- 855 | @skeleton-color: #f2f2f2; 856 | @skeleton-to-color: shade(@skeleton-color, 5%); 857 | @skeleton-paragraph-margin-top: 28px; 858 | @skeleton-paragraph-li-margin-top: @margin-md; 859 | @skeleton-paragraph-li-height: 16px; 860 | @skeleton-title-height: 16px; 861 | @skeleton-title-paragraph-margin-top: @margin-lg; 862 | 863 | // Transfer 864 | // --- 865 | @transfer-header-height: 40px; 866 | @transfer-item-height: @height-base; 867 | @transfer-disabled-bg: @disabled-bg; 868 | @transfer-list-height: 200px; 869 | @transfer-item-hover-bg: @item-hover-bg; 870 | @transfer-item-padding-vertical: 6px; 871 | @transfer-list-search-icon-top: 12px; 872 | 873 | // Message 874 | // --- 875 | @message-notice-content-padding: 10px 16px; 876 | @message-notice-content-bg: @component-background; 877 | // Motion 878 | // --- 879 | @wave-animation-width: 6px; 880 | 881 | // Alert 882 | // --- 883 | @alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; 884 | @alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; 885 | @alert-success-icon-color: @success-color; 886 | @alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; 887 | @alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; 888 | @alert-info-icon-color: @info-color; 889 | @alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; 890 | @alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; 891 | @alert-warning-icon-color: @warning-color; 892 | @alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; 893 | @alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; 894 | @alert-error-icon-color: @error-color; 895 | @alert-message-color: @heading-color; 896 | @alert-text-color: @text-color; 897 | @alert-close-color: @text-color-secondary; 898 | @alert-close-hover-color: @icon-color-hover; 899 | @alert-no-icon-padding-vertical: @padding-xs; 900 | @alert-with-description-no-icon-padding-vertical: @padding-md - 1px; 901 | @alert-with-description-padding-vertical: @padding-md - 1px; 902 | @alert-with-description-padding: @alert-with-description-padding-vertical 15px 903 | @alert-with-description-no-icon-padding-vertical @alert-with-description-icon-size * 2 + 904 | @alert-with-description-padding-vertical; 905 | @alert-icon-top: 8px + @font-size-base * @line-height-base / 2 - @font-size-base / 2; 906 | @alert-with-description-icon-size: 24px; 907 | @alert-with-description-icon-top: @alert-with-description-padding-vertical; 908 | 909 | // List 910 | // --- 911 | @list-header-background: transparent; 912 | @list-footer-background: transparent; 913 | @list-empty-text-padding: @padding-md; 914 | @list-item-padding: @padding-sm 0; 915 | @list-item-padding-sm: @padding-xs @padding-md; 916 | @list-item-padding-lg: 16px 24px; 917 | @list-item-meta-margin-bottom: @padding-md; 918 | @list-item-meta-avatar-margin-right: @padding-md; 919 | @list-item-meta-title-margin-bottom: @padding-sm; 920 | @list-customize-card-bg: @component-background; 921 | @list-item-meta-description-font-size: @font-size-base; 922 | 923 | // Statistic 924 | // --- 925 | @statistic-title-font-size: @font-size-base; 926 | @statistic-content-font-size: 24px; 927 | @statistic-unit-font-size: 16px; 928 | @statistic-font-family: @font-family; 929 | 930 | // Drawer 931 | // --- 932 | @drawer-header-padding: @padding-md @padding-lg; 933 | @drawer-body-padding: @padding-lg; 934 | @drawer-bg: @component-background; 935 | @drawer-footer-padding-vertical: @modal-footer-padding-vertical; 936 | @drawer-footer-padding-horizontal: @modal-footer-padding-horizontal; 937 | @drawer-header-close-size: 56px; 938 | 939 | // Timeline 940 | // --- 941 | @timeline-width: 2px; 942 | @timeline-color: @border-color-split; 943 | @timeline-dot-border-width: 2px; 944 | @timeline-dot-color: @primary-color; 945 | @timeline-dot-bg: @component-background; 946 | @timeline-item-padding-bottom: 20px; 947 | 948 | // Typography 949 | // --- 950 | @typography-title-font-weight: 600; 951 | @typography-title-margin-top: 1.2em; 952 | @typography-title-margin-bottom: 0.5em; 953 | 954 | // Upload 955 | // --- 956 | @upload-actions-color: @text-color-secondary; 957 | 958 | // Steps 959 | // --- 960 | @process-tail-color: @border-color-split; 961 | @steps-nav-arrow-color: fade(@black, 25%); 962 | @steps-background: @component-background; 963 | @steps-icon-size: 32px; 964 | @steps-icon-custom-size: @steps-icon-size; 965 | @steps-icon-custom-top: 0px; 966 | @steps-icon-custom-font-size: 24px; 967 | @steps-icon-top: -1px; 968 | @steps-icon-font-size: @font-size-lg; 969 | @steps-icon-margin: 0 8px 0 0; 970 | @steps-title-line-height: @height-base; 971 | @steps-small-icon-size: 24px; 972 | @steps-small-icon-margin: 0 8px 0 0; 973 | @steps-dot-size: 8px; 974 | @steps-dot-top: 2px; 975 | @steps-current-dot-size: 10px; 976 | @steps-desciption-max-width: 140px; 977 | @steps-nav-content-max-width: auto; 978 | @steps-vertical-icon-width: 16px; 979 | @steps-vertical-tail-width: 16px; 980 | @steps-vertical-tail-width-sm: 12px; 981 | 982 | // Notification 983 | // --- 984 | @notification-bg: @component-background; 985 | @notification-padding-vertical: 16px; 986 | @notification-padding-horizontal: 24px; 987 | 988 | // Result 989 | // --- 990 | @result-title-font-size: 24px; 991 | @result-subtitle-font-size: @font-size-base; 992 | @result-icon-font-size: 72px; 993 | @result-extra-margin: 24px 0 0 0; 994 | 995 | // Image 996 | // --- 997 | @image-size-base: 48px; 998 | @image-font-size-base: 24px; 999 | @image-bg: #f5f5f5; 1000 | @image-color: #fff; 1001 | @image-preview-operation-size: 18px; 1002 | @image-preview-operation-color: @text-color-dark; 1003 | @image-preview-operation-disabled-color: fade(@image-preview-operation-color, 45%); 1004 | 1005 | /* You can add global styles to this file, and also import other style files */ 1006 | --------------------------------------------------------------------------------