parent
22ff8baf33
commit
c1e9271609
@ -0,0 +1,17 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
@ -0,0 +1,34 @@
|
||||
_cli-tpl/
|
||||
dist/
|
||||
coverage/
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
.cache/
|
||||
|
||||
# yarn v2
|
||||
.yarn
|
@ -0,0 +1,126 @@
|
||||
const prettierConfig = require('./.prettierrc.js');
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: { ecmaVersion: 2021 },
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['tsconfig.json'],
|
||||
createDefaultProgram: true
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'jsdoc', 'import'],
|
||||
extends: [
|
||||
'plugin:@angular-eslint/recommended',
|
||||
'plugin:@angular-eslint/template/process-inline-templates',
|
||||
'plugin:prettier/recommended'
|
||||
],
|
||||
rules: {
|
||||
'prettier/prettier': ['error', prettierConfig],
|
||||
'jsdoc/newline-after-description': 1,
|
||||
'@angular-eslint/component-class-suffix': [
|
||||
'error',
|
||||
{
|
||||
suffixes: ['Directive', 'Component', 'Base', 'Widget']
|
||||
}
|
||||
],
|
||||
'@angular-eslint/directive-class-suffix': [
|
||||
'error',
|
||||
{
|
||||
suffixes: ['Directive', 'Component', 'Base', 'Widget']
|
||||
}
|
||||
],
|
||||
'@angular-eslint/component-selector': [
|
||||
'off',
|
||||
{
|
||||
type: ['element', 'attribute'],
|
||||
prefix: ['app', 'test'],
|
||||
style: 'kebab-case'
|
||||
}
|
||||
],
|
||||
'@angular-eslint/directive-selector': [
|
||||
'off',
|
||||
{
|
||||
type: 'attribute',
|
||||
prefix: ['app']
|
||||
}
|
||||
],
|
||||
'@angular-eslint/no-attribute-decorator': 'error',
|
||||
'@angular-eslint/no-conflicting-lifecycle': 'off',
|
||||
'@angular-eslint/no-forward-ref': 'off',
|
||||
'@angular-eslint/no-host-metadata-property': 'off',
|
||||
'@angular-eslint/no-lifecycle-call': 'off',
|
||||
'@angular-eslint/no-pipe-impure': 'error',
|
||||
'@angular-eslint/prefer-output-readonly': 'error',
|
||||
'@angular-eslint/use-component-selector': 'off',
|
||||
'@angular-eslint/use-component-view-encapsulation': 'off',
|
||||
'@angular-eslint/no-input-rename': 'off',
|
||||
'@angular-eslint/no-output-native': 'off',
|
||||
'@typescript-eslint/array-type': [
|
||||
'error',
|
||||
{
|
||||
default: 'array-simple'
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/ban-types': [
|
||||
'off',
|
||||
{
|
||||
types: {
|
||||
String: {
|
||||
message: 'Use string instead.'
|
||||
},
|
||||
Number: {
|
||||
message: 'Use number instead.'
|
||||
},
|
||||
Boolean: {
|
||||
message: 'Use boolean instead.'
|
||||
},
|
||||
Function: {
|
||||
message: 'Use specific callable interface instead.'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
'import/no-duplicates': 'error',
|
||||
'import/no-unused-modules': 'error',
|
||||
'import/no-unassigned-import': 'error',
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: { order: 'asc', caseInsensitive: false },
|
||||
'newlines-between': 'always',
|
||||
groups: ['external', 'internal', ['parent', 'sibling', 'index']],
|
||||
pathGroups: [],
|
||||
pathGroupsExcludedImportTypes: []
|
||||
}
|
||||
],
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
'@typescript-eslint/member-ordering': 'off',
|
||||
'no-irregular-whitespace': 'error',
|
||||
'no-multiple-empty-lines': 'error',
|
||||
'no-sparse-arrays': 'error',
|
||||
'prefer-object-spread': 'error',
|
||||
'prefer-template': 'error',
|
||||
'prefer-const': 'off',
|
||||
'max-len': 'off'
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['*.html'],
|
||||
extends: ['plugin:@angular-eslint/template/recommended'],
|
||||
rules: {}
|
||||
},
|
||||
{
|
||||
files: ['*.html'],
|
||||
excludedFiles: ['*inline-template-*.component.html'],
|
||||
extends: ['plugin:prettier/recommended'],
|
||||
rules: {
|
||||
'prettier/prettier': ['error', { parser: 'angular' }],
|
||||
'@angular-eslint/template/eqeqeq': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
@ -0,0 +1,45 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
export NODE_OPTIONS="--max-old-space-size=4096"
|
||||
npx --no-install tsc -p tsconfig.json --noEmit
|
||||
npx --no-install lint-staged
|
@ -0,0 +1 @@
|
||||
12.14.1
|
@ -0,0 +1,18 @@
|
||||
# add files you wish to ignore here
|
||||
**/*.md
|
||||
**/*.svg
|
||||
**/test.ts
|
||||
|
||||
.stylelintrc
|
||||
.prettierrc
|
||||
|
||||
src/assets/*
|
||||
src/index.html
|
||||
node_modules/
|
||||
.vscode/
|
||||
coverage/
|
||||
dist/
|
||||
package.json
|
||||
tslint.json
|
||||
|
||||
_cli-tpl/**/*
|
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
singleQuote: true,
|
||||
useTabs: false,
|
||||
printWidth: 140,
|
||||
tabWidth: 2,
|
||||
semi: true,
|
||||
htmlWhitespaceSensitivity: 'strict',
|
||||
arrowParens: 'avoid',
|
||||
bracketSpacing: true,
|
||||
proseWrap: 'preserve',
|
||||
trailingComma: 'none',
|
||||
endOfLine: 'lf'
|
||||
};
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"extends": [
|
||||
"stylelint-config-standard",
|
||||
"stylelint-config-rational-order",
|
||||
"stylelint-config-prettier"
|
||||
],
|
||||
"plugins": [
|
||||
"stylelint-order",
|
||||
"stylelint-declaration-block-no-ignored-properties"
|
||||
],
|
||||
"rules": {
|
||||
"no-descending-specificity": null,
|
||||
"plugin/declaration-block-no-ignored-properties": true,
|
||||
"selector-type-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignoreTypes": [
|
||||
"/^g2-/",
|
||||
"/^nz-/",
|
||||
"/^app-/"
|
||||
]
|
||||
}
|
||||
],
|
||||
"selector-pseudo-element-no-unknown": [
|
||||
true,
|
||||
{
|
||||
"ignorePseudoElements": [
|
||||
"ng-deep"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignoreFiles": [
|
||||
"src/assets/**/*"
|
||||
]
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"cipchk.ng-alain-extension-pack"
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:4200",
|
||||
"webRoot": "${workspaceRoot}",
|
||||
"sourceMaps": true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
{
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
// For ESLint
|
||||
"source.fixAll.eslint": true,
|
||||
// For Stylelint
|
||||
"source.fixAll.stylelint": true
|
||||
},
|
||||
"[markdown]": {
|
||||
"editor.formatOnSave": false
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": false
|
||||
},
|
||||
"[json]": {
|
||||
"editor.formatOnSave": false
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.formatOnSave": false
|
||||
},
|
||||
"files.watcherExclude": {
|
||||
"**/.git/*/**": true,
|
||||
"**/node_modules/*/**": true,
|
||||
"**/dist/*/**": true,
|
||||
"**/coverage/*/**": true
|
||||
},
|
||||
"files.associations": {
|
||||
"*.json": "jsonc",
|
||||
".prettierrc": "jsonc",
|
||||
".stylelintrc": "jsonc"
|
||||
},
|
||||
// Angular schematics 插件: https://marketplace.visualstudio.com/items?itemName=cyrilletuzi.angular-schematics
|
||||
"ngschematics.schematics": [
|
||||
"ng-alain"
|
||||
]
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-present 卡色<cipchk@qq.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -0,0 +1,90 @@
|
||||
<p align="center">
|
||||
<a href="https://ng-alain.com">
|
||||
<img width="100" src="https://ng-alain.com/assets/img/logo-color.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h1 align="center">NG-ALAIN</h1>
|
||||
|
||||
<div align="center">
|
||||
Out-of-box UI solution for enterprise applications, Let developers focus on business.
|
||||
|
||||
[![Build Status](https://dev.azure.com/ng-alain/ng-alain/_apis/build/status/ng-alain-CI?branchName=master)](https://dev.azure.com/ng-alain/ng-alain/_build/latest?definitionId=2&branchName=master)
|
||||
[![Dependency Status](https://david-dm.org/ng-alain/ng-alain/status.svg?style=flat-square)](https://david-dm.org/ng-alain/ng-alain)
|
||||
[![GitHub Release Date](https://img.shields.io/github/release-date/ng-alain/ng-alain.svg?style=flat-square)](https://github.com/ng-alain/ng-alain/releases)
|
||||
[![NPM version](https://img.shields.io/npm/v/ng-alain.svg?style=flat-square)](https://www.npmjs.com/package/ng-alain)
|
||||
[![prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://prettier.io/)
|
||||
[![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](https://github.com/ng-alain/ng-alain/blob/master/LICENSE)
|
||||
[![Gitter](https://img.shields.io/gitter/room/ng-alain/ng-alain.svg?style=flat-square)](https://gitter.im/ng-alain/ng-alain)
|
||||
[![ng-zorro-vscode](https://img.shields.io/badge/ng--zorro-VSCODE-brightgreen.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-zorro-vscode)
|
||||
[![ng-alain-vscode](https://img.shields.io/badge/ng--alain-VSCODE-brightgreen.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=cipchk.ng-alain-vscode)
|
||||
|
||||
</div>
|
||||
|
||||
English | [简体中文](README-zh_CN.md)
|
||||
|
||||
## Quickstart
|
||||
|
||||
- [Getting Started](https://ng-alain.com/docs/getting-started)
|
||||
|
||||
## Links
|
||||
|
||||
+ [Document](https://ng-alain.com) ([Surge Mirror](https://ng-alain-doc.surge.sh))
|
||||
+ [@delon Source](https://github.com/ng-alain/delon)
|
||||
+ [DEMO](https://ng-alain.surge.sh) ([国内镜像](https://ng-alain.gitee.io/))
|
||||
|
||||
## Features
|
||||
|
||||
+ `ng-zorro-antd` based
|
||||
+ Responsive Layout
|
||||
+ I18n
|
||||
+ [@delon](https://github.com/ng-alain/delon)
|
||||
+ Lazy load Assets
|
||||
+ UI Router States
|
||||
+ Customize Theme
|
||||
+ Less preprocessor
|
||||
+ RTL
|
||||
+ Well organized & commented code
|
||||
+ Simple upgrade
|
||||
+ Support Docker deploy
|
||||
|
||||
## Architecture
|
||||
|
||||
![Architecture](https://raw.githubusercontent.com/ng-alain/delon/master/_screenshot/architecture.png)
|
||||
|
||||
> [delon](https://github.com/ng-alain/delon) is a production-ready solution for admin business components packages, Built on the design principles developed by Ant Design.
|
||||
|
||||
## App Shots
|
||||
|
||||
![desktop](https://raw.githubusercontent.com/ng-alain/delon/master/_screenshot/desktop.png)
|
||||
![ipad](https://raw.githubusercontent.com/ng-alain/delon/master/_screenshot/ipad.png)
|
||||
![iphone](https://raw.githubusercontent.com/ng-alain/delon/master/_screenshot/iphone.png)
|
||||
|
||||
## Contributing
|
||||
|
||||
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/ng-alain/ng-alain/pulls)
|
||||
|
||||
We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ng-alain/ng-alain/blob/master/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ng-alain/ng-alain/pulls) or as [GitHub issues](https://github.com/ng-alain/ng-alain/issues).
|
||||
|
||||
> If you're new to posting issues, we ask that you read [*How To Ask Questions The Smart Way*](http://www.catb.org/~esr/faqs/smart-questions.html) (**This guide does not provide actual support services for this project!**), [How to Ask a Question in Open Source Community](https://github.com/seajs/seajs/issues/545) and [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) prior to posting. Well written bug reports help us help you!
|
||||
|
||||
## Donation
|
||||
|
||||
ng-alain is an MIT-licensed open source project. In order to achieve better and sustainable development of the project, we expect to gain more backers. You can support us in any of the following ways:
|
||||
|
||||
- [patreon](https://www.patreon.com/cipchk)
|
||||
- [opencollective](https://opencollective.com/ng-alain)
|
||||
- [paypal](https://www.paypal.me/cipchk)
|
||||
- [支付宝或微信](https://ng-alain.com/assets/donate.png)
|
||||
|
||||
Or purchasing our [business theme](https://e.ng-alain.com/).
|
||||
|
||||
## Backers
|
||||
|
||||
Thank you to all our backers! 🙏
|
||||
|
||||
<a href="https://opencollective.com/ng-alain#backers" target="_blank"><img src="https://opencollective.com/ng-alain/backers.svg?width=890"></a>
|
||||
|
||||
### License
|
||||
|
||||
The MIT License (see the [LICENSE](https://github.com/ng-alain/ng-alain/blob/master/LICENSE) file for the full text)
|
@ -0,0 +1 @@
|
||||
[Document](https://ng-alain.com/mock)
|
@ -0,0 +1 @@
|
||||
export * from './_user';
|
@ -0,0 +1,162 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"go-micro-dashboard": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"skipTests": false,
|
||||
"flat": false,
|
||||
"inlineStyle": true,
|
||||
"inlineTemplate": false,
|
||||
"style": "less"
|
||||
},
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
},
|
||||
"ng-alain:module": {
|
||||
"routing": true,
|
||||
"skipTests": false
|
||||
},
|
||||
"ng-alain:list": {
|
||||
"skipTests": false
|
||||
},
|
||||
"ng-alain:edit": {
|
||||
"skipTests": false,
|
||||
"modal": true
|
||||
},
|
||||
"ng-alain:view": {
|
||||
"skipTests": false,
|
||||
"modal": true
|
||||
},
|
||||
"ng-alain:curd": {
|
||||
"skipTests": false
|
||||
},
|
||||
"@schematics/angular:module": {
|
||||
"routing": true,
|
||||
"skipTests": false
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"skipTests": false
|
||||
},
|
||||
"@schematics/angular:service": {
|
||||
"skipTests": false
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/go-micro-dashboard",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "less",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.less"
|
||||
],
|
||||
"scripts": [],
|
||||
"allowedCommonJsDependencies": [
|
||||
"@antv/g2",
|
||||
"ajv",
|
||||
"ajv-formats",
|
||||
"date-fns",
|
||||
"file-saver"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "3mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "go-micro-dashboard:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "go-micro-dashboard:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"proxyConfig": "proxy.conf.json"
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "go-micro-dashboard:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "less",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.less"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "go-micro-dashboard"
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/go-micro-dashboard'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "./node_modules/ng-alain/schema.json",
|
||||
"theme": {
|
||||
"list": [
|
||||
{
|
||||
"theme": "dark"
|
||||
},
|
||||
{
|
||||
"theme": "compact"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,98 @@
|
||||
{
|
||||
"name": "go-micro-dashboard",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng s -o",
|
||||
"build": "npm run ng-high-memory build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"ng-high-memory": "node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng",
|
||||
"hmr": "ng s -o --hmr",
|
||||
"analyze": "npm run ng-high-memory build -- --source-map",
|
||||
"analyze:view": "source-map-explorer dist/**/*.js",
|
||||
"test-coverage": "ng test --code-coverage --watch=false",
|
||||
"color-less": "ng-alain-plugin-theme -t=colorLess",
|
||||
"theme": "ng-alain-plugin-theme -t=themeCss",
|
||||
"icon": "ng g ng-alain:plugin icon",
|
||||
"prepare": "husky install",
|
||||
"lint": "npm run lint:ts && npm run lint:style",
|
||||
"lint:ts": "ng lint --fix",
|
||||
"lint:style": "stylelint \"src/**/*.less\" --syntax less --fix"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.2.0",
|
||||
"@angular/common": "~12.2.0",
|
||||
"@angular/compiler": "~12.2.0",
|
||||
"@angular/core": "~12.2.0",
|
||||
"@angular/forms": "~12.2.0",
|
||||
"@angular/platform-browser": "~12.2.0",
|
||||
"@angular/platform-browser-dynamic": "~12.2.0",
|
||||
"@angular/router": "~12.2.0",
|
||||
"rxjs": "~6.6.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.11.4",
|
||||
"@delon/abc": "^12.3.0",
|
||||
"@delon/acl": "^12.3.0",
|
||||
"@delon/auth": "^12.3.0",
|
||||
"@delon/cache": "^12.3.0",
|
||||
"@delon/form": "^12.3.0",
|
||||
"@delon/mock": "^12.3.0",
|
||||
"@delon/theme": "^12.3.0",
|
||||
"@delon/util": "^12.3.0",
|
||||
"@delon/chart": "^12.3.0",
|
||||
"ajv": "^8.6.2",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"screenfull": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.2.12",
|
||||
"@angular/cli": "~12.2.12",
|
||||
"@angular/compiler-cli": "~12.2.0",
|
||||
"@types/jasmine": "~3.8.0",
|
||||
"@types/node": "^12.11.1",
|
||||
"jasmine-core": "~3.8.0",
|
||||
"karma": "~6.3.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "~1.7.0",
|
||||
"typescript": "~4.3.5",
|
||||
"@angular-eslint/builder": "~12.3.1",
|
||||
"@angular-eslint/eslint-plugin": "~12.3.1",
|
||||
"@angular-eslint/eslint-plugin-template": "~12.3.1",
|
||||
"@angular-eslint/schematics": "~12.3.1",
|
||||
"@angular-eslint/template-parser": "~12.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "~4.29.2",
|
||||
"@typescript-eslint/parser": "~4.29.2",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^2.2.1",
|
||||
"eslint-plugin-import": "~2.24.1",
|
||||
"eslint-plugin-jsdoc": "~36.0.7",
|
||||
"eslint-plugin-prefer-arrow": "~1.2.3",
|
||||
"eslint-plugin-prettier": "^2.2.1",
|
||||
"prettier": "^2.2.1",
|
||||
"husky": "^6.0.0",
|
||||
"ng-alain": "^12.3.0",
|
||||
"ng-alain-plugin-theme": "^12.0.0",
|
||||
"source-map-explorer": "^2.5.2",
|
||||
"@angular/language-service": "~12.2.0",
|
||||
"@delon/testing": "^12.3.0",
|
||||
"lint-staged": "^11.1.2",
|
||||
"stylelint": "^13.13.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-config-standard": "^22.0.0",
|
||||
"stylelint-declaration-block-no-ignored-properties": "^2.4.0",
|
||||
"stylelint-order": "^4.1.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"(src)/**/*.{html,ts}": [
|
||||
"eslint --fix"
|
||||
],
|
||||
"(src)/**/*.less": [
|
||||
"stylelint --syntax less --fix"
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Component, ElementRef, OnInit, Renderer2 } from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { TitleService, VERSION as VERSION_ALAIN } from '@delon/theme';
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
import { VERSION as VERSION_ZORRO } from 'ng-zorro-antd/version';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
template: ` <router-outlet></router-outlet> `
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
el: ElementRef,
|
||||
renderer: Renderer2,
|
||||
private router: Router,
|
||||
private titleSrv: TitleService,
|
||||
private modalSrv: NzModalService
|
||||
) {
|
||||
renderer.setAttribute(el.nativeElement, 'ng-alain-version', VERSION_ALAIN.full);
|
||||
renderer.setAttribute(el.nativeElement, 'ng-zorro-version', VERSION_ZORRO.full);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.router.events.pipe(filter(evt => evt instanceof NavigationEnd)).subscribe(() => {
|
||||
this.titleSrv.setTitle();
|
||||
this.modalSrv.closeAll();
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/* eslint-disable import/order */
|
||||
/* eslint-disable import/no-duplicates */
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, Injector, LOCALE_ID, NgModule, Type } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NzMessageModule } from 'ng-zorro-antd/message';
|
||||
import { NzNotificationModule } from 'ng-zorro-antd/notification';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
// #region default language
|
||||
// Reference: https://ng-alain.com/docs/i18n
|
||||
import { default as ngLang } from '@angular/common/locales/en';
|
||||
import { DELON_LOCALE, en_US as delonLang } from '@delon/theme';
|
||||
import { zhCN as dateLang } from 'date-fns/locale';
|
||||
import { NZ_DATE_LOCALE, NZ_I18N, en_US as zorroLang } from 'ng-zorro-antd/i18n';
|
||||
const LANG = {
|
||||
abbr: 'en',
|
||||
ng: ngLang,
|
||||
zorro: zorroLang,
|
||||
date: dateLang,
|
||||
delon: delonLang,
|
||||
};
|
||||
// register angular
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
registerLocaleData(LANG.ng, LANG.abbr);
|
||||
const LANG_PROVIDES = [
|
||||
{ provide: LOCALE_ID, useValue: LANG.abbr },
|
||||
{ provide: NZ_I18N, useValue: LANG.zorro },
|
||||
{ provide: NZ_DATE_LOCALE, useValue: LANG.date },
|
||||
{ provide: DELON_LOCALE, useValue: LANG.delon },
|
||||
];
|
||||
// #endregion
|
||||
|
||||
// #region JSON Schema form (using @delon/form)
|
||||
import { JsonSchemaModule } from '@shared';
|
||||
const FORM_MODULES = [ JsonSchemaModule ];
|
||||
// #endregion
|
||||
|
||||
|
||||
// #region Http Interceptors
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { DefaultInterceptor } from '@core';
|
||||
import { SimpleInterceptor } from '@delon/auth';
|
||||
const INTERCEPTOR_PROVIDES = [
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: SimpleInterceptor, multi: true},
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: DefaultInterceptor, multi: true}
|
||||
];
|
||||
// #endregion
|
||||
|
||||
// #region global third module
|
||||
const GLOBAL_THIRD_MODULES: Array<Type<void>> = [];
|
||||
// #endregion
|
||||
|
||||
// #region Startup Service
|
||||
import { StartupService } from '@core';
|
||||
export function StartupServiceFactory(startupService: StartupService): () => Observable<void> {
|
||||
return () => startupService.load();
|
||||
}
|
||||
const APPINIT_PROVIDES = [
|
||||
StartupService,
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: StartupServiceFactory,
|
||||
deps: [StartupService],
|
||||
multi: true
|
||||
}
|
||||
];
|
||||
// #endregion
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { GlobalConfigModule } from './global-config.module';
|
||||
import { LayoutModule } from './layout/layout.module';
|
||||
import { RoutesModule } from './routes/routes.module';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
import { STWidgetModule } from './shared/st-widget/st-widget.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
GlobalConfigModule.forRoot(),
|
||||
CoreModule,
|
||||
SharedModule,
|
||||
LayoutModule,
|
||||
RoutesModule,
|
||||
STWidgetModule,
|
||||
NzMessageModule,
|
||||
NzNotificationModule,
|
||||
...FORM_MODULES,
|
||||
...GLOBAL_THIRD_MODULES
|
||||
],
|
||||
providers: [
|
||||
...LANG_PROVIDES,
|
||||
...INTERCEPTOR_PROVIDES,
|
||||
...APPINIT_PROVIDES
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -0,0 +1,13 @@
|
||||
import { NgModule, Optional, SkipSelf } from '@angular/core';
|
||||
import { throwIfAlreadyLoaded } from './module-import-guard';
|
||||
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
]
|
||||
})
|
||||
export class CoreModule {
|
||||
constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
|
||||
throwIfAlreadyLoaded(parentModule, 'CoreModule');
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
|
||||
export * from './module-import-guard';
|
||||
export * from './net/default.interceptor';
|
||||
export * from './startup/startup.service';
|
@ -0,0 +1,6 @@
|
||||
// https://angular.io/guide/styleguide#style-04-12
|
||||
export function throwIfAlreadyLoaded(parentModule: any, moduleName: string): void {
|
||||
if (parentModule) {
|
||||
throw new Error(`${moduleName} has already been loaded. Import Core modules in the AppModule only.`);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
[Document](https://ng-alain.com/theme/default)
|
@ -0,0 +1,82 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { SettingsService, User } from '@delon/theme';
|
||||
import { LayoutDefaultOptions } from '@delon/theme/layout-default';
|
||||
import { environment } from '@env/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'layout-basic',
|
||||
template: `
|
||||
<layout-default [options]="options" [asideUser]="asideUserTpl" [content]="contentTpl">
|
||||
<layout-default-header-item direction="left">
|
||||
<a layout-default-header-item-trigger href="//github.com/ng-alain/ng-alain" target="_blank">
|
||||
<i nz-icon nzType="github"></i>
|
||||
</a>
|
||||
</layout-default-header-item>
|
||||
<layout-default-header-item direction="left" hidden="mobile">
|
||||
<a layout-default-header-item-trigger routerLink="/passport/lock">
|
||||
<i nz-icon nzType="lock"></i>
|
||||
</a>
|
||||
</layout-default-header-item>
|
||||
<layout-default-header-item direction="left" hidden="pc">
|
||||
<div layout-default-header-item-trigger (click)="searchToggleStatus = !searchToggleStatus">
|
||||
<i nz-icon nzType="search"></i>
|
||||
</div>
|
||||
</layout-default-header-item>
|
||||
<layout-default-header-item direction="middle">
|
||||
<header-search class="alain-default__search" [toggleChange]="searchToggleStatus"></header-search>
|
||||
</layout-default-header-item>
|
||||
<layout-default-header-item direction="right" hidden="mobile">
|
||||
<div layout-default-header-item-trigger nz-dropdown [nzDropdownMenu]="settingsMenu" nzTrigger="click" nzPlacement="bottomRight">
|
||||
<i nz-icon nzType="setting"></i>
|
||||
</div>
|
||||
<nz-dropdown-menu #settingsMenu="nzDropdownMenu">
|
||||
<div nz-menu style="width: 200px;">
|
||||
<div nz-menu-item>
|
||||
<header-fullscreen></header-fullscreen>
|
||||
</div>
|
||||
<div nz-menu-item>
|
||||
<header-clear-storage></header-clear-storage>
|
||||
</div>
|
||||
</div>
|
||||
</nz-dropdown-menu>
|
||||
</layout-default-header-item>
|
||||
<layout-default-header-item direction="right">
|
||||
<header-user></header-user>
|
||||
</layout-default-header-item>
|
||||
<ng-template #asideUserTpl>
|
||||
<div nz-dropdown nzTrigger="click" [nzDropdownMenu]="userMenu" class="alain-default__aside-user">
|
||||
<nz-avatar class="alain-default__aside-user-avatar" [nzSrc]="user.avatar"></nz-avatar>
|
||||
<div class="alain-default__aside-user-info">
|
||||
<strong>{{ user.name }}</strong>
|
||||
<p class="mb0">{{ user.email }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<nz-dropdown-menu #userMenu="nzDropdownMenu">
|
||||
<ul nz-menu>
|
||||
<li nz-menu-item routerLink="/pro/account/center">Account Center</li>
|
||||
<li nz-menu-item routerLink="/pro/account/settings">Account Settings</li>
|
||||
</ul>
|
||||
</nz-dropdown-menu>
|
||||
</ng-template>
|
||||
<ng-template #contentTpl>
|
||||
<router-outlet></router-outlet>
|
||||
</ng-template>
|
||||
</layout-default>
|
||||
|
||||
<setting-drawer *ngIf="showSettingDrawer"></setting-drawer>
|
||||
<theme-btn></theme-btn>
|
||||
`,
|
||||
})
|
||||
export class LayoutBasicComponent {
|
||||
options: LayoutDefaultOptions = {
|
||||
logoExpanded: `./assets/logo-full.svg`,
|
||||
logoCollapsed: `./assets/logo.svg`,
|
||||
};
|
||||
searchToggleStatus = false;
|
||||
showSettingDrawer = !environment.production;
|
||||
get user(): User {
|
||||
return this.settings.user;
|
||||
}
|
||||
|
||||
constructor(private settings: SettingsService) {}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
|
||||
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||
import { NzModalService } from 'ng-zorro-antd/modal';
|
||||
|
||||
@Component({
|
||||
selector: 'header-clear-storage',
|
||||
template: `
|
||||
<i nz-icon nzType="tool"></i>
|
||||
Clear Local Storage
|
||||
`,
|
||||
host: {
|
||||
'[class.d-block]': 'true'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderClearStorageComponent {
|
||||
constructor(private modalSrv: NzModalService, private messageSrv: NzMessageService) {}
|
||||
|
||||
@HostListener('click')
|
||||
_click(): void {
|
||||
this.modalSrv.confirm({
|
||||
nzTitle: 'Make sure clear all local storage?',
|
||||
nzOnOk: () => {
|
||||
localStorage.clear();
|
||||
this.messageSrv.success('Clear Finished!');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
|
||||
import * as screenfull from 'screenfull';
|
||||
|
||||
@Component({
|
||||
selector: 'header-fullscreen',
|
||||
template: `
|
||||
<i nz-icon [nzType]="status ? 'fullscreen-exit' : 'fullscreen'"></i>
|
||||
{{ status ? 'Exit Fullscreen' : 'Fullscreen' }}
|
||||
`,
|
||||
host: {
|
||||
'[class.d-block]': 'true'
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderFullScreenComponent {
|
||||
status = false;
|
||||
private get sf(): screenfull.Screenfull {
|
||||
return screenfull as screenfull.Screenfull;
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
_resize(): void {
|
||||
this.status = this.sf.isFullscreen;
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
_click(): void {
|
||||
if (this.sf.isEnabled) {
|
||||
this.sf.toggle();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectionStrategy,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnDestroy,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { debounceTime, distinctUntilChanged, tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'header-search',
|
||||
template: `
|
||||
<nz-input-group [nzPrefix]="iconTpl" [nzSuffix]="loadingTpl">
|
||||
<ng-template #iconTpl>
|
||||
<i nz-icon [nzType]="focus ? 'arrow-down' : 'search'"></i>
|
||||
</ng-template>
|
||||
<ng-template #loadingTpl>
|
||||
<i *ngIf="loading" nz-icon nzType="loading"></i>
|
||||
</ng-template>
|
||||
<input
|
||||
type="text"
|
||||
nz-input
|
||||
[(ngModel)]="q"
|
||||
[nzAutocomplete]="auto"
|
||||
(input)="search($event)"
|
||||
(focus)="qFocus()"
|
||||
(blur)="qBlur()"
|
||||
[attr.placeholder]="'Search for people, file, photos...'"
|
||||
/>
|
||||
</nz-input-group>
|
||||
<nz-autocomplete nzBackfill #auto>
|
||||
<nz-auto-option *ngFor="let i of options" [nzValue]="i">{{ i }}</nz-auto-option>
|
||||
</nz-autocomplete>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderSearchComponent implements AfterViewInit, OnDestroy {
|
||||
q = '';
|
||||
qIpt: HTMLInputElement | null = null;
|
||||
options: string[] = [];
|
||||
search$ = new BehaviorSubject('');
|
||||
loading = false;
|
||||
|
||||
@HostBinding('class.alain-default__search-focus')
|
||||
focus = false;
|
||||
@HostBinding('class.alain-default__search-toggled')
|
||||
searchToggled = false;
|
||||
|
||||
@Input()
|
||||
set toggleChange(value: boolean) {
|
||||
if (typeof value === 'undefined') {
|
||||
return;
|
||||
}
|
||||
this.searchToggled = value;
|
||||
this.focus = value;
|
||||
if (value) {
|
||||
setTimeout(() => this.qIpt!.focus());
|
||||
}
|
||||
}
|
||||
@Output() readonly toggleChangeChange = new EventEmitter<boolean>();
|
||||
|
||||
constructor(private el: ElementRef<HTMLElement>, private cdr: ChangeDetectorRef) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.qIpt = this.el.nativeElement.querySelector('.ant-input') as HTMLInputElement;
|
||||
this.search$
|
||||
.pipe(
|
||||
debounceTime(500),
|
||||
distinctUntilChanged(),
|
||||
tap({
|
||||
complete: () => {
|
||||
this.loading = true;
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe(value => {
|
||||
this.options = value ? [value, value + value, value + value + value] : [];
|
||||
this.loading = false;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
}
|
||||
|
||||
qFocus(): void {
|
||||
this.focus = true;
|
||||
}
|
||||
|
||||
qBlur(): void {
|
||||
this.focus = false;
|
||||
this.searchToggled = false;
|
||||
this.options.length = 0;
|
||||
this.toggleChangeChange.emit(false);
|
||||
}
|
||||
|
||||
search(ev: Event): void {
|
||||
this.search$.next((ev.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.search$.complete();
|
||||
this.search$.unsubscribe();
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
|
||||
import { SettingsService, User } from '@delon/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'header-user',
|
||||
template: `
|
||||
<div class="alain-default__nav-item d-flex align-items-center px-sm" nz-dropdown nzPlacement="bottomRight" [nzDropdownMenu]="userMenu">
|
||||
<nz-avatar [nzSrc]="user.avatar" nzSize="small" class="mr-sm"></nz-avatar>
|
||||
{{ user.name }}
|
||||
</div>
|
||||
<nz-dropdown-menu #userMenu="nzDropdownMenu">
|
||||
<div nz-menu class="width-sm">
|
||||
<div nz-menu-item routerLink="/pro/account/center">
|
||||
<i nz-icon nzType="user" class="mr-sm"></i>
|
||||
Account Center
|
||||
</div>
|
||||
<div nz-menu-item routerLink="/pro/account/settings">
|
||||
<i nz-icon nzType="setting" class="mr-sm"></i>
|
||||
Account Settings
|
||||
</div>
|
||||
<div nz-menu-item routerLink="/exception/trigger">
|
||||
<i nz-icon nzType="close-circle" class="mr-sm"></i>
|
||||
Trigger Error
|
||||
</div>
|
||||
<li nz-menu-divider></li>
|
||||
<div nz-menu-item (click)="logout()">
|
||||
<i nz-icon nzType="logout" class="mr-sm"></i>
|
||||
Logout
|
||||
</div>
|
||||
</div>
|
||||
</nz-dropdown-menu>
|
||||
`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class HeaderUserComponent {
|
||||
get user(): User {
|
||||
return this.settings.user;
|
||||
}
|
||||
|
||||
constructor(private settings: SettingsService, private router: Router, @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
|
||||
|
||||
logout(): void {
|
||||
this.tokenService.clear();
|
||||
this.router.navigateByUrl(this.tokenService.login_url!);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
[Document](https://ng-alain.com/theme/blank)
|
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'layout-blank',
|
||||
template: `<router-outlet></router-outlet> `,
|
||||
host: {
|
||||
'[class.alain-blank]': 'true'
|
||||
}
|
||||
})
|
||||
export class LayoutBlankComponent {}
|
@ -0,0 +1,66 @@
|
||||
/* eslint-disable import/order */
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { GlobalFooterModule } from '@delon/abc/global-footer';
|
||||
import { NoticeIconModule } from '@delon/abc/notice-icon';
|
||||
import { LayoutDefaultModule } from '@delon/theme/layout-default';
|
||||
import { SettingDrawerModule } from '@delon/theme/setting-drawer';
|
||||
import { ThemeBtnModule } from '@delon/theme/theme-btn';
|
||||
import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete';
|
||||
import { NzAvatarModule } from 'ng-zorro-antd/avatar';
|
||||
import { NzBadgeModule } from 'ng-zorro-antd/badge';
|
||||
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
|
||||
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||
import { NzGridModule } from 'ng-zorro-antd/grid';
|
||||
import { NzIconModule } from 'ng-zorro-antd/icon';
|
||||
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
||||
|
||||
import { LayoutBasicComponent } from './basic/basic.component';
|
||||
import { HeaderClearStorageComponent } from './basic/widgets/clear-storage.component';
|
||||
import { HeaderFullScreenComponent } from './basic/widgets/fullscreen.component';
|
||||
import { HeaderSearchComponent } from './basic/widgets/search.component';
|
||||
import { HeaderUserComponent } from './basic/widgets/user.component';
|
||||
import { LayoutBlankComponent } from './blank/blank.component';
|
||||
|
||||
const COMPONENTS = [LayoutBasicComponent, LayoutBlankComponent];
|
||||
|
||||
const HEADERCOMPONENTS = [
|
||||
HeaderSearchComponent,
|
||||
HeaderFullScreenComponent,
|
||||
HeaderClearStorageComponent,
|
||||
HeaderUserComponent,
|
||||
];
|
||||
|
||||
// passport
|
||||
import { LayoutPassportComponent } from './passport/passport.component';
|
||||
const PASSPORT = [
|
||||
LayoutPassportComponent
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
RouterModule,
|
||||
ThemeBtnModule,
|
||||
SettingDrawerModule,
|
||||
LayoutDefaultModule,
|
||||
NoticeIconModule,
|
||||
GlobalFooterModule,
|
||||
NzDropDownModule,
|
||||
NzInputModule,
|
||||
NzAutocompleteModule,
|
||||
NzGridModule,
|
||||
NzFormModule,
|
||||
NzSpinModule,
|
||||
NzBadgeModule,
|
||||
NzAvatarModule,
|
||||
NzIconModule,
|
||||
],
|
||||
declarations: [...COMPONENTS, ...HEADERCOMPONENTS, ...PASSPORT],
|
||||
exports: [...COMPONENTS, ...PASSPORT],
|
||||
})
|
||||
export class LayoutModule { }
|
@ -0,0 +1,17 @@
|
||||
<div class="container">
|
||||
<div class="wrap">
|
||||
<div class="top">
|
||||
<div class="head">
|
||||
<img class="logo" src="./assets/logo-color.svg">
|
||||
<span class="title">ng-alain</span>
|
||||
</div>
|
||||
<div class="desc">武林中最有影响力的《葵花宝典》;欲练神功,挥刀自宫</div>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
<global-footer [links]="links">
|
||||
Copyright
|
||||
<i class="anticon anticon-copyright"></i> 2021
|
||||
<a href="//github.com/cipchk" target="_blank">卡色</a>出品
|
||||
</global-footer>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,98 @@
|
||||
@import '~@delon/theme/index';
|
||||
:host ::ng-deep {
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
.langs {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
line-height: 44px;
|
||||
text-align: right;
|
||||
.anticon {
|
||||
margin-top: 24px;
|
||||
margin-right: 24px;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.wrap {
|
||||
flex: 1;
|
||||
padding: 32px 0;
|
||||
}
|
||||
.ant-form-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-md-min) {
|
||||
.container {
|
||||
background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center 110px;
|
||||
background-size: 100%;
|
||||
}
|
||||
.wrap {
|
||||
padding: 32px 0 24px;
|
||||
}
|
||||
}
|
||||
.top {
|
||||
text-align: center;
|
||||
}
|
||||
.header {
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
height: 44px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
.title {
|
||||
position: relative;
|
||||
color: @heading-color;
|
||||
font-weight: 600;
|
||||
font-size: 33px;
|
||||
font-family: 'Myriad Pro', 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.desc {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 40px;
|
||||
color: @text-color-secondary;
|
||||
font-size: @font-size-base;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
:host ::ng-deep {
|
||||
.container {
|
||||
background: #141414;
|
||||
}
|
||||
.title {
|
||||
color: fade(@white, 85%);
|
||||
}
|
||||
.desc {
|
||||
color: fade(@white, 45%);
|
||||
}
|
||||
@media (min-width: @screen-md-min) {
|
||||
.container {
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='compact'] {
|
||||
:host ::ng-deep {
|
||||
.ant-form-item {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
|
||||
|
||||
@Component({
|
||||
selector: 'layout-passport',
|
||||
templateUrl: './passport.component.html',
|
||||
styleUrls: ['./passport.component.less']
|
||||
})
|
||||
export class LayoutPassportComponent implements OnInit {
|
||||
links = [
|
||||
{
|
||||
title: '帮助',
|
||||
href: ''
|
||||
},
|
||||
{
|
||||
title: '隐私',
|
||||
href: ''
|
||||
},
|
||||
{
|
||||
title: '条款',
|
||||
href: ''
|
||||
}
|
||||
];
|
||||
|
||||
constructor(@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.tokenService.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
<page-header></page-header>
|
@ -0,0 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DashboardComponent {}
|
@ -0,0 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'exception-403',
|
||||
template: ` <exception type="403" style="min-height: 500px; height: 80%;"></exception> `
|
||||
})
|
||||
export class Exception403Component {}
|
@ -0,0 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'exception-404',
|
||||
template: ` <exception type="404" style="min-height: 500px; height: 80%;"></exception> `
|
||||
})
|
||||
export class Exception404Component {}
|
@ -0,0 +1,7 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'exception-500',
|
||||
template: ` <exception type="500" style="min-height: 500px; height: 80%;"></exception> `
|
||||
})
|
||||
export class Exception500Component {}
|
@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { Exception403Component } from './403.component';
|
||||
import { Exception404Component } from './404.component';
|
||||
import { Exception500Component } from './500.component';
|
||||
import { ExceptionTriggerComponent } from './trigger.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '403', component: Exception403Component },
|
||||
{ path: '404', component: Exception404Component },
|
||||
{ path: '500', component: Exception500Component },
|
||||
{ path: 'trigger', component: ExceptionTriggerComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class ExceptionRoutingModule {}
|
@ -0,0 +1,19 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ExceptionModule as DelonExceptionModule } from '@delon/abc/exception';
|
||||
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||
import { NzCardModule } from 'ng-zorro-antd/card';
|
||||
|
||||
import { Exception403Component } from './403.component';
|
||||
import { Exception404Component } from './404.component';
|
||||
import { Exception500Component } from './500.component';
|
||||
import { ExceptionRoutingModule } from './exception-routing.module';
|
||||
import { ExceptionTriggerComponent } from './trigger.component';
|
||||
|
||||
const COMPONENTS = [Exception403Component, Exception404Component, Exception500Component, ExceptionTriggerComponent];
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, DelonExceptionModule, NzButtonModule, NzCardModule, ExceptionRoutingModule],
|
||||
declarations: [...COMPONENTS]
|
||||
})
|
||||
export class ExceptionModule {}
|
@ -0,0 +1,35 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
|
||||
import { _HttpClient } from '@delon/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'exception-trigger',
|
||||
template: `
|
||||
<div class="pt-lg">
|
||||
<nz-card>
|
||||
<button *ngFor="let t of types" (click)="go(t)" nz-button nzDanger>触发{{ t }}</button>
|
||||
<button nz-button nzType="link" (click)="refresh()">触发刷新Token</button>
|
||||
</nz-card>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class ExceptionTriggerComponent {
|
||||
types = [401, 403, 404, 500];
|
||||
|
||||
constructor(private http: _HttpClient, @Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService) {}
|
||||
|
||||
go(type: number): void {
|
||||
this.http.get(`/api/${type}`).subscribe();
|
||||
}
|
||||
|
||||
refresh(): void {
|
||||
this.tokenService.set({ token: 'invalid-token' });
|
||||
// 必须提供一个后端地址,无法通过 Mock 来模拟
|
||||
this.http.post(`https://localhost:5001/auth`).subscribe(
|
||||
res => console.warn('成功', res),
|
||||
err => {
|
||||
console.log('最后结果失败', err);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { SocialService } from '@delon/auth';
|
||||
import { SettingsService } from '@delon/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'app-callback',
|
||||
template: ``,
|
||||
providers: [SocialService]
|
||||
})
|
||||
export class CallbackComponent implements OnInit {
|
||||
type = '';
|
||||
|
||||
constructor(private socialService: SocialService, private settingsSrv: SettingsService, private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.type = this.route.snapshot.params.type;
|
||||
this.mockModel();
|
||||
}
|
||||
|
||||
private mockModel(): void {
|
||||
const info = {
|
||||
token: '123456789',
|
||||
name: 'cipchk',
|
||||
email: `${this.type}@${this.type}.com`,
|
||||
id: 10000,
|
||||
time: +new Date()
|
||||
};
|
||||
this.settingsSrv.setUser({
|
||||
...this.settingsSrv.user,
|
||||
...info
|
||||
});
|
||||
this.socialService.callback(info);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<div class="ant-card width-lg" style="margin: 0 auto">
|
||||
<div class="ant-card-body">
|
||||
<div class="avatar">
|
||||
<nz-avatar [nzSrc]="user.avatar" nzIcon="user" nzSize="large"></nz-avatar>
|
||||
</div>
|
||||
<form nz-form [formGroup]="f" (ngSubmit)="submit()" role="form" class="mt-md">
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="'Please enter your password!'">
|
||||
<nz-input-group nzSuffixIcon="lock">
|
||||
<input type="password" nz-input formControlName="password" />
|
||||
</nz-input-group>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-row nzType="flex" nzAlign="middle">
|
||||
<nz-col [nzOffset]="12" [nzSpan]="12" style="text-align: right">
|
||||
<button nz-button [disabled]="!f.valid" nzType="primary">Lock</button>
|
||||
</nz-col>
|
||||
</nz-row>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,12 @@
|
||||
:host ::ng-deep {
|
||||
.ant-card-body {
|
||||
position: relative;
|
||||
margin-top: 80px;
|
||||
}
|
||||
.avatar {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { DA_SERVICE_TOKEN, ITokenService } from '@delon/auth';
|
||||
import { SettingsService, User } from '@delon/theme';
|
||||
|
||||
@Component({
|
||||
selector: 'passport-lock',
|
||||
templateUrl: './lock.component.html',
|
||||
styleUrls: ['./lock.component.less']
|
||||
})
|
||||
export class UserLockComponent {
|
||||
f: FormGroup;
|
||||
|
||||
get user(): User {
|
||||
return this.settings.user;
|
||||
}
|
||||
|
||||
constructor(
|
||||
fb: FormBuilder,
|
||||
@Inject(DA_SERVICE_TOKEN) private tokenService: ITokenService,
|
||||
private settings: SettingsService,
|
||||
private router: Router
|
||||
) {
|
||||
this.f = fb.group({
|
||||
password: [null, Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
for (const i in this.f.controls) {
|
||||
this.f.controls[i].markAsDirty();
|
||||
this.f.controls[i].updateValueAndValidity();
|
||||
}
|
||||
if (this.f.valid) {
|
||||
console.log('Valid!');
|
||||
console.log(this.f.value);
|
||||
this.tokenService.set({
|
||||
token: '123'
|
||||
});
|
||||
this.router.navigate(['dashboard']);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
<form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form">
|
||||
<nz-tabset [nzAnimated]="false" class="tabs" (nzSelectChange)="switch($event)">
|
||||
<nz-tab [nzTitle]="'Credentials'">
|
||||
<nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
|
||||
<nz-form-item>
|
||||
<nz-form-control nzErrorTip="Please enter mobile number, muse be: admin or user">
|
||||
<nz-input-group nzSize="large" nzPrefixIcon="user">
|
||||
<input nz-input formControlName="userName" placeholder="username: admin or user" />
|
||||
</nz-input-group>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control nzErrorTip="Please enter password, muse be: ng-alain.com">
|
||||
<nz-input-group nzSize="large" nzPrefixIcon="lock">
|
||||
<input nz-input type="password" formControlName="password" placeholder="password: ng-alain.com" />
|
||||
</nz-input-group>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</nz-tab>
|
||||
<nz-tab [nzTitle]="'Mobile number'">
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="mobileErrorTip">
|
||||
<nz-input-group nzSize="large" nzPrefixIcon="user">
|
||||
<input nz-input formControlName="mobile" placeholder="mobile number" />
|
||||
</nz-input-group>
|
||||
<ng-template #mobileErrorTip let-i>
|
||||
<ng-container *ngIf="i.errors.required">
|
||||
Please enter your phone number!
|
||||
</ng-container>
|
||||
<ng-container *ngIf="i.errors.pattern">
|
||||
Malformed phone number!
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="'Please enter the verification code!'">
|
||||
<nz-row [nzGutter]="8">
|
||||
<nz-col [nzSpan]="16">
|
||||
<nz-input-group nzSize="large" nzPrefixIcon="mail">
|
||||
<input nz-input formControlName="captcha" placeholder="captcha" />
|
||||
</nz-input-group>
|
||||
</nz-col>
|
||||
<nz-col [nzSpan]="8">
|
||||
<button type="button" nz-button nzSize="large" (click)="getCaptcha()" [disabled]="count >= 0" nzBlock [nzLoading]="loading">
|
||||
{{ count ? count + 's' : ('Get code') }}
|
||||
</button>
|
||||
</nz-col>
|
||||
</nz-row>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</nz-tab>
|
||||
</nz-tabset>
|
||||
<nz-form-item>
|
||||
<nz-col [nzSpan]="12">
|
||||
<label nz-checkbox formControlName="remember">Remember me</label>
|
||||
</nz-col>
|
||||
<nz-col [nzSpan]="12" class="text-right">
|
||||
<a class="forgot" routerLink="/passport/register">Forgot your password?</a>
|
||||
</nz-col>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<button nz-button type="submit" nzType="primary" nzSize="large" [nzLoading]="loading" nzBlock>
|
||||
Login
|
||||
</button>
|
||||
</nz-form-item>
|
||||
</form>
|
||||
<div class="other">
|
||||
Sign in with
|
||||
<i nz-tooltip nzTooltipTitle="in fact Auth0 via window" (click)="open('auth0', 'window')" nz-icon nzType="alipay-circle" class="icon"></i>
|
||||
<i nz-tooltip nzTooltipTitle="in fact Github via redirect" (click)="open('github')" nz-icon nzType="taobao-circle" class="icon"></i>
|
||||
<i (click)="open('weibo', 'window')" nz-icon nzType="weibo-circle" class="icon"></i>
|
||||
<a class="register" routerLink="/passport/register">Sign up</a>
|
||||
</div>
|
@ -0,0 +1,53 @@
|
||||
@import '~@delon/theme/index';
|
||||
:host {
|
||||
display: block;
|
||||
width: 368px;
|
||||
margin: 0 auto;
|
||||
::ng-deep {
|
||||
.ant-tabs .ant-tabs-bar {
|
||||
margin-bottom: 24px;
|
||||
text-align: center;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.ant-tabs-tab {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
.ant-input-affix-wrapper .ant-input:not(:first-child) {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.icon {
|
||||
margin-left: 16px;
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
font-size: 24px;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
&:hover {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.other {
|
||||
margin-top: 24px;
|
||||
line-height: 22px;
|
||||
text-align: left;
|
||||
nz-tooltip {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.register {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
:host ::ng-deep {
|
||||
.icon {
|
||||
color: rgba(255, 255, 255, 0.2);
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { NzMessageService } from 'ng-zorro-antd/message';
|
||||
|
||||
@Component({
|
||||
selector: 'passport-register-result',
|
||||
templateUrl: './register-result.component.html'
|
||||
})
|
||||
export class UserRegisterResultComponent {
|
||||
params = { email: '' };
|
||||
email = '';
|
||||
constructor(route: ActivatedRoute, public msg: NzMessageService) {
|
||||
this.params.email = this.email = route.snapshot.queryParams.email || 'ng-alain@example.com';
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
<h3>Register</h3>
|
||||
<form nz-form [formGroup]="form" (ngSubmit)="submit()" role="form">
|
||||
<nz-alert *ngIf="error" [nzType]="'error'" [nzMessage]="error" [nzShowIcon]="true" class="mb-lg"></nz-alert>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="mailErrorTip">
|
||||
<nz-input-group nzSize="large" nzAddonBeforeIcon="user">
|
||||
<input nz-input formControlName="mail" placeholder="Email" />
|
||||
</nz-input-group>
|
||||
<ng-template #mailErrorTip let-i>
|
||||
<ng-container *ngIf="i.errors?.required">Please enter your email!</ng-container>
|
||||
<ng-container *ngIf="i.errors?.email">The email address is in the wrong format!</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="'Please enter your password!'">
|
||||
<nz-input-group
|
||||
nzSize="large"
|
||||
nzAddonBeforeIcon="lock"
|
||||
nz-popover
|
||||
nzPopoverPlacement="right"
|
||||
nzPopoverTrigger="focus"
|
||||
[(nzPopoverVisible)]="visible"
|
||||
nzPopoverOverlayClassName="register-password-cdk"
|
||||
[nzPopoverOverlayStyle]="{ 'width.px': 240 }"
|
||||
[nzPopoverContent]="pwdCdkTpl"
|
||||
>
|
||||
<input nz-input type="password" formControlName="password" placeholder="Password" />
|
||||
</nz-input-group>
|
||||
<ng-template #pwdCdkTpl>
|
||||
<div style="padding: 4px 0">
|
||||
<ng-container [ngSwitch]="status">
|
||||
<div *ngSwitchCase="'ok'" class="success">Strength: strong</div>
|
||||
<div *ngSwitchCase="'pass'" class="warning">Strength: medium</div>
|
||||
<div *ngSwitchDefault class="error">Strength: too short</div>
|
||||
</ng-container>
|
||||
<div class="progress-{{ status }}">
|
||||
<nz-progress
|
||||
[nzPercent]="progress"
|
||||
[nzStatus]="passwordProgressMap[status]"
|
||||
[nzStrokeWidth]="6"
|
||||
[nzShowInfo]="false"
|
||||
></nz-progress>
|
||||
</div>
|
||||
<p class="mt-sm">Please enter at least 6 characters and don't use passwords that are easy to guess.</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="confirmErrorTip">
|
||||
<nz-input-group nzSize="large" nzAddonBeforeIcon="lock">
|
||||
<input nz-input type="password" formControlName="confirm" placeholder="Confirm Password" />
|
||||
</nz-input-group>
|
||||
<ng-template #confirmErrorTip let-i>
|
||||
<ng-container *ngIf="i.errors?.required">Please confirm your password!</ng-container>
|
||||
<ng-container *ngIf="i.errors?.matchControl">The passwords entered twice do not match!</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="mobileErrorTip">
|
||||
<nz-input-group nzSize="large" [nzAddOnBefore]="addOnBeforeTemplate">
|
||||
<ng-template #addOnBeforeTemplate>
|
||||
<nz-select formControlName="mobilePrefix" style="width: 100px">
|
||||
<nz-option [nzLabel]="'+86'" [nzValue]="'+86'"></nz-option>
|
||||
<nz-option [nzLabel]="'+87'" [nzValue]="'+87'"></nz-option>
|
||||
</nz-select>
|
||||
</ng-template>
|
||||
<input formControlName="mobile" nz-input placeholder="Phone number" />
|
||||
</nz-input-group>
|
||||
<ng-template #mobileErrorTip let-i>
|
||||
<ng-container *ngIf="i.errors?.required">Please enter your phone number!</ng-container>
|
||||
<ng-container *ngIf="i.errors?.pattern">Malformed phone number!</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="'Please enter the verification code!'">
|
||||
<nz-row [nzGutter]="8">
|
||||
<nz-col [nzSpan]="16">
|
||||
<nz-input-group nzSize="large" nzAddonBeforeIcon="mail">
|
||||
<input nz-input formControlName="captcha" placeholder="Captcha" />
|
||||
</nz-input-group>
|
||||
</nz-col>
|
||||
<nz-col [nzSpan]="8">
|
||||
<button type="button" nz-button nzSize="large" (click)="getCaptcha()" [disabled]="count > 0" nzBlock [nzLoading]="loading">
|
||||
{{ count ? count + 's' : ('Get code') }}
|
||||
</button>
|
||||
</nz-col>
|
||||
</nz-row>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item>
|
||||
<button nz-button nzType="primary" nzSize="large" type="submit" [nzLoading]="loading" class="submit">
|
||||
Register
|
||||
</button>
|
||||
<a class="login" routerLink="/passport/login">Already have an account?</a>
|
||||
</nz-form-item>
|
||||
</form>
|
@ -0,0 +1,42 @@
|
||||
@import '~@delon/theme/index';
|
||||
:host {
|
||||
display: block;
|
||||
width: 368px;
|
||||
margin: 0 auto;
|
||||
::ng-deep {
|
||||
h3 {
|
||||
margin-bottom: 20px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.submit {
|
||||
width: 50%;
|
||||
}
|
||||
.login {
|
||||
float: right;
|
||||
line-height: @btn-height-lg;
|
||||
}
|
||||
}
|
||||
}
|
||||
::ng-deep {
|
||||
.register-password-cdk {
|
||||
.success,
|
||||
.warning,
|
||||
.error {
|
||||
transition: color 0.3s;
|
||||
}
|
||||
.success {
|
||||
color: @success-color;
|
||||
}
|
||||
.warning {
|
||||
color: @warning-color;
|
||||
}
|
||||
.error {
|
||||
color: @error-color;
|
||||
}
|
||||
.progress-pass > .progress {
|
||||
.ant-progress-bg {
|
||||
background-color: @warning-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { _HttpClient } from '@delon/theme';
|
||||
import { MatchControl } from '@delon/util/form';
|
||||
import { NzSafeAny } from 'ng-zorro-antd/core/types';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'passport-register',
|
||||
templateUrl: './register.component.html',
|
||||
styleUrls: ['./register.component.less'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class UserRegisterComponent implements OnDestroy {
|
||||
constructor(fb: FormBuilder, private router: Router, private http: _HttpClient, private cdr: ChangeDetectorRef) {
|
||||
this.form = fb.group(
|
||||
{
|
||||
mail: [null, [Validators.required, Validators.email]],
|
||||
password: [null, [Validators.required, Validators.minLength(6), UserRegisterComponent.checkPassword.bind(this)]],
|
||||
confirm: [null, [Validators.required, Validators.minLength(6)]],
|
||||
mobilePrefix: ['+86'],
|
||||
mobile: [null, [Validators.required, Validators.pattern(/^1\d{10}$/)]],
|
||||
captcha: [null, [Validators.required]]
|
||||
},
|
||||
{
|
||||
validators: MatchControl('password', 'confirm')
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// #region fields
|
||||
|
||||
get mail(): AbstractControl {
|
||||
return this.form.controls.mail;
|
||||
}
|
||||
get password(): AbstractControl {
|
||||
return this.form.controls.password;
|
||||
}
|
||||
get confirm(): AbstractControl {
|
||||
return this.form.controls.confirm;
|
||||
}
|
||||
get mobile(): AbstractControl {
|
||||
return this.form.controls.mobile;
|
||||
}
|
||||
get captcha(): AbstractControl {
|
||||
return this.form.controls.captcha;
|
||||
}
|
||||
form: FormGroup;
|
||||
error = '';
|
||||
type = 0;
|
||||
loading = false;
|
||||
visible = false;
|
||||
status = 'pool';
|
||||
progress = 0;
|
||||
passwordProgressMap: { [key: string]: 'success' | 'normal' | 'exception' } = {
|
||||
ok: 'success',
|
||||
pass: 'normal',
|
||||
pool: 'exception'
|
||||
};
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region get captcha
|
||||
|
||||
count = 0;
|
||||
interval$: any;
|
||||
|
||||
static checkPassword(control: FormControl): NzSafeAny {
|
||||
if (!control) {
|
||||
return null;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const self: any = this;
|
||||
self.visible = !!control.value;
|
||||
if (control.value && control.value.length > 9) {
|
||||
self.status = 'ok';
|
||||
} else if (control.value && control.value.length > 5) {
|
||||
self.status = 'pass';
|
||||
} else {
|
||||
self.status = 'pool';
|
||||
}
|
||||
|
||||
if (self.visible) {
|
||||
self.progress = control.value.length * 10 > 100 ? 100 : control.value.length * 10;
|
||||
}
|
||||
}
|
||||
|
||||
getCaptcha(): void {
|
||||
if (this.mobile.invalid) {
|
||||
this.mobile.markAsDirty({ onlySelf: true });
|
||||
this.mobile.updateValueAndValidity({ onlySelf: true });
|
||||
return;
|
||||
}
|
||||
this.count = 59;
|
||||
this.cdr.detectChanges();
|
||||
this.interval$ = setInterval(() => {
|
||||
this.count -= 1;
|
||||
this.cdr.detectChanges();
|
||||
if (this.count <= 0) {
|
||||
clearInterval(this.interval$);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
submit(): void {
|
||||
this.error = '';
|
||||
Object.keys(this.form.controls).forEach(key => {
|
||||
this.form.controls[key].markAsDirty();
|
||||
this.form.controls[key].updateValueAndValidity();
|
||||
});
|
||||
if (this.form.invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = this.form.value;
|
||||
this.loading = true;
|
||||
this.cdr.detectChanges();
|
||||
this.http
|
||||
.post('/register?_allow_anonymous=true', data)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.loading = false;
|
||||
this.cdr.detectChanges();
|
||||
})
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.router.navigate(['passport', 'register-result'], { queryParams: { email: data.mail } });
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.interval$) {
|
||||
clearInterval(this.interval$);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { SimpleGuard } from '@delon/auth';
|
||||
import { environment } from '@env/environment';
|
||||
// layout
|
||||
import { LayoutBasicComponent } from '../layout/basic/basic.component';
|
||||
import { LayoutPassportComponent } from '../layout/passport/passport.component';
|
||||
// dashboard pages
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
// single pages
|
||||
import { CallbackComponent } from './passport/callback.component';
|
||||
import { UserLockComponent } from './passport/lock/lock.component';
|
||||
// passport pages
|
||||
import { UserLoginComponent } from './passport/login/login.component';
|
||||
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
|
||||
import { UserRegisterComponent } from './passport/register/register.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: LayoutBasicComponent,
|
||||
canActivate: [SimpleGuard],
|
||||
children: [
|
||||
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
|
||||
{ path: 'dashboard', component: DashboardComponent, data: { title: '仪表盘', titleI18n: 'dashboard' } },
|
||||
{ path: 'exception', loadChildren: () => import('./exception/exception.module').then(m => m.ExceptionModule) },
|
||||
// 业务子模块
|
||||
// { path: 'widgets', loadChildren: () => import('./widgets/widgets.module').then(m => m.WidgetsModule) },
|
||||
]
|
||||
},
|
||||
// 空白布局
|
||||
// {
|
||||
// path: 'blank',
|
||||
// component: LayoutBlankComponent,
|
||||
// children: [
|
||||
// ]
|
||||
// },
|
||||
// passport
|
||||
{
|
||||
path: 'passport',
|
||||
component: LayoutPassportComponent,
|
||||
children: [
|
||||
{ path: 'login', component: UserLoginComponent, data: { title: '登录', titleI18n: 'pro-login' } },
|
||||
{ path: 'register', component: UserRegisterComponent, data: { title: '注册', titleI18n: 'pro-register' } },
|
||||
{ path: 'register-result', component: UserRegisterResultComponent, data: { title: '注册结果', titleI18n: 'pro-register-result' } },
|
||||
{ path: 'lock', component: UserLockComponent, data: { title: '锁屏', titleI18n: 'lock' } },
|
||||
]
|
||||
},
|
||||
// 单页不包裹Layout
|
||||
{ path: 'passport/callback/:type', component: CallbackComponent },
|
||||
{ path: '**', redirectTo: 'exception/404' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forRoot(
|
||||
routes, {
|
||||
useHash: environment.useHash,
|
||||
// NOTICE: If you use `reuse-tab` component and turn on keepingScroll you can set to `disabled`
|
||||
// Pls refer to https://ng-alain.com/components/reuse-tab
|
||||
scrollPositionRestoration: 'top',
|
||||
}
|
||||
)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class RouteRoutingModule { }
|
@ -0,0 +1,29 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { SharedModule } from '@shared';
|
||||
// dashboard pages
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
// single pages
|
||||
import { CallbackComponent } from './passport/callback.component';
|
||||
import { UserLockComponent } from './passport/lock/lock.component';
|
||||
// passport pages
|
||||
import { UserLoginComponent } from './passport/login/login.component';
|
||||
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
|
||||
import { UserRegisterComponent } from './passport/register/register.component';
|
||||
import { RouteRoutingModule } from './routes-routing.module';
|
||||
|
||||
const COMPONENTS: Array<Type<void>> = [
|
||||
DashboardComponent,
|
||||
// passport pages
|
||||
UserLoginComponent,
|
||||
UserRegisterComponent,
|
||||
UserRegisterResultComponent,
|
||||
// single pages
|
||||
CallbackComponent,
|
||||
UserLockComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouteRoutingModule],
|
||||
declarations: COMPONENTS,
|
||||
})
|
||||
export class RoutesModule {}
|
@ -0,0 +1,8 @@
|
||||
// Components
|
||||
|
||||
// Utils
|
||||
export * from './utils/yuan';
|
||||
|
||||
// Module
|
||||
export * from './shared.module';
|
||||
export * from './json-schema/json-schema.module';
|
@ -0,0 +1,3 @@
|
||||
# 建议统一在 `widgets` 目录下自定义小部件
|
||||
|
||||
> 注:@delon/form 本身提供 nz-zorro-antd 数据录入组件的全部实现,以及若干第三方组件的代码,可从[widgets-third](https://github.com/ng-alain/delon/tree/master/packages/form/widgets-third)中获取并放置 `widgets` 目录下注册即可。
|
@ -0,0 +1,18 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DelonFormModule, WidgetRegistry } from '@delon/form';
|
||||
|
||||
import { SharedModule } from '../shared.module';
|
||||
import { TestWidget } from './test/test.widget';
|
||||
|
||||
export const SCHEMA_THIRDS_COMPONENTS = [TestWidget];
|
||||
|
||||
@NgModule({
|
||||
declarations: SCHEMA_THIRDS_COMPONENTS,
|
||||
imports: [SharedModule, DelonFormModule.forRoot()],
|
||||
exports: SCHEMA_THIRDS_COMPONENTS
|
||||
})
|
||||
export class JsonSchemaModule {
|
||||
constructor(widgetRegistry: WidgetRegistry) {
|
||||
widgetRegistry.register(TestWidget.KEY, TestWidget);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ControlWidget } from '@delon/form';
|
||||
|
||||
@Component({
|
||||
selector: 'test',
|
||||
template: `
|
||||
<sf-item-wrap [id]="id" [schema]="schema" [ui]="ui" [showError]="showError" [error]="error" [showTitle]="schema.title">
|
||||
test widget
|
||||
</sf-item-wrap>
|
||||
`,
|
||||
preserveWhitespaces: false,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class TestWidget extends ControlWidget implements OnInit {
|
||||
static readonly KEY = 'test';
|
||||
|
||||
ngOnInit(): void {
|
||||
console.warn('init test widget');
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import { PageHeaderModule } from '@delon/abc/page-header';
|
||||
import { ResultModule } from '@delon/abc/result';
|
||||
import { SEModule } from '@delon/abc/se';
|
||||
import { STModule } from '@delon/abc/st';
|
||||
import { SVModule } from '@delon/abc/sv';
|
||||
|
||||
export const SHARED_DELON_MODULES = [PageHeaderModule, STModule, SEModule, SVModule, ResultModule];
|
@ -0,0 +1,45 @@
|
||||
import { NzAlertModule } from 'ng-zorro-antd/alert';
|
||||
import { NzAvatarModule } from 'ng-zorro-antd/avatar';
|
||||
import { NzButtonModule } from 'ng-zorro-antd/button';
|
||||
import { NzCardModule } from 'ng-zorro-antd/card';
|
||||
import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
|
||||
import { NzDrawerModule } from 'ng-zorro-antd/drawer';
|
||||
import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
|
||||
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||
import { NzGridModule } from 'ng-zorro-antd/grid';
|
||||
import { NzIconModule } from 'ng-zorro-antd/icon';
|
||||
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||
import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
|
||||
import { NzModalModule } from 'ng-zorro-antd/modal';
|
||||
import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
|
||||
import { NzPopoverModule } from 'ng-zorro-antd/popover';
|
||||
import { NzProgressModule } from 'ng-zorro-antd/progress';
|
||||
import { NzSelectModule } from 'ng-zorro-antd/select';
|
||||
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
||||
import { NzTableModule } from 'ng-zorro-antd/table';
|
||||
import { NzTabsModule } from 'ng-zorro-antd/tabs';
|
||||
import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
|
||||
|
||||
export const SHARED_ZORRO_MODULES = [
|
||||
NzFormModule,
|
||||
NzGridModule,
|
||||
NzButtonModule,
|
||||
NzInputModule,
|
||||
NzInputNumberModule,
|
||||
NzAlertModule,
|
||||
NzProgressModule,
|
||||
NzSelectModule,
|
||||
NzAvatarModule,
|
||||
NzCardModule,
|
||||
NzDropDownModule,
|
||||
NzPopconfirmModule,
|
||||
NzTableModule,
|
||||
NzPopoverModule,
|
||||
NzDrawerModule,
|
||||
NzModalModule,
|
||||
NzTabsModule,
|
||||
NzToolTipModule,
|
||||
NzIconModule,
|
||||
NzCheckboxModule,
|
||||
NzSpinModule,
|
||||
];
|
@ -0,0 +1,61 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AlainThemeModule } from '@delon/theme';
|
||||
import { DelonACLModule } from '@delon/acl';
|
||||
import { DelonFormModule } from '@delon/form';
|
||||
|
||||
import { SHARED_DELON_MODULES } from './shared-delon.module';
|
||||
import { SHARED_ZORRO_MODULES } from './shared-zorro.module';
|
||||
|
||||
// #region third libs
|
||||
|
||||
const THIRDMODULES: Array<Type<void>> = [];
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region your componets & directives
|
||||
|
||||
const COMPONENTS: Array<Type<void>> = [];
|
||||
const DIRECTIVES: Array<Type<void>> = [];
|
||||
|
||||
// #endregion
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
RouterModule,
|
||||
ReactiveFormsModule,
|
||||
AlainThemeModule.forChild(),
|
||||
DelonACLModule,
|
||||
DelonFormModule,
|
||||
...SHARED_DELON_MODULES,
|
||||
...SHARED_ZORRO_MODULES,
|
||||
// third libs
|
||||
...THIRDMODULES
|
||||
],
|
||||
declarations: [
|
||||
// your components
|
||||
...COMPONENTS,
|
||||
...DIRECTIVES
|
||||
],
|
||||
exports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule,
|
||||
AlainThemeModule,
|
||||
DelonACLModule,
|
||||
DelonFormModule,
|
||||
...SHARED_DELON_MODULES,
|
||||
...SHARED_ZORRO_MODULES,
|
||||
// third libs
|
||||
...THIRDMODULES,
|
||||
// your components
|
||||
...COMPONENTS,
|
||||
...DIRECTIVES
|
||||
]
|
||||
})
|
||||
export class SharedModule { }
|
@ -0,0 +1,17 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
// import { STWidgetRegistry } from '@delon/abc/st';
|
||||
import { SharedModule } from '../shared.module';
|
||||
|
||||
export const STWIDGET_COMPONENTS = [];
|
||||
|
||||
@NgModule({
|
||||
declarations: STWIDGET_COMPONENTS,
|
||||
imports: [SharedModule],
|
||||
exports: [...STWIDGET_COMPONENTS]
|
||||
})
|
||||
export class STWidgetModule {
|
||||
// constructor(widgetRegistry: STWidgetRegistry) {
|
||||
// widgetRegistry.register(STImgWidget.KEY, STImgWidget);
|
||||
// }
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0px" y="0px" width="222px" height="222px" viewBox="-4.092 0 222 222" enable-background="new -4.092 0 222 222"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#F0776F" d="M195.333,129.506c-0.446,0-0.893,0-1.488-0.148c-6.399-0.744-11.013-6.548-10.269-12.947l6.994-57.891
|
||||
c0.447-3.721-1.785-7.293-5.208-8.483l-47.176-16.816c-6.103-2.232-9.228-8.78-7.144-14.882c2.232-6.102,8.78-9.227,14.882-7.144
|
||||
l47.176,16.816c13.989,4.911,22.472,18.603,20.687,33.336l-6.995,57.891C206.197,125.042,201.137,129.506,195.333,129.506z"/>
|
||||
<path fill="#F0776F" d="M104.851,222.222c-5.209,0-10.417-1.34-15.329-4.019l-61.016-33.931
|
||||
c-8.781-4.911-14.733-13.691-15.924-23.663L0.23,60.007c-1.786-14.733,6.995-28.723,20.983-33.634L96.665,0.627
|
||||
c6.102-2.083,12.799,1.19,14.882,7.292c2.084,6.103-1.19,12.799-7.292,14.883L28.803,48.547c-3.572,1.191-5.804,4.763-5.357,8.632
|
||||
l12.352,100.603c0.298,2.53,1.786,4.762,4.018,6.102l61.016,33.931c2.381,1.34,5.358,1.34,7.739,0l66.076-36.163
|
||||
c2.232-1.19,3.87-3.571,4.167-6.102c0.744-6.399,6.549-11.013,12.948-10.269c6.398,0.744,11.012,6.548,10.269,12.947
|
||||
c-1.191,9.971-7.293,18.9-16.073,23.812l-66.076,36.163C115.268,220.882,110.059,222.222,104.851,222.222z"/>
|
||||
<path fill="#F0776F" d="M157.086,131.441l-37.8-68.309l-0.149-0.149c-2.679-4.613-7.738-7.59-13.096-7.59s-10.417,2.977-13.096,7.59
|
||||
l-37.8,68.458c-2.828,5.208-1.042,11.607,4.167,14.436c5.208,2.827,11.608,1.041,14.436-4.167l7.292-13.245h50.004l7.292,13.245
|
||||
c1.935,3.571,5.506,5.506,9.376,5.506c1.785,0,3.571-0.446,5.06-1.339C157.979,143.049,159.914,136.501,157.086,131.441z
|
||||
M92.796,107.183l13.245-23.96l13.245,23.96H92.796z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0px" y="0px" width="552px" height="222px" viewBox="-4.092 0 552 222" enable-background="new -4.092 0 552 222"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#FFFFFF" d="M195.333,129.506c-0.446,0-0.893,0-1.488-0.148c-6.399-0.744-11.013-6.548-10.269-12.947l6.994-57.891
|
||||
c0.447-3.721-1.785-7.293-5.208-8.483l-47.176-16.816c-6.103-2.232-9.228-8.78-7.144-14.882c2.232-6.102,8.78-9.227,14.882-7.144
|
||||
l47.176,16.816c13.989,4.911,22.472,18.603,20.687,33.336l-6.995,57.891C206.197,125.042,201.137,129.506,195.333,129.506z"/>
|
||||
<path fill="#FFFFFF" d="M104.851,222.222c-5.209,0-10.417-1.34-15.329-4.019l-61.016-33.931
|
||||
c-8.781-4.911-14.733-13.691-15.924-23.663L0.23,60.007c-1.786-14.733,6.995-28.723,20.983-33.634L96.665,0.627
|
||||
c6.102-2.083,12.799,1.19,14.882,7.292c2.084,6.103-1.19,12.799-7.292,14.883L28.803,48.547c-3.572,1.191-5.804,4.763-5.357,8.632
|
||||
l12.352,100.603c0.298,2.53,1.786,4.762,4.018,6.102l61.016,33.931c2.381,1.34,5.358,1.34,7.739,0l66.076-36.163
|
||||
c2.232-1.19,3.87-3.571,4.167-6.102c0.744-6.399,6.549-11.013,12.948-10.269c6.398,0.744,11.012,6.548,10.269,12.947
|
||||
c-1.191,9.971-7.293,18.9-16.073,23.812l-66.076,36.163C115.268,220.882,110.059,222.222,104.851,222.222z"/>
|
||||
<path fill="#FFFFFF" d="M157.086,131.441l-37.8-68.309l-0.149-0.149c-2.679-4.613-7.738-7.59-13.096-7.59s-10.417,2.977-13.096,7.59
|
||||
l-37.8,68.458c-2.828,5.208-1.042,11.607,4.167,14.436c5.208,2.827,11.608,1.041,14.436-4.167l7.292-13.245h50.004l7.292,13.245
|
||||
c1.935,3.571,5.506,5.506,9.376,5.506c1.785,0,3.571-0.446,5.06-1.339C157.979,143.049,159.914,136.501,157.086,131.441z
|
||||
M92.796,107.183l13.245-23.96l13.245,23.96H92.796z"/>
|
||||
<path fill="#FFFFFF" d="M252.497,113.075c17.46-47.694,32.79-79.42,47.481-97.305c6.813,1.277,21.506,9.794,23.848,13.414
|
||||
c-22.144,26.189-38.113,54.934-52.166,93.898c-11.923,33.216-18.311,60.896-18.311,78.78c0,4.897,0,5.11,0.213,6.175
|
||||
c-3.833-0.426-7.026-2.129-7.878-4.045c-0.64-1.491-3.833-4.897-5.75-6.175c-2.555-1.703-4.471-9.795-4.471-18.95
|
||||
C235.464,166.518,241.639,142.884,252.497,113.075z"/>
|
||||
<path fill="#FFFFFF" d="M374.289,113.926c-11.498,23.847-19.376,48.972-19.376,63.451c0,7.878,1.704,13.414,5.536,15.543
|
||||
c-3.406,2.129-9.581,3.833-13.84,3.833c-7.665,0-11.498-5.11-11.498-15.757c0-7.878,2.769-19.376,8.092-33.216
|
||||
c-11.498,25.977-30.235,47.269-43.437,49.398c-10.433-0.426-17.672-11.072-17.672-25.764c0-31.726,30.66-75.161,53.655-76.439
|
||||
c5.749,1.491,15.331,11.498,15.97,16.821c-22.783,3.62-50.676,41.307-50.676,67.496c0,2.981,1.065,4.472,2.981,5.11
|
||||
c8.304-1.703,18.524-13.627,33.854-39.178c5.962-10.007,14.479-25.977,20.653-38.751
|
||||
C364.495,106.474,374.502,111.158,374.289,113.926z"/>
|
||||
<path fill="#FFFFFF" d="M391.749,137.773c1.277-5.536,7.452-27.68,20.228-34.067c4.685,1.064,14.266,5.749,19.802,14.053
|
||||
c-12.988,14.479-16.82,29.596-24.061,48.333c-2.98,7.878-6.174,17.034-6.387,23.209c0,5.109,0,7.026-1.278,7.026
|
||||
c-2.129,0-15.543-5.536-15.543-18.099C384.51,173.331,386.213,163.324,391.749,137.773z M425.816,81.988
|
||||
c-1.49-1.491-2.555-4.685-2.555-7.026c0-4.897,2.98-18.737,6.601-27.893c6.601,0,21.505,8.517,25.764,14.905
|
||||
c-6.388,5.961-21.932,24.912-24.061,29.596c-3.407-0.639-6.388-3.407-6.388-5.749C425.178,84.969,425.391,83.691,425.816,81.988z"/>
|
||||
<path fill="#FFFFFF" d="M486.712,109.668c-6.388,15.543-28.745,45.778-30.448,58.766c8.943-9.581,23.422-27.467,28.318-32.576
|
||||
c10.859-11.498,30.874-32.577,44.714-32.577c7.239,0,12.35,6.175,15.117,11.498c0,0.639-2.342,0.852-6.175,5.323
|
||||
c-7.665,10.007-22.144,38.113-22.144,55.573c0,7.026,1.916,8.304,5.323,8.304c2.98,0,7.026-2.13,8.942-2.13
|
||||
c1.064,0.64,1.916,2.981,1.916,4.259c-4.258,3.833-13.414,8.729-18.311,8.729c-16.396,0-20.228-10.007-20.228-22.569
|
||||
c0-7.026,1.916-15.756,11.71-38.326c-0.639,0-8.942,4.046-17.246,12.137c-13.201,12.775-23.209,24.486-34.28,39.816
|
||||
c-6.175,8.729-10.859,15.33-14.266,17.247c-5.962-3.407-8.517-10.221-9.795-16.608c0-10.646,6.388-34.493,15.97-56.424
|
||||
c10.858-24.912,20.866-39.816,23.208-40.881C476.491,91.569,483.73,100.299,486.712,109.668z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 4.3 KiB |
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
|
||||
<!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
|
||||
]>
|
||||
<svg version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
|
||||
x="0px" y="0px" width="222px" height="222px" viewBox="-4.092 0 222 222" enable-background="new -4.092 0 222 222"
|
||||
xml:space="preserve">
|
||||
<defs>
|
||||
</defs>
|
||||
<path fill="#FFFFFF" d="M195.333,129.506c-0.446,0-0.893,0-1.488-0.148c-6.399-0.744-11.013-6.548-10.269-12.947l6.994-57.891
|
||||
c0.447-3.721-1.785-7.293-5.208-8.483l-47.176-16.816c-6.103-2.232-9.228-8.78-7.144-14.882c2.232-6.102,8.78-9.227,14.882-7.144
|
||||
l47.176,16.816c13.989,4.911,22.472,18.603,20.687,33.336l-6.995,57.891C206.197,125.042,201.137,129.506,195.333,129.506z"/>
|
||||
<path fill="#FFFFFF" d="M104.851,222.222c-5.209,0-10.417-1.34-15.329-4.019l-61.016-33.931
|
||||
c-8.781-4.911-14.733-13.691-15.924-23.663L0.23,60.007c-1.786-14.733,6.995-28.723,20.983-33.634L96.665,0.627
|
||||
c6.102-2.083,12.799,1.19,14.882,7.292c2.084,6.103-1.19,12.799-7.292,14.883L28.803,48.547c-3.572,1.191-5.804,4.763-5.357,8.632
|
||||
l12.352,100.603c0.298,2.53,1.786,4.762,4.018,6.102l61.016,33.931c2.381,1.34,5.358,1.34,7.739,0l66.076-36.163
|
||||
c2.232-1.19,3.87-3.571,4.167-6.102c0.744-6.399,6.549-11.013,12.948-10.269c6.398,0.744,11.012,6.548,10.269,12.947
|
||||
c-1.191,9.971-7.293,18.9-16.073,23.812l-66.076,36.163C115.268,220.882,110.059,222.222,104.851,222.222z"/>
|
||||
<path fill="#FFFFFF" d="M157.086,131.441l-37.8-68.309l-0.149-0.149c-2.679-4.613-7.738-7.59-13.096-7.59s-10.417,2.977-13.096,7.59
|
||||
l-37.8,68.458c-2.828,5.208-1.042,11.607,4.167,14.436c5.208,2.827,11.608,1.041,14.436-4.167l7.292-13.245h50.004l7.292,13.245
|
||||
c1.935,3.571,5.506,5.506,9.376,5.506c1.785,0,3.571-0.446,5.06-1.339C157.979,143.049,159.914,136.501,157.086,131.441z
|
||||
M92.796,107.183l13.245-23.96l13.245,23.96H92.796z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,353 @@
|
||||
{
|
||||
"app": {
|
||||
"name": "Alain",
|
||||
"description": "Ng-zorro admin panel front-end framework"
|
||||
},
|
||||
"user": {
|
||||
"name": "Admin",
|
||||
"avatar": "./assets/tmp/img/avatar.jpg",
|
||||
"email": "cipchk@qq.com"
|
||||
},
|
||||
"menu": [
|
||||
{
|
||||
"text": "主导航",
|
||||
"i18n": "menu.main",
|
||||
"group": true,
|
||||
"hideInBreadcrumb": true,
|
||||
"children": [
|
||||
{
|
||||
"text": "仪表盘",
|
||||
"i18n": "menu.dashboard",
|
||||
"icon": "anticon-dashboard",
|
||||
"children": [
|
||||
{
|
||||
"text": "仪表盘V1",
|
||||
"link": "/dashboard/v1",
|
||||
"i18n": "menu.dashboard.v1"
|
||||
},
|
||||
{
|
||||
"text": "分析页",
|
||||
"link": "/dashboard/analysis",
|
||||
"i18n": "menu.dashboard.analysis"
|
||||
},
|
||||
{
|
||||
"text": "监控页",
|
||||
"link": "/dashboard/monitor",
|
||||
"i18n": "menu.dashboard.monitor"
|
||||
},
|
||||
{
|
||||
"text": "工作台",
|
||||
"link": "/dashboard/workplace",
|
||||
"i18n": "menu.dashboard.workplace"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "快捷菜单",
|
||||
"i18n": "menu.shortcut",
|
||||
"icon": "anticon-rocket",
|
||||
"shortcutRoot": true,
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"text": "小部件",
|
||||
"i18n": "menu.widgets",
|
||||
"link": "/widgets",
|
||||
"icon": "anticon-appstore",
|
||||
"badge": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Alain",
|
||||
"i18n": "menu.alain",
|
||||
"group": true,
|
||||
"hideInBreadcrumb": true,
|
||||
"children": [
|
||||
{
|
||||
"text": "样式",
|
||||
"i18n": "menu.style",
|
||||
"icon": "anticon-info",
|
||||
"children": [
|
||||
{
|
||||
"text": "Typography",
|
||||
"link": "/style/typography",
|
||||
"i18n": "menu.style.typography",
|
||||
"shortcut": true
|
||||
},
|
||||
{
|
||||
"text": "Grid Masonry",
|
||||
"link": "/style/gridmasonry",
|
||||
"i18n": "menu.style.gridmasonry"
|
||||
},
|
||||
{
|
||||
"text": "Colors",
|
||||
"link": "/style/colors",
|
||||
"i18n": "menu.style.colors"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Delon",
|
||||
"i18n": "menu.delon",
|
||||
"icon": "anticon-bulb",
|
||||
"children": [
|
||||
{
|
||||
"text": "Dynamic Form",
|
||||
"link": "/delon/form",
|
||||
"i18n": "menu.delon.form"
|
||||
},
|
||||
{
|
||||
"text": "Simple Table",
|
||||
"link": "/delon/st",
|
||||
"i18n": "menu.delon.table"
|
||||
},
|
||||
{
|
||||
"text": "Util",
|
||||
"link": "/delon/util",
|
||||
"i18n": "menu.delon.util",
|
||||
"acl": "role-a"
|
||||
},
|
||||
{
|
||||
"text": "Print",
|
||||
"link": "/delon/print",
|
||||
"i18n": "menu.delon.print",
|
||||
"acl": "role-b"
|
||||
},
|
||||
{
|
||||
"text": "QR",
|
||||
"link": "/delon/qr",
|
||||
"i18n": "menu.delon.qr"
|
||||
},
|
||||
{
|
||||
"text": "ACL",
|
||||
"link": "/delon/acl",
|
||||
"i18n": "menu.delon.acl"
|
||||
},
|
||||
{
|
||||
"text": "Route Guard",
|
||||
"link": "/delon/guard",
|
||||
"i18n": "menu.delon.guard"
|
||||
},
|
||||
{
|
||||
"text": "Cache",
|
||||
"link": "/delon/cache",
|
||||
"i18n": "menu.delon.cache"
|
||||
},
|
||||
{
|
||||
"text": "Down File",
|
||||
"link": "/delon/downfile",
|
||||
"i18n": "menu.delon.downfile"
|
||||
},
|
||||
{
|
||||
"text": "Xlsx",
|
||||
"link": "/delon/xlsx",
|
||||
"i18n": "menu.delon.xlsx"
|
||||
},
|
||||
{
|
||||
"text": "Zip",
|
||||
"link": "/delon/zip",
|
||||
"i18n": "menu.delon.zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Pro",
|
||||
"i18n": "menu.pro",
|
||||
"group": true,
|
||||
"hideInBreadcrumb": true,
|
||||
"children": [
|
||||
{
|
||||
"text": "Form Page",
|
||||
"i18n": "menu.form",
|
||||
"link": "/pro/form",
|
||||
"icon": "anticon-edit",
|
||||
"children": [
|
||||
{
|
||||
"text": "Basic Form",
|
||||
"link": "/pro/form/basic-form",
|
||||
"i18n": "menu.form.basicform",
|
||||
"shortcut": true
|
||||
},
|
||||
{
|
||||
"text": "Step Form",
|
||||
"link": "/pro/form/step-form",
|
||||
"i18n": "menu.form.stepform"
|
||||
},
|
||||
{
|
||||
"text": "Advanced Form",
|
||||
"link": "/pro/form/advanced-form",
|
||||
"i18n": "menu.form.advancedform"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "List",
|
||||
"i18n": "menu.list",
|
||||
"icon": "anticon-appstore",
|
||||
"children": [
|
||||
{
|
||||
"text": "Table List",
|
||||
"link": "/pro/list/table-list",
|
||||
"i18n": "menu.list.searchtable",
|
||||
"shortcut": true
|
||||
},
|
||||
{
|
||||
"text": "Basic List",
|
||||
"link": "/pro/list/basic-list",
|
||||
"i18n": "menu.list.basiclist"
|
||||
},
|
||||
{
|
||||
"text": "Card List",
|
||||
"link": "/pro/list/card-list",
|
||||
"i18n": "menu.list.cardlist"
|
||||
},
|
||||
{
|
||||
"text": "Search List",
|
||||
"i18n": "menu.list.searchlist",
|
||||
"children": [
|
||||
{
|
||||
"link": "/pro/list/articles",
|
||||
"i18n": "menu.list.searchlist.articles"
|
||||
},
|
||||
{
|
||||
"link": "/pro/list/projects",
|
||||
"i18n": "menu.list.searchlist.projects",
|
||||
"shortcut": true
|
||||
},
|
||||
{
|
||||
"link": "/pro/list/applications",
|
||||
"i18n": "menu.list.searchlist.applications"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Profile",
|
||||
"i18n": "menu.profile",
|
||||
"icon": "anticon-profile",
|
||||
"children": [
|
||||
{
|
||||
"text": "Basic",
|
||||
"link": "/pro/profile/basic",
|
||||
"i18n": "menu.profile.basic"
|
||||
},
|
||||
{
|
||||
"text": "Advanced",
|
||||
"link": "/pro/profile/advanced",
|
||||
"i18n": "menu.profile.advanced",
|
||||
"shortcut": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Result",
|
||||
"i18n": "menu.result",
|
||||
"icon": "anticon-check-circle",
|
||||
"children": [
|
||||
{
|
||||
"text": "Success",
|
||||
"link": "/pro/result/success",
|
||||
"i18n": "menu.result.success"
|
||||
},
|
||||
{
|
||||
"text": "Fail",
|
||||
"link": "/pro/result/fail",
|
||||
"i18n": "menu.result.fail"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Exception",
|
||||
"i18n": "menu.exception",
|
||||
"link": "/",
|
||||
"icon": "anticon-exception",
|
||||
"children": [
|
||||
{
|
||||
"text": "403",
|
||||
"link": "/exception/403",
|
||||
"i18n": "menu.exception.not-permission",
|
||||
"reuse": false
|
||||
},
|
||||
{
|
||||
"text": "404",
|
||||
"link": "/exception/404",
|
||||
"i18n": "menu.exception.not-find",
|
||||
"reuse": false
|
||||
},
|
||||
{
|
||||
"text": "500",
|
||||
"link": "/exception/500",
|
||||
"i18n": "menu.exception.server-error",
|
||||
"reuse": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Account",
|
||||
"i18n": "menu.account",
|
||||
"icon": "anticon-user",
|
||||
"children": [
|
||||
{
|
||||
"text": "center",
|
||||
"link": "/pro/account/center",
|
||||
"i18n": "menu.account.center"
|
||||
},
|
||||
{
|
||||
"text": "settings",
|
||||
"link": "/pro/account/settings",
|
||||
"i18n": "menu.account.settings"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "More",
|
||||
"i18n": "menu.more",
|
||||
"group": true,
|
||||
"hideInBreadcrumb": true,
|
||||
"children": [
|
||||
{
|
||||
"text": "Report",
|
||||
"i18n": "menu.report",
|
||||
"icon": "anticon-cloud",
|
||||
"children": [
|
||||
{
|
||||
"text": "Relation",
|
||||
"link": "/data-v/relation",
|
||||
"i18n": "menu.report.relation",
|
||||
"reuse": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "Extras",
|
||||
"i18n": "menu.extras",
|
||||
"link": "/extras",
|
||||
"icon": "anticon-link",
|
||||
"children": [
|
||||
{
|
||||
"text": "Help Center",
|
||||
"link": "/extras/helpcenter",
|
||||
"i18n": "menu.extras.helpcenter"
|
||||
},
|
||||
{
|
||||
"text": "Settings",
|
||||
"link": "/extras/settings",
|
||||
"i18n": "menu.extras.settings"
|
||||
},
|
||||
{
|
||||
"text": "Poi",
|
||||
"link": "/extras/poi",
|
||||
"i18n": "menu.extras.poi"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 400 400" style="enable-background:new 0 0 400 400;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:url(#SVGID_1_);}
|
||||
.st1{fill:url(#SVGID_2_);}
|
||||
.st2{fill:url(#SVGID_3_);}
|
||||
</style>
|
||||
<g>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="215.0983" y1="173.3861" x2="271.3071" y2="173.3861">
|
||||
<stop offset="3.215440e-02" style="stop-color:#F0776F"/>
|
||||
<stop offset="1" style="stop-color:#F0606F"/>
|
||||
</linearGradient>
|
||||
<path class="st0" d="M258.7,213.4c-0.3,0-0.6,0-1-0.1c-4.3-0.5-7.4-4.4-6.9-8.7l4.7-38.9c0.3-2.5-1.2-4.9-3.5-5.7l-31.7-11.3
|
||||
c-4.1-1.5-6.2-5.9-4.8-10c1.5-4.1,5.9-6.2,10-4.8l31.7,11.3c9.4,3.3,15.1,12.5,13.9,22.4l-4.7,38.9
|
||||
C266,210.4,262.6,213.4,258.7,213.4z"/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="127.4784" y1="201.0843" x2="263.3311" y2="201.0843">
|
||||
<stop offset="0" style="stop-color:#6EB4E0"/>
|
||||
<stop offset="1" style="stop-color:#1588E0"/>
|
||||
</linearGradient>
|
||||
<path class="st1" d="M197.9,275.7c-3.5,0-7-0.9-10.3-2.7l-41-22.8c-5.9-3.3-9.9-9.2-10.7-15.9l-8.3-67.6
|
||||
c-1.2-9.9,4.7-19.3,14.1-22.6l50.7-17.3c4.1-1.4,8.6,0.8,10,4.9c1.4,4.1-0.8,8.6-4.9,10l-50.7,17.3c-2.4,0.8-3.9,3.2-3.6,5.8
|
||||
l8.3,67.6c0.2,1.7,1.2,3.2,2.7,4.1l41,22.8c1.6,0.9,3.6,0.9,5.2,0l44.4-24.3c1.5-0.8,2.6-2.4,2.8-4.1c0.5-4.3,4.4-7.4,8.7-6.9
|
||||
c4.3,0.5,7.4,4.4,6.9,8.7c-0.8,6.7-4.9,12.7-10.8,16l-44.4,24.3C204.9,274.8,201.4,275.7,197.9,275.7z"/>
|
||||
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="163.5466" y1="194.4135" x2="233.869" y2="194.4135">
|
||||
<stop offset="3.215440e-02" style="stop-color:#F0776F"/>
|
||||
<stop offset="1" style="stop-color:#F0606F"/>
|
||||
</linearGradient>
|
||||
<path class="st2" d="M233,214.7l-25.4-45.9l-0.1-0.1c-1.8-3.1-5.2-5.1-8.8-5.1c-3.6,0-7,2-8.8,5.1l-25.4,46
|
||||
c-1.9,3.5-0.7,7.8,2.8,9.7c3.5,1.9,7.8,0.7,9.7-2.8l4.9-8.9h33.6l4.9,8.9c1.3,2.4,3.7,3.7,6.3,3.7c1.2,0,2.4-0.3,3.4-0.9
|
||||
C233.6,222.5,234.9,218.1,233,214.7z M189.8,198.4l8.9-16.1l8.9,16.1H189.8z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
@ -0,0 +1,11 @@
|
||||
import { Environment } from '@delon/theme';
|
||||
|
||||
export const environment = {
|
||||
production: true,
|
||||
useHash: true,
|
||||
api: {
|
||||
baseUrl: './',
|
||||
refreshTokenEnabled: true,
|
||||
refreshTokenType: 'auth-refresh'
|
||||
}
|
||||
} as Environment;
|
@ -0,0 +1,27 @@
|
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build ---prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
import { DelonMockModule } from '@delon/mock';
|
||||
import { Environment } from '@delon/theme';
|
||||
|
||||
import * as MOCKDATA from '../../_mock';
|
||||
|
||||
export const environment = {
|
||||
production: false,
|
||||
useHash: true,
|
||||
api: {
|
||||
baseUrl: './',
|
||||
refreshTokenEnabled: true,
|
||||
refreshTokenType: 'auth-refresh'
|
||||
},
|
||||
modules: [DelonMockModule.forRoot({ data: MOCKDATA })]
|
||||
} as Environment;
|
||||
|
||||
/*
|
||||
* In development mode, to ignore zone related error stack frames such as
|
||||
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
|
||||
* import the following file, but please comment it out in production mode
|
||||
* because it will have performance impact when throw error
|
||||
*/
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>GoMicroDashboard</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<style type="text/css">.preloader{position:fixed;top:0;left:0;width:100%;height:100%;overflow:hidden;background:#49a9ee;z-index:9999;transition:opacity .65s}.preloader-hidden-add{opacity:1;display:block}.preloader-hidden-add-active{opacity:0}.preloader-hidden{display:none}.cs-loader{position:absolute;top:0;left:0;height:100%;width:100%}.cs-loader-inner{transform:translateY(-50%);top:50%;position:absolute;width:100%;color:#fff;text-align:center}.cs-loader-inner label{font-size:20px;opacity:0;display:inline-block}@keyframes lol{0%{opacity:0;transform:translateX(-300px)}33%{opacity:1;transform:translateX(0)}66%{opacity:1;transform:translateX(0)}100%{opacity:0;transform:translateX(300px)}}.cs-loader-inner label:nth-child(6){animation:lol 3s infinite ease-in-out}.cs-loader-inner label:nth-child(5){animation:lol 3s .1s infinite ease-in-out}.cs-loader-inner label:nth-child(4){animation:lol 3s .2s infinite ease-in-out}.cs-loader-inner label:nth-child(3){animation:lol 3s .3s infinite ease-in-out}.cs-loader-inner label:nth-child(2){animation:lol 3s .4s infinite ease-in-out}.cs-loader-inner label:nth-child(1){animation:lol 3s .5s infinite ease-in-out}</style></head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<div class="preloader"><div class="cs-loader"><div class="cs-loader-inner"><label> ●</label><label> ●</label><label> ●</label><label> ●</label><label> ●</label><label> ●</label></div></div></div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,27 @@
|
||||
import { enableProdMode, ViewEncapsulation } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { preloaderFinished } from '@delon/theme';
|
||||
import { NzSafeAny } from 'ng-zorro-antd/core/types';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
preloaderFinished();
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule, {
|
||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||
preserveWhitespaces: false
|
||||
})
|
||||
.then(res => {
|
||||
const win = window as NzSafeAny;
|
||||
if (win && win.appBootstrap) {
|
||||
win.appBootstrap();
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch(err => console.error(err));
|
@ -0,0 +1,66 @@
|
||||
/* eslint-disable import/no-unassigned-import */
|
||||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/guide/browser-support
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/**
|
||||
* IE11 requires the following for NgClass support on SVG elements
|
||||
*/
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
* user can disable parts of macroTask/DomEvents patch by setting following flags
|
||||
* because those flags need to be set before `zone.js` being loaded, and webpack
|
||||
* will put import in the top of bundle, so user need to create a separate file
|
||||
* in this directory (for example: zone-flags.ts), and put the following flags
|
||||
* into that file, and then add the following code before importing zone.js.
|
||||
* import './zone-flags';
|
||||
*
|
||||
* The flags allowed in zone-flags.ts are listed here.
|
||||
*
|
||||
* The following flags will work for all browsers.
|
||||
*
|
||||
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Automatically generated by 'ng g ng-alain:plugin icon'
|
||||
* @see https://ng-alain.com/cli/plugin#icon
|
||||
*/
|
||||
|
||||
import {
|
||||
AlipayCircleOutline,
|
||||
ApiOutline,
|
||||
AppstoreOutline,
|
||||
ArrowDownOutline,
|
||||
BookOutline,
|
||||
BorderLeftOutline,
|
||||
BorderRightOutline,
|
||||
CloudOutline,
|
||||
CopyrightOutline,
|
||||
CustomerServiceOutline,
|
||||
DashboardOutline,
|
||||
DatabaseOutline,
|
||||
DingdingOutline,
|
||||
DislikeOutline,
|
||||
DownloadOutline,
|
||||
ForkOutline,
|
||||
FrownOutline,
|
||||
FullscreenExitOutline,
|
||||
FullscreenOutline,
|
||||
GithubOutline,
|
||||
GlobalOutline,
|
||||
HddOutline,
|
||||
LaptopOutline,
|
||||
LikeOutline,
|
||||
LockOutline,
|
||||
LogoutOutline,
|
||||
MailOutline,
|
||||
MenuFoldOutline,
|
||||
MenuUnfoldOutline,
|
||||
MessageOutline,
|
||||
PayCircleOutline,
|
||||
PieChartOutline,
|
||||
PrinterOutline,
|
||||
RocketOutline,
|
||||
ScanOutline,
|
||||
SettingOutline,
|
||||
ShareAltOutline,
|
||||
ShoppingCartOutline,
|
||||
SoundOutline,
|
||||
StarOutline,
|
||||
TaobaoCircleOutline,
|
||||
TaobaoOutline,
|
||||
TeamOutline,
|
||||
ToolOutline,
|
||||
TrophyOutline,
|
||||
UsbOutline,
|
||||
UserOutline,
|
||||
WeiboCircleOutline
|
||||
} from '@ant-design/icons-angular/icons';
|
||||
|
||||
export const ICONS_AUTO = [
|
||||
AlipayCircleOutline,
|
||||
ApiOutline,
|
||||
AppstoreOutline,
|
||||
ArrowDownOutline,
|
||||
BookOutline,
|
||||
BorderLeftOutline,
|
||||
BorderRightOutline,
|
||||
CloudOutline,
|
||||
CopyrightOutline,
|
||||
CustomerServiceOutline,
|
||||
DashboardOutline,
|
||||
DatabaseOutline,
|
||||
DingdingOutline,
|
||||
DislikeOutline,
|
||||
DownloadOutline,
|
||||
ForkOutline,
|
||||
FrownOutline,
|
||||
FullscreenExitOutline,
|
||||
FullscreenOutline,
|
||||
GithubOutline,
|
||||
GlobalOutline,
|
||||
HddOutline,
|
||||
LaptopOutline,
|
||||
LikeOutline,
|
||||
LockOutline,
|
||||
LogoutOutline,
|
||||
MailOutline,
|
||||
MenuFoldOutline,
|
||||
MenuUnfoldOutline,
|
||||
MessageOutline,
|
||||
PayCircleOutline,
|
||||
PieChartOutline,
|
||||
PrinterOutline,
|
||||
RocketOutline,
|
||||
ScanOutline,
|
||||
SettingOutline,
|
||||
ShareAltOutline,
|
||||
ShoppingCartOutline,
|
||||
SoundOutline,
|
||||
StarOutline,
|
||||
TaobaoCircleOutline,
|
||||
TaobaoOutline,
|
||||
TeamOutline,
|
||||
ToolOutline,
|
||||
TrophyOutline,
|
||||
UsbOutline,
|
||||
UserOutline,
|
||||
WeiboCircleOutline
|
||||
];
|
@ -0,0 +1,5 @@
|
||||
// Custom icon static resources
|
||||
|
||||
import { BulbOutline, ExceptionOutline, InfoOutline, LinkOutline, ProfileOutline } from '@ant-design/icons-angular/icons';
|
||||
|
||||
export const ICONS = [InfoOutline, BulbOutline, ProfileOutline, ExceptionOutline, LinkOutline];
|
@ -0,0 +1,8 @@
|
||||
@import '~@delon/theme/system/index';
|
||||
@import '~@delon/abc/index';
|
||||
@import '~@delon/chart/index';
|
||||
@import '~@delon/theme/layout-default/style/index';
|
||||
@import '~@delon/theme/layout-blank/style/index';
|
||||
|
||||
@import './styles/index';
|
||||
@import './styles/theme';
|
@ -0,0 +1 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
@ -0,0 +1,9 @@
|
||||
// You can directly set the default theme
|
||||
// - `default` Default theme
|
||||
// - `dark` Import the official dark less style file
|
||||
// - `compact` Import the official compact less style file
|
||||
@import '~@delon/theme/theme-default.less';
|
||||
|
||||
// ==========The following is the custom theme variable area==========
|
||||
// The theme paraments can be generated at https://ng-alain.github.io/ng-alain/
|
||||
// @primary-color: #f50;
|
@ -0,0 +1,22 @@
|
||||
/* eslint-disable import/no-unassigned-import */
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
@ -0,0 +1,3 @@
|
||||
// # 3rd Party Library
|
||||
// If the library doesn't have typings available at `@types/`,
|
||||
// you can still use it by manually adding typings for it
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue