├── .browserslistrc ├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── _mock └── index.ts ├── angular.json ├── components ├── CHANGELOG.md ├── README.md ├── index.ts ├── layout │ ├── base-menu.component.html │ ├── base-menu.component.ts │ ├── basic-layout.component.html │ ├── basic-layout.component.ts │ ├── doc │ │ └── index.zh-CN.md │ ├── global-footer.component.ts │ ├── global-header.component.ts │ ├── grid-content.component.ts │ ├── index.ts │ ├── layout.module.ts │ ├── package.json │ ├── page-header-wrapper.component.html │ ├── page-header-wrapper.component.ts │ ├── public-api.ts │ ├── style │ │ ├── base-menu.less │ │ ├── basic-layout.less │ │ ├── entry.less │ │ ├── global-footer.less │ │ ├── global-header.less │ │ ├── grid-content.less │ │ ├── header.less │ │ ├── page-header-wrapper.less │ │ └── top-nav-header.less │ └── top-nav-header.component.ts ├── ng-package.json ├── ng-zorro-pro.less ├── package.json ├── public-api.ts ├── reuse-tab │ ├── index.ts │ ├── package.json │ ├── public-api.ts │ ├── reuse-tab-history.service.ts │ ├── reuse-tab-menu.component.ts │ ├── reuse-tab-menu.service.ts │ ├── reuse-tab.component.ts │ ├── reuse-tab.interface.ts │ ├── reuse-tab.module.ts │ ├── reuse-tab.service.ts │ ├── reuse-tab.strategy.ts │ ├── scroll.service.ts │ └── style │ │ ├── entry.less │ │ └── index.less ├── test.ts ├── tsconfig.lib.json ├── tsconfig.lib.prod.json ├── tsconfig.spec.json └── tslint.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.json ├── karma.conf.js ├── package.json ├── src ├── app │ ├── acl │ │ ├── acl-guard.spec.ts │ │ ├── acl-guard.ts │ │ ├── acl-if.directive.spec.ts │ │ ├── acl-if.directive.ts │ │ ├── acl.config.ts │ │ ├── acl.directive.spec.ts │ │ ├── acl.directive.ts │ │ ├── acl.module.ts │ │ ├── acl.service.spec.ts │ │ ├── acl.service.ts │ │ ├── acl.type.ts │ │ └── index.ts │ ├── app-menu.ts │ ├── app-routing.module.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── core │ │ ├── i18n │ │ │ └── i18n.service.ts │ │ └── startup │ │ │ └── startup.service.ts │ ├── locales │ │ ├── en-US.ts │ │ ├── en-US │ │ │ ├── component.ts │ │ │ ├── globalHeader.ts │ │ │ ├── menu.ts │ │ │ ├── pwa.ts │ │ │ ├── settingDrawer.ts │ │ │ └── settings.ts │ │ ├── pt-BR.ts │ │ ├── pt-BR │ │ │ ├── component.ts │ │ │ ├── globalHeader.ts │ │ │ ├── menu.ts │ │ │ ├── pwa.ts │ │ │ ├── settingDrawer.ts │ │ │ └── settings.ts │ │ ├── zh-CN.ts │ │ ├── zh-CN │ │ │ ├── component.ts │ │ │ ├── globalHeader.ts │ │ │ ├── menu.ts │ │ │ ├── pwa.ts │ │ │ ├── settingDrawer.ts │ │ │ └── settings.ts │ │ ├── zh-TW.ts │ │ └── zh-TW │ │ │ ├── component.ts │ │ │ ├── globalHeader.ts │ │ │ ├── menu.ts │ │ │ ├── pwa.ts │ │ │ ├── settingDrawer.ts │ │ │ └── settings.ts │ ├── pages │ │ ├── account │ │ │ ├── account-routing.module.ts │ │ │ ├── account.module.ts │ │ │ ├── center │ │ │ │ ├── _mock.ts │ │ │ │ ├── center.component.html │ │ │ │ ├── center.component.less │ │ │ │ └── center.component.ts │ │ │ └── settings │ │ │ │ ├── components │ │ │ │ └── security-view │ │ │ │ │ ├── security-view.component.html │ │ │ │ │ └── security-view.component.ts │ │ │ │ ├── settings.component.html │ │ │ │ └── settings.component.ts │ │ ├── dashboard │ │ │ ├── analysis │ │ │ │ ├── _mock.ts │ │ │ │ ├── analysis.component.html │ │ │ │ ├── analysis.component.less │ │ │ │ ├── analysis.component.ts │ │ │ │ ├── components │ │ │ │ │ ├── charts │ │ │ │ │ │ └── bar │ │ │ │ │ │ │ ├── bar.component.html │ │ │ │ │ │ │ └── bar.component.ts │ │ │ │ │ ├── introduce-row │ │ │ │ │ │ ├── introduce-row.component.html │ │ │ │ │ │ └── introduce-row.component.ts │ │ │ │ │ ├── offline-data │ │ │ │ │ │ ├── offline-data.component.html │ │ │ │ │ │ └── offline-data.component.ts │ │ │ │ │ ├── proportion-sales │ │ │ │ │ │ ├── proportion-sales.component.html │ │ │ │ │ │ └── proportion-sales.component.ts │ │ │ │ │ ├── sales-card │ │ │ │ │ │ ├── sales-card.component.html │ │ │ │ │ │ └── sales-card.component.ts │ │ │ │ │ └── top-search │ │ │ │ │ │ ├── top-search.component.html │ │ │ │ │ │ └── top-search.component.ts │ │ │ │ ├── data.d.ts │ │ │ │ └── index.ts │ │ │ ├── dashboard-routing.module.ts │ │ │ ├── dashboard.module.ts │ │ │ ├── monitor │ │ │ │ ├── _mock.ts │ │ │ │ ├── components │ │ │ │ │ ├── active-chart │ │ │ │ │ │ ├── active-chart.component.html │ │ │ │ │ │ ├── active-chart.component.less │ │ │ │ │ │ └── active-chart.component.ts │ │ │ │ │ └── chart │ │ │ │ │ │ └── mini-area │ │ │ │ │ │ ├── mini-area.component.html │ │ │ │ │ │ ├── mini-area.component.less │ │ │ │ │ │ └── mini-area.component.ts │ │ │ │ ├── index.ts │ │ │ │ ├── monitor.component.html │ │ │ │ ├── monitor.component.less │ │ │ │ └── monitor.component.ts │ │ │ └── workplace │ │ │ │ ├── _mock.ts │ │ │ │ ├── components │ │ │ │ ├── editable-link-group │ │ │ │ │ ├── editable-link-group.component.html │ │ │ │ │ ├── editable-link-group.component.less │ │ │ │ │ └── editable-link-group.component.ts │ │ │ │ └── radar │ │ │ │ │ ├── radar.component.html │ │ │ │ │ ├── radar.component.less │ │ │ │ │ └── radar.component.ts │ │ │ │ ├── data.d.ts │ │ │ │ ├── index.ts │ │ │ │ ├── workplace.component.html │ │ │ │ ├── workplace.component.less │ │ │ │ └── workplace.component.ts │ │ ├── exception │ │ │ ├── 403 │ │ │ │ ├── 403.component.ts │ │ │ │ └── locales │ │ │ │ │ ├── en-US.ts │ │ │ │ │ ├── pt-BR.ts │ │ │ │ │ ├── zh-CN.ts │ │ │ │ │ └── zh-TW.ts │ │ │ ├── 404 │ │ │ │ ├── 404.component.ts │ │ │ │ └── locales │ │ │ │ │ ├── en-US.ts │ │ │ │ │ ├── pt-BR.ts │ │ │ │ │ ├── zh-CN.ts │ │ │ │ │ └── zh-TW.ts │ │ │ ├── 500 │ │ │ │ ├── 500.component.ts │ │ │ │ └── locales │ │ │ │ │ ├── en-US.ts │ │ │ │ │ ├── pt-BR.ts │ │ │ │ │ ├── zh-CN.ts │ │ │ │ │ └── zh-TW.ts │ │ │ ├── exception-routing.module.ts │ │ │ └── exception.module.ts │ │ ├── forms │ │ │ ├── advanced-form │ │ │ │ ├── advanced-form.component.html │ │ │ │ └── advanced-form.component.ts │ │ │ ├── basic-form │ │ │ │ ├── basic-form.component.html │ │ │ │ └── basic-form.component.ts │ │ │ ├── forms-routing.module.ts │ │ │ ├── forms.module.ts │ │ │ ├── step-form │ │ │ │ ├── step-form.component.html │ │ │ │ └── step-form.component.ts │ │ │ └── table-form │ │ │ │ ├── table-form.component.html │ │ │ │ └── table-form.component.ts │ │ ├── list │ │ │ ├── basic-list │ │ │ │ ├── _mock.ts │ │ │ │ ├── basic-list.component.html │ │ │ │ ├── basic-list.component.less │ │ │ │ ├── basic-list.component.ts │ │ │ │ └── data.d.ts │ │ │ ├── card-list │ │ │ │ ├── card-list.component.html │ │ │ │ ├── card-list.component.less │ │ │ │ └── card-list.component.ts │ │ │ ├── list-routing.module.ts │ │ │ ├── list.module.ts │ │ │ ├── list │ │ │ │ ├── applications │ │ │ │ │ ├── applications.component.html │ │ │ │ │ └── applications.component.ts │ │ │ │ ├── articles │ │ │ │ │ ├── articles.component.html │ │ │ │ │ └── articles.component.ts │ │ │ │ ├── list.component.html │ │ │ │ ├── list.component.ts │ │ │ │ └── projects │ │ │ │ │ ├── projects.component.html │ │ │ │ │ └── projects.component.ts │ │ │ └── table-list │ │ │ │ ├── _mock.ts │ │ │ │ ├── data.d.ts │ │ │ │ ├── table-list-detail.component.ts │ │ │ │ ├── table-list.component.html │ │ │ │ ├── table-list.component.less │ │ │ │ └── table-list.component.ts │ │ ├── other │ │ │ ├── other-routing.module.ts │ │ │ ├── other.module.ts │ │ │ ├── permission-list │ │ │ │ ├── permission-list.component.html │ │ │ │ └── permission-list.component.ts │ │ │ ├── role-list │ │ │ │ ├── role-list.component.html │ │ │ │ └── role-list.component.ts │ │ │ └── user-list │ │ │ │ ├── user-list.component.html │ │ │ │ └── user-list.component.ts │ │ ├── profile │ │ │ ├── advanced-profile │ │ │ │ ├── _mock.ts │ │ │ │ ├── advanced-profile.component.html │ │ │ │ ├── advanced-profile.component.less │ │ │ │ └── advanced-profile.component.ts │ │ │ ├── basic-profile │ │ │ │ ├── _mock.ts │ │ │ │ ├── basic-profile.component.html │ │ │ │ ├── basic-profile.component.less │ │ │ │ └── basic-profile.component.ts │ │ │ ├── profile-routing.module.ts │ │ │ └── profile.module.ts │ │ ├── result │ │ │ ├── fail │ │ │ │ ├── fail.component.html │ │ │ │ ├── fail.component.less │ │ │ │ └── fail.component.ts │ │ │ ├── result-routing.module.ts │ │ │ ├── result.module.ts │ │ │ └── success │ │ │ │ ├── success.component.html │ │ │ │ ├── success.component.less │ │ │ │ └── success.component.ts │ │ └── user │ │ │ ├── login │ │ │ ├── locales │ │ │ │ ├── en-US.ts │ │ │ │ ├── zh-CN.ts │ │ │ │ └── zh-TW.ts │ │ │ ├── login.component.html │ │ │ ├── login.component.less │ │ │ └── login.component.ts │ │ │ ├── register-result │ │ │ ├── locales │ │ │ │ ├── en-US.ts │ │ │ │ ├── zh-CN.ts │ │ │ │ └── zh-TW.ts │ │ │ ├── register-result.component.html │ │ │ ├── register-result.component.less │ │ │ └── register-result.component.ts │ │ │ ├── register │ │ │ ├── locales │ │ │ │ ├── en-US.ts │ │ │ │ ├── zh-CN.ts │ │ │ │ └── zh-TW.ts │ │ │ ├── register.component.html │ │ │ ├── register.component.less │ │ │ └── register.component.ts │ │ │ └── user.module.ts │ └── shared │ │ ├── components │ │ ├── copy-block │ │ │ ├── copy-block.component.html │ │ │ ├── copy-block.component.less │ │ │ └── copy-block.component.ts │ │ ├── global-header │ │ │ ├── avatar-dropdown │ │ │ │ ├── avatar-dropdown.component.html │ │ │ │ └── avatar-dropdown.component.ts │ │ │ ├── notice-icon-view │ │ │ │ ├── notice-icon-view.component.html │ │ │ │ └── notice-icon-view.component.ts │ │ │ └── right-content │ │ │ │ ├── right-content.component.html │ │ │ │ ├── right-content.component.less │ │ │ │ └── right-content.component.ts │ │ ├── header-dropdown │ │ │ ├── header-dropdown.component.html │ │ │ ├── header-dropdown.component.less │ │ │ └── header-dropdown.component.ts │ │ ├── header-search │ │ │ ├── header-search.component.html │ │ │ ├── header-search.component.less │ │ │ └── header-search.component.ts │ │ ├── index.ts │ │ ├── notice-icon │ │ │ ├── notice-icon.component.html │ │ │ ├── notice-icon.component.less │ │ │ ├── notice-icon.component.ts │ │ │ └── notice-list │ │ │ │ ├── notice-list.component.html │ │ │ │ ├── notice-list.component.less │ │ │ │ └── notice-list.component.ts │ │ ├── page-loading │ │ │ ├── page-loading.component.html │ │ │ └── page-loading.component.ts │ │ ├── result │ │ │ ├── result.component.html │ │ │ ├── result.component.less │ │ │ └── result.component.ts │ │ └── select-lang │ │ │ ├── select-lang.component.html │ │ │ ├── select-lang.component.less │ │ │ └── select-lang.component.ts │ │ ├── layout │ │ ├── basic-layout │ │ │ ├── basic-layout.component.html │ │ │ └── basic-layout.component.ts │ │ ├── blank-layout │ │ │ ├── blank-layout.component.html │ │ │ └── blank-layout.component.ts │ │ ├── index.ts │ │ └── user-layout │ │ │ ├── user-layout.component.html │ │ │ ├── user-layout.component.less │ │ │ └── user-layout.component.ts │ │ ├── models │ │ └── user.ts │ │ ├── shared-zorro.module.ts │ │ └── shared.module.ts ├── assets │ ├── .gitkeep │ └── logo.svg ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.less ├── styles │ ├── global.less │ ├── theme.less │ └── utils.less └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | package-lock.json 13 | 14 | # profiling files 15 | chrome-profiler-events.json 16 | speed-measure-plugin.json 17 | 18 | # IDEs and editors 19 | /.idea 20 | .project 21 | .classpath 22 | .c9/ 23 | *.launch 24 | .settings/ 25 | *.sublime-workspace 26 | 27 | # IDE - VSCode 28 | .vscode/* 29 | !.vscode/settings.json 30 | !.vscode/tasks.json 31 | !.vscode/launch.json 32 | !.vscode/extensions.json 33 | .history/* 34 | 35 | # misc 36 | /.sass-cache 37 | /connect.lock 38 | /coverage 39 | /libpeerconnection.log 40 | npm-debug.log 41 | yarn-error.log 42 | testem.log 43 | /typings 44 | 45 | # System Files 46 | .DS_Store 47 | Thumbs.db 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 sanshine 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NPM version](https://img.shields.io/npm/v/pro-layout.svg)](https://www.npmjs.com/package/pro-layout) 2 | 3 | 4 |

Ant Design Pro Angular

5 | 6 |
7 | 8 | ![image](https://user-images.githubusercontent.com/8186664/55930941-276e6580-5c56-11e9-800d-bc284bda4daf.png) 9 | 10 | 开箱即用的中台前端/设计解决方案。此仓库是 Angular 版本的 Ant Design Pro 的 layout, 是为了方便快速的使用 layout 而开发。 11 | 12 | 样式对应 `@ant-design/pro-layout:4.6.2` 13 | 14 | 15 |
16 | 17 | ## 使用 18 | 19 | ```bash 20 | npm i pro-layout --save 21 | // or 22 | yarn add pro-layout 23 | ``` 24 | 25 | ```ts 26 | import {LayoutModule} from "pro-layout"; 27 | 28 | @NgModule({ 29 | imports: [ LayoutModule ] 30 | }) 31 | export class AppModule { 32 | } 33 | ``` 34 | 35 | ## 依赖项目 36 | 37 | - [ng-zorro-antd](https://github.com/NG-ZORRO/ng-zorro-antd) 38 | - [@delon/auth](https://ng-alain.com/auth/getting-started/zh) 39 | - [@delon/acl](https://ng-alain.com/acl/getting-started/zh) 40 | - [@delon/mock](https://ng-alain.com/mock/getting-started/zh) 41 | - [@ngx-translate/core](https://github.com/ngx-translate/core) 42 | -------------------------------------------------------------------------------- /_mock/index.ts: -------------------------------------------------------------------------------- 1 | export * from '../src/app/pages/dashboard/analysis/_mock'; 2 | export * from '../src/app/pages/dashboard/workplace/_mock'; 3 | export * from '../src/app/pages/profile/advanced-profile/_mock'; 4 | export * from '../src/app/pages/profile/basic-profile/_mock'; 5 | export * from '../src/app/pages/account/center/_mock'; 6 | export * from '../src/app/pages/list/basic-list/_mock'; 7 | export * from '../src/app/pages/list/table-list/_mock'; 8 | 9 | -------------------------------------------------------------------------------- /components/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | 3 | ### 0.0.23 4 | - fix ViewDestroyed detectChanges error 5 | 6 | ### 0.0.22 7 | - 修复关闭替他标签异常 8 | 9 | ### 0.0.21 10 | - 处理关闭bug 11 | - 增加关闭当前页跳转到列表页的方法 12 | 13 | ### 0.0.20 14 | - 修改 zorro V10 tab 文件名,防止与v8 tab冲突 15 | 16 | ### 0.0.19 17 | - reuseTab增加refreshable配置 18 | 19 | ### 0.0.18 20 | - 增加reuseTab,queryParam来区分路由 21 | 22 | ### 0.0.9 23 | - 菜单展开增加路由监听 24 | 25 | ### 0.0.8 26 | - menuDataItem增加externalClick以支持自己控制如何打开第三方URL 27 | 28 | ### 0.0.7 29 | - menuDataItem增加external以支持新标签页打开第三方URL 30 | 31 | ### 0.0.6 32 | - `menu`没有根据`delon acl`的变化更新 33 | 34 | ### 0.0.5 35 | 36 | - `localStorage`不保存`settings` 37 | - `menu`使用 `[nzMatchRouter]`来控制默认选中 38 | - 修复已知问题 39 | 40 | ### 0.0.4 41 | 42 | - 同步`react v4.6.2`样式 43 | -------------------------------------------------------------------------------- /components/README.md: -------------------------------------------------------------------------------- 1 | # ant design pro layout of angular 2 | 3 | ## 使用 4 | 5 | ```bash 6 | npm i pro-layout --save 7 | // or 8 | yarn add pro-layout 9 | ``` 10 | 11 | ```html 12 | 24 | 25 | 26 | 27 | ``` 28 | 29 | ### PRO_LAYOUT (InjectToken) 30 | 31 | ``` 32 | { 33 | provide: PRO_LAYOUT, 34 | useValue: { 35 | title: 'Ant Design Pro', 36 | logo: 'assets/logo.svg', 37 | navTheme: 'dark', 38 | primaryColor: '#1890FF', 39 | layout: 'sidemenu', 40 | contentWidth: 'Fluid', 41 | fixedHeader: false, 42 | autoHideHeader: false, 43 | fixSiderbar: false, 44 | reuseTab: true, 45 | } 46 | } 47 | ``` 48 | 49 | ### MenuDataItem 50 | 51 | ```ts 52 | export interface MenuDataItem { 53 | name?: string; 54 | icon?: string; 55 | locale?: string; 56 | path: string; 57 | guard?: ACLType; 58 | external?: boolean; 59 | children?: MenuDataItem[]; 60 | [key: string]: any; 61 | } 62 | ``` 63 | 64 | ### Router config data 65 | 66 | ```ts 67 | export interface RouterData { 68 | name?: string; 69 | locale?: string; 70 | guard?: ACLType; 71 | reuse?: boolean 72 | [key: string]: any; 73 | } 74 | ``` 75 | -------------------------------------------------------------------------------- /components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layout/index'; 2 | export * from './reuse-tab/index'; 3 | -------------------------------------------------------------------------------- /components/layout/base-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | ChangeDetectionStrategy, ChangeDetectorRef, 4 | Component, 5 | EventEmitter, 6 | Input, OnInit, 7 | Output, 8 | ViewEncapsulation 9 | } from '@angular/core'; 10 | import {ACLService, ACLType} from '@delon/acl'; 11 | 12 | export interface RouterData { 13 | name?: string; 14 | locale?: string; 15 | guard?: ACLType; 16 | 17 | [key: string]: any; 18 | } 19 | 20 | export interface MenuDataItem { 21 | name?: string; 22 | icon?: string; 23 | locale?: string; 24 | path: string; 25 | guard?: ACLType; 26 | external?: boolean; // 通过新标签打开外部连接 27 | externalClick?: (menuDataItem: MenuDataItem) => void; // 自定义如何打开外部连接 28 | children?: MenuDataItem[]; 29 | 30 | [key: string]: any; 31 | } 32 | 33 | @Component({ 34 | selector: 'pro-base-menu', 35 | templateUrl: 'base-menu.component.html', 36 | changeDetection: ChangeDetectionStrategy.OnPush, 37 | encapsulation: ViewEncapsulation.None, 38 | exportAs: 'proBaseMenu', 39 | preserveWhitespaces: false 40 | }) 41 | export class BaseMenuComponent implements OnInit, AfterViewInit { 42 | 43 | @Input() style: { [key: string]: string }; 44 | @Input() mode = 'inline'; 45 | @Input() menuData: MenuDataItem[]; 46 | @Input() theme = 'dark'; 47 | @Input() collapsed: boolean; 48 | /** @deprecated */ 49 | @Input() selectedKey: string; 50 | @Input() openKeys: Set = new Set(); 51 | @Output() openChange: EventEmitter = new EventEmitter(); 52 | 53 | constructor(private aclService: ACLService, 54 | private cdf: ChangeDetectorRef) { 55 | } 56 | 57 | ngAfterViewInit(): void { 58 | this.aclService.change.subscribe((change: ACLType | boolean | null) => { 59 | if (change) { 60 | this.cdf.markForCheck(); 61 | } 62 | }) 63 | } 64 | 65 | ngOnInit(): void { 66 | // console.log(this.menuData); 67 | } 68 | 69 | onOpenChange(status, menuData) { 70 | this.openChange.emit({status, item: menuData}); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /components/layout/global-footer.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef, ViewEncapsulation} from '@angular/core'; 2 | 3 | export interface GlobalFooterProps { 4 | links?: { 5 | key?: string; 6 | title: TemplateRef | string; 7 | href: string; 8 | blankTarget?: boolean; 9 | }[]; 10 | copyright?: TemplateRef; 11 | style?: string; 12 | className?: string; 13 | } 14 | 15 | @Component({ 16 | selector: 'pro-global-footer,[pro-global-footer]', 17 | template: ` 18 | 33 | 41 | `, 42 | changeDetection: ChangeDetectionStrategy.OnPush, 43 | encapsulation: ViewEncapsulation.None, 44 | exportAs: 'proGlobalFooter', 45 | preserveWhitespaces: false, 46 | host: { 47 | '[class]': `'ant-pro-global-footer ' + className` 48 | } 49 | }) 50 | export class GlobalFooterComponent implements OnInit { 51 | 52 | @Input() className = ''; 53 | @Input() links: GlobalFooterProps['links']; 54 | @Input() copyright: TemplateRef | string; 55 | 56 | constructor() { 57 | } 58 | 59 | ngOnInit() { 60 | } 61 | 62 | isString(val) { 63 | return typeof val === 'string'; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /components/layout/global-header.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectionStrategy, 3 | Component, 4 | EventEmitter, 5 | Input, 6 | OnInit, 7 | Output, 8 | TemplateRef, 9 | ViewEncapsulation 10 | } from '@angular/core'; 11 | 12 | @Component({ 13 | selector: 'pro-global-header,[pro-global-header]', 14 | template: ` 15 | 16 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 34 | 35 | `, 36 | changeDetection: ChangeDetectionStrategy.OnPush, 37 | encapsulation: ViewEncapsulation.None, 38 | exportAs: 'proGlobalHeader', 39 | preserveWhitespaces: false, 40 | host: { 41 | '[class]': `'ant-pro-global-header'` 42 | } 43 | }) 44 | export class GlobalHeaderComponent implements OnInit { 45 | 46 | @Input() isMobile: boolean; 47 | @Input() logo: TemplateRef | string; 48 | @Input() collapsed: boolean; 49 | @Input() collapsedButtonRender: TemplateRef; 50 | @Input() rightContentRender: TemplateRef; 51 | @Output() collapsedChange: EventEmitter = new EventEmitter(); 52 | 53 | constructor() { 54 | } 55 | 56 | ngOnInit() { 57 | } 58 | 59 | toggle() { 60 | this.collapsedChange.emit(!this.collapsed); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /components/layout/grid-content.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'pro-grid-content', 5 | template: ` 6 |
7 | 8 |
9 | `, 10 | changeDetection: ChangeDetectionStrategy.OnPush, 11 | encapsulation: ViewEncapsulation.None, 12 | exportAs: 'proGridContent', 13 | preserveWhitespaces: false 14 | }) 15 | export class GridContentComponent implements OnInit { 16 | 17 | @Input() contentWidth: 'Fluid' | 'Fixed'; 18 | 19 | constructor() { 20 | } 21 | 22 | ngOnInit() { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /components/layout/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-api'; 2 | -------------------------------------------------------------------------------- /components/layout/layout.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {BaseMenuComponent} from './base-menu.component'; 4 | import {BasicLayoutComponent} from './basic-layout.component'; 5 | import {GlobalHeaderComponent} from './global-header.component'; 6 | import {GridContentComponent} from './grid-content.component'; 7 | import {TopNavHeaderComponent} from './top-nav-header.component'; 8 | import {GlobalFooterComponent} from './global-footer.component'; 9 | import {NzLayoutModule} from 'ng-zorro-antd/layout'; 10 | import {NzMenuModule} from 'ng-zorro-antd/menu'; 11 | import {NzIconModule} from 'ng-zorro-antd/icon'; 12 | import {RouterModule} from "@angular/router"; 13 | import {NzDrawerModule} from 'ng-zorro-antd/drawer'; 14 | import {NzPageHeaderModule} from 'ng-zorro-antd/page-header'; 15 | import {NzTabsModule} from 'ng-zorro-antd/tabs'; 16 | import {NzBreadCrumbModule} from 'ng-zorro-antd/breadcrumb'; 17 | import {NzOutletModule} from 'ng-zorro-antd/core/outlet'; 18 | import {DelonACLModule} from "@delon/acl"; 19 | import {TranslateModule} from "@ngx-translate/core"; 20 | import {PageHeaderWrapperComponent} from "./page-header-wrapper.component"; 21 | 22 | const Layouts = [ 23 | GlobalHeaderComponent, 24 | BasicLayoutComponent, 25 | GridContentComponent, 26 | TopNavHeaderComponent, 27 | GlobalFooterComponent, 28 | BaseMenuComponent, 29 | PageHeaderWrapperComponent 30 | ]; 31 | 32 | @NgModule({ 33 | imports: [ 34 | CommonModule, 35 | RouterModule, 36 | 37 | NzOutletModule, 38 | NzLayoutModule, 39 | NzMenuModule, 40 | NzIconModule, 41 | NzDrawerModule, 42 | NzPageHeaderModule, 43 | NzTabsModule, 44 | NzBreadCrumbModule, 45 | DelonACLModule, 46 | TranslateModule, 47 | ], 48 | exports: [ 49 | ...Layouts 50 | ], 51 | declarations: [ 52 | ...Layouts 53 | ], 54 | providers: [], 55 | }) 56 | export class LayoutModule { 57 | } 58 | -------------------------------------------------------------------------------- /components/layout/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "ngPackage": { 3 | "lib": { 4 | "entryFile": "public-api.ts" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /components/layout/public-api.ts: -------------------------------------------------------------------------------- 1 | export * from './base-menu.component'; 2 | export * from './basic-layout.component'; 3 | export * from './global-footer.component'; 4 | export * from './global-header.component'; 5 | export * from './grid-content.component'; 6 | export * from './top-nav-header.component'; 7 | export * from './layout.module'; 8 | -------------------------------------------------------------------------------- /components/layout/style/basic-layout.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @basicLayout-prefix-cls: ~'@{ant-prefix}-pro-basicLayout-content'; 4 | 5 | .@{basicLayout-prefix-cls} { 6 | margin: 24px; 7 | padding-top: @layout-header-height; 8 | } 9 | 10 | .basicLayout { 11 | .ant-layout { 12 | transition: all 0.2s; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /components/layout/style/entry.less: -------------------------------------------------------------------------------- 1 | @import 'base-menu.less'; 2 | @import 'basic-layout.less'; 3 | @import 'global-footer.less'; 4 | @import 'global-header.less'; 5 | @import 'grid-content.less'; 6 | @import 'header.less'; 7 | @import 'page-header-wrapper.less'; 8 | @import 'top-nav-header.less'; 9 | -------------------------------------------------------------------------------- /components/layout/style/global-footer.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @global-footer-prefix-cls: ~'@{ant-prefix}-pro-global-footer'; 4 | 5 | .@{global-footer-prefix-cls} { 6 | margin: 48px 0 24px 0; 7 | padding: 0 16px; 8 | text-align: center; 9 | 10 | &-links { 11 | margin-bottom: 8px; 12 | 13 | a { 14 | color: @text-color-secondary; 15 | transition: all 0.3s; 16 | 17 | &:not(:last-child) { 18 | margin-right: 40px; 19 | } 20 | 21 | &:hover { 22 | color: @text-color; 23 | } 24 | } 25 | } 26 | 27 | &-copyright { 28 | color: @text-color-secondary; 29 | font-size: @font-size-base; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /components/layout/style/global-header.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | @global-header-prefix-cls: ~'@{ant-prefix}-pro-global-header'; 3 | 4 | @pro-header-bg: @component-background; 5 | @pro-header-hover-bg: @component-background; 6 | @pro-header-box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08); 7 | 8 | .@{global-header-prefix-cls} { 9 | position: relative; 10 | height: @layout-header-height; 11 | padding: 0; 12 | background: @pro-header-bg; 13 | box-shadow: @pro-header-box-shadow; 14 | 15 | &-logo { 16 | display: inline-block; 17 | height: @layout-header-height; 18 | padding: 0 0 0 24px; 19 | font-size: 20px; 20 | line-height: @layout-header-height; 21 | vertical-align: top; 22 | cursor: pointer; 23 | img { 24 | display: inline-block; 25 | width: 32px; 26 | vertical-align: middle; 27 | } 28 | } 29 | 30 | &-menu { 31 | .anticon { 32 | margin-right: 8px; 33 | } 34 | .ant-dropdown-menu-item { 35 | min-width: 160px; 36 | } 37 | } 38 | 39 | &-trigger { 40 | height: @layout-header-height; 41 | padding: ~'calc((@{layout-header-height} - 26px) / 2)' 24px; 42 | font-size: 20px; 43 | cursor: pointer; 44 | transition: all 0.3s, padding 0s; 45 | &:hover { 46 | background: @pro-header-hover-bg; 47 | } 48 | } 49 | 50 | .dark { 51 | height: @layout-header-height; 52 | .action { 53 | color: rgba(255, 255, 255, 0.85); 54 | > i { 55 | color: rgba(255, 255, 255, 0.85); 56 | } 57 | &:hover, 58 | &.opened { 59 | background: @primary-color; 60 | } 61 | .ant-badge { 62 | color: rgba(255, 255, 255, 0.85); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /components/layout/style/grid-content.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @grid-content-prefix-cls: ~'@{ant-prefix}-pro-grid-content'; 4 | 5 | .@{grid-content-prefix-cls} { 6 | width: 100%; 7 | height: 100%; 8 | min-height: 100%; 9 | transition: 0.3s; 10 | &.wide { 11 | max-width: 1200px; 12 | margin: 0 auto; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /components/layout/style/header.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @fixed-header-prefix-cls: ~'@{ant-prefix}-pro-fixed-header'; 4 | 5 | .@{fixed-header-prefix-cls} { 6 | position: fixed; 7 | top: 0; 8 | right: 0; 9 | z-index: 9; 10 | width: 100%; 11 | transition: width 0.2s; 12 | } 13 | -------------------------------------------------------------------------------- /components/layout/style/page-header-wrapper.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @ant-pro-page-header-wrap: ~'@{ant-prefix}-pro-page-header-wrap'; 4 | 5 | .@{ant-pro-page-header-wrap}-children-content { 6 | margin: 24px 24px 0; 7 | } 8 | 9 | .@{ant-pro-page-header-wrap}-page-header-warp { 10 | background-color: @component-background; 11 | } 12 | 13 | .@{ant-pro-page-header-wrap}-main { 14 | .@{ant-pro-page-header-wrap}-detail { 15 | display: flex; 16 | } 17 | 18 | .@{ant-pro-page-header-wrap}-row { 19 | display: flex; 20 | width: 100%; 21 | } 22 | 23 | .@{ant-pro-page-header-wrap}-title-content { 24 | margin-bottom: 16px; 25 | } 26 | 27 | .@{ant-pro-page-header-wrap}-title, 28 | .@{ant-pro-page-header-wrap}-content { 29 | flex: auto; 30 | } 31 | 32 | .@{ant-pro-page-header-wrap}-extraContent, 33 | .@{ant-pro-page-header-wrap}-main { 34 | flex: 0 1 auto; 35 | } 36 | 37 | .@{ant-pro-page-header-wrap}-main { 38 | width: 100%; 39 | } 40 | 41 | .@{ant-pro-page-header-wrap}-title { 42 | margin-bottom: 16px; 43 | } 44 | 45 | .@{ant-pro-page-header-wrap}-logo { 46 | margin-bottom: 16px; 47 | } 48 | 49 | .@{ant-pro-page-header-wrap}-extraContent { 50 | min-width: 242px; 51 | margin-left: 88px; 52 | text-align: right; 53 | } 54 | } 55 | 56 | @media screen and (max-width: @screen-xl) { 57 | .@{ant-pro-page-header-wrap}-main { 58 | .@{ant-pro-page-header-wrap}-extraContent { 59 | margin-left: 44px; 60 | } 61 | } 62 | } 63 | 64 | @media screen and (max-width: @screen-lg) { 65 | .@{ant-pro-page-header-wrap}-main { 66 | .@{ant-pro-page-header-wrap}-extraContent { 67 | margin-left: 20px; 68 | } 69 | } 70 | } 71 | 72 | @media screen and (max-width: @screen-md) { 73 | .@{ant-pro-page-header-wrap}-main { 74 | .@{ant-pro-page-header-wrap}-row { 75 | display: block; 76 | } 77 | 78 | .@{ant-pro-page-header-wrap}-action, 79 | .@{ant-pro-page-header-wrap}-extraContent { 80 | margin-left: 0; 81 | text-align: left; 82 | } 83 | } 84 | } 85 | 86 | @media screen and (max-width: @screen-sm) { 87 | .@{ant-pro-page-header-wrap}-detail { 88 | display: block; 89 | } 90 | .@{ant-pro-page-header-wrap}-extraContent { 91 | margin-left: 0; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /components/layout/style/top-nav-header.less: -------------------------------------------------------------------------------- 1 | @import "~ng-zorro-antd/style/themes/index"; 2 | 3 | @top-nav-header-prefix-cls: ~'@{ant-prefix}-pro-top-nav-header'; 4 | 5 | .@{top-nav-header-prefix-cls} { 6 | position: relative; 7 | width: 100%; 8 | height: @layout-header-height; 9 | box-shadow: @box-shadow-base; 10 | transition: background 0.3s, width 0.2s; 11 | .ant-menu-submenu.ant-menu-submenu-horizontal { 12 | height: 100%; 13 | line-height: @layout-header-height; 14 | .ant-menu-submenu-title { 15 | height: 100%; 16 | } 17 | } 18 | 19 | &.light { 20 | background-color: @component-background; 21 | h1 { 22 | color: #002140; 23 | } 24 | } 25 | 26 | &-main { 27 | display: flex; 28 | height: @layout-header-height; 29 | padding-left: 24px; 30 | &.wide { 31 | max-width: 1200px; 32 | margin: auto; 33 | padding-left: 0; 34 | } 35 | .left { 36 | display: flex; 37 | flex: 1; 38 | } 39 | .right { 40 | width: 324px; 41 | } 42 | } 43 | 44 | &-logo { 45 | position: relative; 46 | width: 165px; 47 | height: @layout-header-height; 48 | overflow: hidden; 49 | line-height: @layout-header-height; 50 | transition: all 0.3s; 51 | img { 52 | display: inline-block; 53 | height: 32px; 54 | vertical-align: middle; 55 | } 56 | h1 { 57 | display: inline-block; 58 | margin: 0 0 0 12px; 59 | color: @btn-primary-color; 60 | font-weight: 400; 61 | font-size: 16px; 62 | vertical-align: top; 63 | } 64 | } 65 | &-menu { 66 | .ant-menu.ant-menu-horizontal { 67 | height: @layout-header-height; 68 | line-height: @layout-header-height; 69 | border: none; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /components/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../dist/publish", 4 | "deleteDestPath": true, 5 | "lib": { 6 | "entryFile": "public-api.ts", 7 | "umdModuleIds": { 8 | "ng-zorro-antd": "ng-zorro-antd", 9 | "@ngx-translate/core": "@ngx-translate/core" 10 | } 11 | }, 12 | "allowedNonPeerDependencies": [], 13 | "assets": [ 14 | "ng-zorro-pro.less", 15 | "components.less", 16 | "./*/style/*.less" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /components/ng-zorro-pro.less: -------------------------------------------------------------------------------- 1 | @import "layout/style/entry.less"; 2 | @import "reuse-tab/style/entry.less"; 3 | -------------------------------------------------------------------------------- /components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pro-layout", 3 | "version": "0.0.38", 4 | "dependencies": { 5 | "tslib": "^2.0.0" 6 | }, 7 | "peerDependencies": { 8 | "@angular/common": "^10.0.0", 9 | "@angular/core": "^10.0.0", 10 | "ng-zorro-antd": "^11.0.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /components/public-api.ts: -------------------------------------------------------------------------------- 1 | export * from './layout/index'; 2 | export * from './reuse-tab/index'; 3 | 4 | -------------------------------------------------------------------------------- /components/reuse-tab/index.ts: -------------------------------------------------------------------------------- 1 | export * from './public-api'; 2 | -------------------------------------------------------------------------------- /components/reuse-tab/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "ngPackage": { 3 | "lib": { 4 | "entryFile": "public-api.ts" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /components/reuse-tab/public-api.ts: -------------------------------------------------------------------------------- 1 | export * from './reuse-tab.component'; 2 | export * from './reuse-tab.strategy'; 3 | export * from './reuse-tab.service'; 4 | export * from './reuse-tab.module'; 5 | export * from './reuse-tab.interface'; 6 | export * from './reuse-tab-menu.component'; 7 | export * from './reuse-tab-menu.service'; 8 | export * from './scroll.service'; 9 | -------------------------------------------------------------------------------- /components/reuse-tab/reuse-tab.interface.ts: -------------------------------------------------------------------------------- 1 | import {ActivatedRouteSnapshot, Params} from '@angular/router'; 2 | 3 | export interface ReuseTitle { 4 | name?: string; 5 | locale?: string; 6 | } 7 | 8 | export interface ReuseTabCached { 9 | title: ReuseTitle; 10 | url: string; 11 | /** 是否允许关闭,默认:`true` */ 12 | closable?: boolean; 13 | /** 是否允许刷新,默认:`true` */ 14 | refreshable?: boolean; 15 | /** 当前滚动条位置 */ 16 | position?: [number, number] | null; 17 | _snapshot: ActivatedRouteSnapshot; 18 | _handle: ReuseComponentHandle; 19 | } 20 | 21 | export interface ReuseTabNotify { 22 | /** 事件类型 */ 23 | active: 'add' | 'override' | 'title' | 'clear' | 'closable' | 'close' | 'closeRight' | 'move' | 'refresh'; 24 | url?: string; 25 | queryParams?: Params; 26 | title?: ReuseTitle; 27 | item?: ReuseTabCached; 28 | list?: ReuseTabCached[]; 29 | 30 | [key: string]: any; 31 | } 32 | 33 | export interface ReuseItem { 34 | url: string; 35 | queryParams: Params | null; 36 | title?: string; 37 | closable?: boolean; 38 | refreshable?: boolean; 39 | index?: number; 40 | active?: boolean; 41 | last?: boolean; 42 | } 43 | 44 | export interface ReuseContextEvent { 45 | event: MouseEvent; 46 | item: ReuseItem; 47 | } 48 | 49 | export type CloseType = 'close' | 'closeOther' | 'closeRight' | 'refresh' | null; 50 | 51 | export interface ReuseContextCloseEvent { 52 | type: CloseType; 53 | item: ReuseItem; 54 | includeNonCloseable: boolean; 55 | } 56 | 57 | export interface ReuseComponentHandle { 58 | componentRef: ReuseComponentRef; 59 | } 60 | 61 | export interface ReuseComponentRef { 62 | instance: ReuseComponentInstance; 63 | } 64 | 65 | export type ReuseHookTypes = 'onReuseInit' | 'onReuseDestroy'; 66 | 67 | export type ReuseHookOnReuseInitType = 'init' | 'refresh'; 68 | 69 | export interface ReuseComponentInstance { 70 | /** 再次进入标签页时触发,有2中类型init和refresh **/ 71 | onReuseInit: (type: ReuseHookOnReuseInitType) => void; 72 | /** 标签页离开时触发 **/ 73 | onReuseDestroy: () => void; 74 | destroy: () => void; 75 | } 76 | -------------------------------------------------------------------------------- /components/reuse-tab/reuse-tab.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {ReuseTabMenuComponent} from "./reuse-tab-menu.component"; 4 | import {ReuseTabComponent} from "./reuse-tab.component"; 5 | import {CommonModule} from "@angular/common"; 6 | import {RouterModule} from "@angular/router"; 7 | import {NzMenuModule} from "ng-zorro-antd/menu"; 8 | import {NzTabsModule} from "ng-zorro-antd/tabs"; 9 | 10 | @NgModule({ 11 | imports: [CommonModule, RouterModule, NzMenuModule, NzTabsModule], 12 | exports: [ReuseTabComponent], 13 | declarations: [ReuseTabMenuComponent, ReuseTabComponent], 14 | entryComponents: [ReuseTabMenuComponent], 15 | }) 16 | export class ReuseTabModule { 17 | } 18 | -------------------------------------------------------------------------------- /components/reuse-tab/reuse-tab.strategy.ts: -------------------------------------------------------------------------------- 1 | import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router'; 2 | import { ReuseTabService } from './reuse-tab.service'; 3 | 4 | export class ReuseTabStrategy implements RouteReuseStrategy { 5 | constructor(private reuseTabService: ReuseTabService) {} 6 | 7 | /** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */ 8 | shouldDetach(route: ActivatedRouteSnapshot): boolean { 9 | return this.reuseTabService.shouldDetach(route); 10 | } 11 | /** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */ 12 | store(route: ActivatedRouteSnapshot,handle: DetachedRouteHandle | null): void { 13 | this.reuseTabService.store(route, handle); 14 | } 15 | /** 若 path 在缓存中有的都认为允许还原路由 */ 16 | shouldAttach(route: ActivatedRouteSnapshot): boolean { 17 | return this.reuseTabService.shouldAttach(route); 18 | } 19 | /** 从缓存中获取快照,若无则返回nul */ 20 | retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { 21 | return this.reuseTabService.retrieve(route); 22 | } 23 | /** 进入路由触发,判断是否同一路由 */ 24 | shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { 25 | return this.reuseTabService.shouldReuseRoute(future, curr); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /components/reuse-tab/scroll.service.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from '@angular/cdk/platform'; 2 | import { DOCUMENT } from '@angular/common'; 3 | import { Inject, Injectable } from '@angular/core'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class ScrollService { 7 | private _getDoc(): Document { 8 | return this._doc || document; 9 | } 10 | 11 | private _getWin(): Window { 12 | const doc = this._getDoc(); 13 | return doc.defaultView || window; 14 | } 15 | 16 | constructor(@Inject(DOCUMENT) private _doc: any, private platform: Platform) {} 17 | 18 | /** 19 | * 获取滚动条位置 20 | * @param element 指定元素,默认 `window` 21 | */ 22 | getScrollPosition(element?: Element | Window): [number, number] { 23 | if (!this.platform.isBrowser) { 24 | return [0, 0]; 25 | } 26 | 27 | const win = this._getWin(); 28 | if (element && element !== win) { 29 | return [(element as Element).scrollLeft, (element as Element).scrollTop]; 30 | } else { 31 | return [win.pageXOffset, win.pageYOffset]; 32 | } 33 | } 34 | 35 | /** 36 | * 设置滚动条位置 37 | * @param element 指定元素 38 | */ 39 | scrollToPosition(element: Element | Window | null | undefined, position: [number, number]): void { 40 | if (!this.platform.isBrowser) { 41 | return; 42 | } 43 | (element || this._getWin()).scrollTo(position[0], position[1]); 44 | } 45 | 46 | /** 47 | * 设置滚动条至指定元素 48 | * @param element 指定元素,默认 `document.body` 49 | * @param topOffset 偏移值,默认 `0` 50 | */ 51 | scrollToElement(element?: Element | null, topOffset: number = 0): void { 52 | if (!this.platform.isBrowser) { 53 | return; 54 | } 55 | if (!element) { 56 | element = this._getDoc().body; 57 | } 58 | 59 | element.scrollIntoView(); 60 | 61 | const win = this._getWin(); 62 | if (win && win.scrollBy) { 63 | win.scrollBy(0, element!.getBoundingClientRect().top - topOffset); 64 | 65 | if (win.pageYOffset < 20) { 66 | win.scrollBy(0, -win.pageYOffset); 67 | } 68 | } 69 | } 70 | 71 | /** 72 | * 滚动至顶部 73 | * @param topOffset 偏移值,默认 `0` 74 | */ 75 | scrollToTop(topOffset: number = 0): void { 76 | if (!this.platform.isBrowser) { 77 | return; 78 | } 79 | this.scrollToElement(this._getDoc().body, topOffset); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /components/reuse-tab/style/entry.less: -------------------------------------------------------------------------------- 1 | @import 'index.less'; 2 | -------------------------------------------------------------------------------- /components/reuse-tab/style/index.less: -------------------------------------------------------------------------------- 1 | @ant-prefix: ant; 2 | @ant-pro-reuse-tab: ~'.@{ant-prefix}-pro-reuse-tab'; 3 | @reuse-tab-bg: #f5f7f9; 4 | @reuse-tab-height: 46px; 5 | @reuse-tab-padding: 6px; 6 | @reuse-tab-border-color: #d9d9d9; 7 | 8 | @reuse-tabs-card-gutter: 6px; 9 | 10 | @{ant-pro-reuse-tab} { 11 | display: block; 12 | background-color: @reuse-tab-bg; 13 | outline: none; 14 | user-select: none; 15 | padding: @reuse-tab-padding; 16 | 17 | .@{ant-prefix}-tabs { 18 | 19 | .@{ant-prefix}-tabs-bar { 20 | margin: 0; 21 | border-bottom: 0; 22 | } 23 | 24 | > .@{ant-prefix}-tabs-nav { 25 | 26 | margin: 0; 27 | 28 | .@{ant-prefix}-tabs-tab { 29 | border: transparent; 30 | border-radius: 4px !important; 31 | background: #fff; 32 | padding: 6px 12px !important; 33 | } 34 | 35 | .@{ant-prefix}-tabs-tab:not(:last-of-type){ 36 | margin-right: @reuse-tabs-card-gutter !important; 37 | } 38 | 39 | &::before { 40 | border-bottom: transparent; 41 | } 42 | } 43 | 44 | .@{ant-prefix}-tabs-tab-remove { 45 | margin: 0; 46 | padding-right: 0px; 47 | } 48 | 49 | .@{ant-prefix}-tabs-nav-more{ 50 | background: #fff!important; 51 | } 52 | } 53 | } 54 | 55 | @{ant-pro-reuse-tab}-cm { 56 | .@{ant-prefix}-menu { 57 | border: 1px solid #f7f5f5; 58 | 59 | &-item { 60 | height: 24px; 61 | line-height: 24px; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /components/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone'; 4 | import 'zone.js/dist/zone-testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: any; 12 | 13 | // First, initialize the Angular testing environment. 14 | getTestBed().initTestEnvironment( 15 | BrowserDynamicTestingModule, 16 | platformBrowserDynamicTesting() 17 | ); 18 | // Then we find all the tests. 19 | const context = require.context('./', true, /\.spec\.ts$/); 20 | // And load the modules. 21 | context.keys().map(context); 22 | -------------------------------------------------------------------------------- /components/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "../out-tsc/lib", 6 | "declarationMap": true, 7 | "target": "es2015", 8 | "declaration": true, 9 | "inlineSources": true, 10 | "types": [], 11 | "lib": [ 12 | "dom", 13 | "es2018" 14 | ] 15 | }, 16 | "angularCompilerOptions": { 17 | "skipTemplateCodegen": true, 18 | "strictMetadataEmit": true, 19 | "enableResourceInlining": true 20 | }, 21 | "exclude": [ 22 | "./test.ts", 23 | "**/*.spec.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /components/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "enableIvy": false 8 | } 9 | } -------------------------------------------------------------------------------- /components/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "./test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /components/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "pro", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "pro", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | 'browserName': 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to ant-design-pro-angular!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es2018", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/ant-design-pro-angular'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/acl/acl-guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, CanLoad, Route, Router, RouterStateSnapshot, Data } from '@angular/router'; 3 | import { of, Observable } from 'rxjs'; 4 | import { map, tap } from 'rxjs/operators'; 5 | 6 | import { DelonACLConfig } from './acl.config'; 7 | import { ACLService } from './acl.service'; 8 | import { ACLCanType } from './acl.type'; 9 | 10 | /** 11 | * Routing guard prevent unauthorized users visit the page, [ACL Document](https://ng-alain.com/acl). 12 | * 13 | * ```ts 14 | * data: { 15 | * path: 'home', 16 | * canActivate: [ ACLGuard ], 17 | * data: { guard: 'user1' } 18 | * } 19 | * ``` 20 | */ 21 | @Injectable({ providedIn: 'root' }) 22 | export class ACLGuard implements CanActivate, CanActivateChild, CanLoad { 23 | constructor(private srv: ACLService, private router: Router, private options: DelonACLConfig) { } 24 | 25 | private process(data: Data): Observable { 26 | data = { 27 | guard: null, 28 | guard_url: this.options.guard_url, 29 | ...data, 30 | }; 31 | const guard: ACLCanType | Observable = data.guard; 32 | return (guard && guard instanceof Observable ? guard : of(guard != null ? (guard as ACLCanType) : null)).pipe( 33 | map(v => this.srv.can(v)), 34 | tap(v => { 35 | if (v) return; 36 | this.router.navigateByUrl(data.guard_url); 37 | }), 38 | ); 39 | } 40 | 41 | // lazy loading 42 | canLoad(route: Route): Observable { 43 | return this.process(route.data!); 44 | } 45 | // all children route 46 | canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { 47 | return this.canActivate(childRoute, state); 48 | } 49 | // route 50 | canActivate(route: ActivatedRouteSnapshot, _state: RouterStateSnapshot | null): Observable { 51 | return this.process(route.data); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/app/acl/acl.config.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ACLCanType, ACLType } from './acl.type'; 3 | 4 | @Injectable({ providedIn: 'root' }) 5 | export class DelonACLConfig { 6 | /** 7 | * Router URL when guard fail, default: `/403` 8 | */ 9 | guard_url?: string = '/403'; 10 | 11 | /** 12 | * `can` before execution callback 13 | */ 14 | preCan?: ((roleOrAbility: ACLCanType) => ACLType | null) | null; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/acl/acl.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component, DebugElement } from '@angular/core'; 2 | import { ComponentFixture, ComponentFixtureAutoDetect, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | 5 | import { DelonACLModule } from './acl.module'; 6 | import { ACLService } from './acl.service'; 7 | 8 | const CLS = 'acl__hide'; 9 | describe('acl: directive', () => { 10 | let fixture: ComponentFixture; 11 | let context: TestComponent; 12 | let dl: DebugElement; 13 | 14 | beforeEach(() => { 15 | TestBed.configureTestingModule({ 16 | declarations: [TestComponent], 17 | imports: [DelonACLModule.forRoot()], 18 | providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }], 19 | }); 20 | fixture = TestBed.createComponent(TestComponent); 21 | dl = fixture.debugElement; 22 | context = dl.componentInstance; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should show when full', () => { 27 | context.srv.setFull(true); 28 | context.role = 'user'; 29 | fixture.detectChanges(); 30 | expect(dl.queryAll(By.css('.' + CLS)).length).toBe(0); 31 | }); 32 | 33 | it('should hide when not full', () => { 34 | context.srv.setFull(false); 35 | context.role = 'user'; 36 | fixture.detectChanges(); 37 | expect(dl.queryAll(By.css('.' + CLS)).length).toBe(1); 38 | }); 39 | 40 | it('should show when ability', () => { 41 | context.srv.setAbility([1, 2, 3]); 42 | context.ability = 2; 43 | fixture.detectChanges(); 44 | expect(dl.queryAll(By.css('.' + CLS)).length).toBe(0); 45 | }); 46 | 47 | it('should hide when not ability', () => { 48 | context.srv.setAbility([1, 2, 3]); 49 | context.ability = 4; 50 | fixture.detectChanges(); 51 | expect(dl.queryAll(By.css('.' + CLS)).length).toBe(1); 52 | }); 53 | }); 54 | 55 | @Component({ 56 | template: ` 57 | 58 | `, 59 | }) 60 | class TestComponent { 61 | role = 'admin'; 62 | ability = 1; 63 | constructor(public srv: ACLService) {} 64 | } 65 | -------------------------------------------------------------------------------- /src/app/acl/acl.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, Input, OnDestroy, Renderer2 } from '@angular/core'; 2 | import { Subscription } from 'rxjs'; 3 | import { filter } from 'rxjs/operators'; 4 | import { ACLService } from './acl.service'; 5 | import { ACLCanType } from './acl.type'; 6 | 7 | @Directive({ 8 | selector: '[acl]', 9 | exportAs: 'acl', 10 | }) 11 | export class ACLDirective implements OnDestroy { 12 | private _value: ACLCanType; 13 | private change$: Subscription; 14 | 15 | @Input('acl') 16 | set acl(value: ACLCanType) { 17 | this.set(value); 18 | } 19 | 20 | @Input('acl-ability') 21 | set ability(value: ACLCanType) { 22 | this.set(this.srv.parseAbility(value)); 23 | } 24 | 25 | private set(value: ACLCanType) { 26 | this._value = value; 27 | const CLS = 'acl__hide'; 28 | const el = this.el.nativeElement; 29 | if (this.srv.can(this._value)) { 30 | this.renderer.removeClass(el, CLS); 31 | } else { 32 | this.renderer.addClass(el, CLS); 33 | } 34 | } 35 | 36 | constructor(private el: ElementRef, private renderer: Renderer2, protected srv: ACLService) { 37 | this.change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this.set(this._value)); 38 | } 39 | 40 | ngOnDestroy(): void { 41 | this.change$.unsubscribe(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/app/acl/acl.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule, ModuleWithProviders } from '@angular/core'; 3 | import { DelonUtilModule } from '@delon/util'; 4 | 5 | import { ACLIfDirective } from './acl-if.directive'; 6 | import { ACLDirective } from './acl.directive'; 7 | import { ACLService } from './acl.service'; 8 | 9 | const COMPONENTS = [ACLDirective, ACLIfDirective]; 10 | 11 | @NgModule({ 12 | imports: [CommonModule, DelonUtilModule], 13 | declarations: [...COMPONENTS], 14 | exports: [...COMPONENTS], 15 | }) 16 | export class DelonACLModule { 17 | static forRoot(): ModuleWithProviders { 18 | return { 19 | ngModule: DelonACLModule, 20 | providers: [ACLService], 21 | }; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/acl/acl.type.ts: -------------------------------------------------------------------------------- 1 | export interface ACLType { 2 | /** 3 | * 角色 4 | */ 5 | role?: string[]; 6 | /** 7 | * 权限点 8 | */ 9 | ability?: number[] | string[]; 10 | 11 | /** 12 | * 校验模式,默认:`oneOf` 13 | * - `allOf` 表示必须满足所有角色或权限点数组算有效 14 | * - `oneOf` 表示只须满足角色或权限点数组中的一项算有效 15 | */ 16 | mode?: 'allOf' | 'oneOf'; 17 | 18 | /** 19 | * 是否取反,即结果为 `true` 时表示未授权 20 | */ 21 | except?: boolean; 22 | 23 | [key: string]: any; 24 | } 25 | 26 | export type ACLCanType = number | number[] | string | string[] | ACLType; 27 | -------------------------------------------------------------------------------- /src/app/acl/index.ts: -------------------------------------------------------------------------------- 1 | export * from './acl.service'; 2 | export * from './acl-if.directive'; 3 | export * from './acl.directive'; 4 | export * from './acl.config'; 5 | export * from './acl.type'; 6 | export * from './acl-guard'; 7 | export * from './acl.module'; 8 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit, Renderer2} from '@angular/core'; 2 | import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; 3 | import {filter, map, mergeMap} from "rxjs/operators"; 4 | import {Title} from "@angular/platform-browser"; 5 | import {HttpClient} from "@angular/common/http"; 6 | import {ReuseTabHistoryService} from "../../components/reuse-tab/reuse-tab-history.service"; 7 | 8 | @Component({ 9 | selector: 'app-root', 10 | template: ` 11 | `, 12 | }) 13 | export class AppComponent implements OnInit { 14 | 15 | constructor(private router: Router, 16 | private activatedRoute: ActivatedRoute, 17 | private renderer: Renderer2, 18 | private httpClient: HttpClient, 19 | private reuseTabHistoryService: ReuseTabHistoryService, 20 | private title: Title) { 21 | } 22 | 23 | ngOnInit() { 24 | // 动态设置title 25 | this.router.events.pipe( 26 | filter(event => event instanceof NavigationEnd), 27 | map(() => this.activatedRoute), 28 | map((route) => { 29 | while (route.firstChild) route = route.firstChild; 30 | return route; 31 | }), 32 | filter((route) => route.outlet === 'primary'), 33 | mergeMap((route) => route.data) 34 | ).subscribe((event) => { 35 | this.title.setTitle(event['name'] + ' - ' + 'Ant Design Pro'); 36 | console.log(`==tabStack== ${this.reuseTabHistoryService.toString()}`); 37 | }); 38 | 39 | if (false) { 40 | this.renderer.addClass(document.body, 'colorWeak'); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {APP_INITIALIZER, NgModule} from '@angular/core'; 3 | import {AppComponent} from './app.component'; 4 | import {HttpClientModule} from '@angular/common/http'; 5 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 6 | import {registerLocaleData} from '@angular/common'; 7 | import zh from '@angular/common/locales/zh'; 8 | import {SharedModule} from './shared/shared.module'; 9 | import {DelonACLModule} from "@delon/acl"; 10 | import {DelonAuthModule} from "@delon/auth"; 11 | import {TranslateModule} from "@ngx-translate/core"; 12 | import {StartupService} from "./core/startup/startup.service"; 13 | import {AppRoutingModule} from "./app-routing.module"; 14 | import {UserModule} from "./pages/user/user.module"; 15 | import {DelonMockModule} from "@delon/mock"; 16 | import * as MOCKDATA from '../../_mock'; 17 | import {RouteReuseStrategy} from "@angular/router"; 18 | import {ReuseTabStrategy} from "pro-layout"; 19 | import {ReuseTabService} from "pro-layout"; 20 | import {ALAIN_CONFIG, AlainConfig} from "@delon/util"; 21 | 22 | 23 | export function StartupServiceFactory(startupService: StartupService) { 24 | return () => startupService.init(); 25 | } 26 | 27 | registerLocaleData(zh); 28 | 29 | const alainConfig: AlainConfig = { 30 | mock: {data: MOCKDATA}, 31 | }; 32 | 33 | @NgModule({ 34 | declarations: [ 35 | AppComponent, 36 | ], 37 | entryComponents: [], 38 | imports: [ 39 | BrowserModule, 40 | BrowserAnimationsModule, 41 | HttpClientModule, 42 | 43 | SharedModule, 44 | DelonAuthModule, 45 | DelonACLModule.forRoot(), 46 | TranslateModule.forRoot(), 47 | AppRoutingModule, 48 | 49 | // pages 50 | UserModule, 51 | 52 | // mock 53 | DelonMockModule.forRoot() 54 | ], 55 | providers: [ 56 | StartupService, 57 | {provide: APP_INITIALIZER, useFactory: StartupServiceFactory, deps: [StartupService], multi: true,}, 58 | {provide: RouteReuseStrategy, useClass: ReuseTabStrategy, deps: [ReuseTabService]}, 59 | {provide: ALAIN_CONFIG, useValue: alainConfig} 60 | ], 61 | bootstrap: [AppComponent] 62 | }) 63 | export class AppModule { 64 | } 65 | -------------------------------------------------------------------------------- /src/app/core/i18n/i18n.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: "root" 5 | }) 6 | export class ProI18nService { 7 | 8 | 9 | constructor() { 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/core/startup/startup.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {ACLService} from "@delon/acl"; 3 | import {HttpClient} from "@angular/common/http"; 4 | import {TranslateService} from "@ngx-translate/core"; 5 | import {default as pro_zh_CN} from '../../locales/zh-CN'; 6 | 7 | 8 | @Injectable() 9 | export class StartupService { 10 | 11 | constructor(private httpClient: HttpClient, 12 | private aclService: ACLService, 13 | private translateService: TranslateService) { 14 | } 15 | 16 | init(): Promise { 17 | return new Promise(resolve => { 18 | // this.httpClient.get().subscribe( 19 | // ()=>{ 20 | // this.translateService.setTranslation('en_US',en_US_PRO); 21 | // this.translateService.setDefaultLang('en_US') 22 | // }, 23 | // ()=>{}, 24 | // ()=>{resolve(null);}) 25 | 26 | this.translateService.setTranslation('zh-CN', pro_zh_CN); 27 | this.translateService.setDefaultLang('zh-CN'); 28 | this.aclService.setAbility([1, 2]) 29 | resolve(null) 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/app/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | import globalHeader from './en-US/globalHeader'; 2 | import menu from './en-US/menu'; 3 | import settingDrawer from './en-US/settingDrawer'; 4 | import settings from './en-US/settings'; 5 | import pwa from './en-US/pwa'; 6 | import component from './en-US/component'; 7 | import pageLogin from '../pages/user/login/locales/en-US'; 8 | import pageRegister from '../pages/user/register/locales/en-US'; 9 | import pageRegisterResult from '../pages/user/register-result/locales/en-US'; 10 | import pageExceptiont403 from '../pages/exception/403/locales/en-US'; 11 | import pageExceptiont404 from '../pages/exception/404/locales/en-US'; 12 | import pageExceptiont500 from '../pages/exception/500/locales/en-US'; 13 | 14 | 15 | export default { 16 | 'navBar.lang': 'Languages', 17 | 'layout.user.link.help': 'Help', 18 | 'layout.user.link.privacy': 'Privacy', 19 | 'layout.user.link.terms': 'Terms', 20 | 'app.preview.down.block': 'Download this page to your local project', 21 | ...globalHeader, 22 | ...menu, 23 | ...settingDrawer, 24 | ...settings, 25 | ...pwa, 26 | ...component, 27 | 28 | ...pageLogin, 29 | ...pageRegister, 30 | ...pageRegisterResult, 31 | ...pageExceptiont403, 32 | ...pageExceptiont404, 33 | ...pageExceptiont500 34 | }; 35 | -------------------------------------------------------------------------------- /src/app/locales/en-US/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': 'Expand', 3 | 'component.tagSelect.collapse': 'Collapse', 4 | 'component.tagSelect.all': 'All', 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/locales/en-US/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': 'Search', 3 | 'component.globalHeader.search.example1': 'Search example 1', 4 | 'component.globalHeader.search.example2': 'Search example 2', 5 | 'component.globalHeader.search.example3': 'Search example 3', 6 | 'component.globalHeader.help': 'Help', 7 | 'component.globalHeader.notification': 'Notification', 8 | 'component.globalHeader.notification.empty': 'You have viewed all notifications.', 9 | 'component.globalHeader.message': 'Message', 10 | 'component.globalHeader.message.empty': 'You have viewed all messsages.', 11 | 'component.globalHeader.event': 'Event', 12 | 'component.globalHeader.event.empty': 'You have viewed all events.', 13 | 'component.noticeIcon.clear': 'Clear', 14 | 'component.noticeIcon.cleared': 'Cleared', 15 | 'component.noticeIcon.empty': 'No notifications', 16 | 'component.noticeIcon.view-more': 'View more', 17 | }; 18 | -------------------------------------------------------------------------------- /src/app/locales/en-US/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': 'Welcome', 3 | 'menu.more-blocks': 'More Blocks', 4 | 'menu.home': 'Home', 5 | 'menu.login': 'Login', 6 | 'menu.register': 'Register', 7 | 'menu.register.result': 'Register Result', 8 | 'menu.dashboard': 'Dashboard', 9 | 'menu.dashboard.analysis': 'Analysis', 10 | 'menu.dashboard.monitor': 'Monitor', 11 | 'menu.dashboard.workplace': 'Workplace', 12 | 'menu.exception.403': '403', 13 | 'menu.exception.404': '404', 14 | 'menu.exception.500': '500', 15 | 'menu.form': 'Form', 16 | 'menu.form.basic-form': 'Basic Form', 17 | 'menu.form.step-form': 'Step Form', 18 | 'menu.form.step-form.info': 'Step Form(write transfer information)', 19 | 'menu.form.step-form.confirm': 'Step Form(confirm transfer information)', 20 | 'menu.form.step-form.result': 'Step Form(finished)', 21 | 'menu.form.advanced-form': 'Advanced Form', 22 | 'menu.list': 'List', 23 | 'menu.list.table-list': 'Search Table', 24 | 'menu.list.basic-list': 'Basic List', 25 | 'menu.list.card-list': 'Card List', 26 | 'menu.list.search-list': 'Search List', 27 | 'menu.list.search-list.articles': 'Search List(articles)', 28 | 'menu.list.search-list.projects': 'Search List(projects)', 29 | 'menu.list.search-list.applications': 'Search List(applications)', 30 | 'menu.profile': 'Profile', 31 | 'menu.profile.basic': 'Basic Profile', 32 | 'menu.profile.advanced': 'Advanced Profile', 33 | 'menu.result': 'Result', 34 | 'menu.result.success': 'Success', 35 | 'menu.result.fail': 'Fail', 36 | 'menu.exception': 'Exception', 37 | 'menu.exception.not-permission': '403', 38 | 'menu.exception.not-find': '404', 39 | 'menu.exception.server-error': '500', 40 | 'menu.exception.trigger': 'Trigger', 41 | 'menu.account': 'Account', 42 | 'menu.account.center': 'Account Center', 43 | 'menu.account.settings': 'Account Settings', 44 | 'menu.account.trigger': 'Trigger Error', 45 | 'menu.account.logout': 'Logout', 46 | 'menu.editor': 'Graphic Editor', 47 | 'menu.editor.flow': 'Flow Editor', 48 | 'menu.editor.mind': 'Mind Editor', 49 | 'menu.editor.koni': 'Koni Editor', 50 | }; 51 | -------------------------------------------------------------------------------- /src/app/locales/en-US/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': 'You are offline now', 3 | 'app.pwa.serviceworker.updated': 'New content is available', 4 | 'app.pwa.serviceworker.updated.hint': 'Please press the "Refresh" button to reload current page', 5 | 'app.pwa.serviceworker.updated.ok': 'Refresh', 6 | }; 7 | -------------------------------------------------------------------------------- /src/app/locales/en-US/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': 'Page style setting', 3 | 'app.setting.pagestyle.dark': 'Dark style', 4 | 'app.setting.pagestyle.light': 'Light style', 5 | 'app.setting.content-width': 'Content Width', 6 | 'app.setting.content-width.fixed': 'Fixed', 7 | 'app.setting.content-width.fluid': 'Fluid', 8 | 'app.setting.themecolor': 'Theme Color', 9 | 'app.setting.themecolor.dust': 'Dust Red', 10 | 'app.setting.themecolor.volcano': 'Volcano', 11 | 'app.setting.themecolor.sunset': 'Sunset Orange', 12 | 'app.setting.themecolor.cyan': 'Cyan', 13 | 'app.setting.themecolor.green': 'Polar Green', 14 | 'app.setting.themecolor.daybreak': 'Daybreak Blue (default)', 15 | 'app.setting.themecolor.geekblue': 'Geek Glue', 16 | 'app.setting.themecolor.purple': 'Golden Purple', 17 | 'app.setting.navigationmode': 'Navigation Mode', 18 | 'app.setting.sidemenu': 'Side Menu Layout', 19 | 'app.setting.topmenu': 'Top Menu Layout', 20 | 'app.setting.fixedheader': 'Fixed Header', 21 | 'app.setting.fixedsidebar': 'Fixed Sidebar', 22 | 'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout', 23 | 'app.setting.hideheader': 'Hidden Header when scrolling', 24 | 'app.setting.hideheader.hint': 'Works when Hidden Header is enabled', 25 | 'app.setting.othersettings': 'Other Settings', 26 | 'app.setting.weakmode': 'Weak Mode', 27 | 'app.setting.copy': 'Copy Setting', 28 | 'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/models/setting.js', 29 | 'app.setting.production.hint': 30 | 'Setting panel shows in development environment only, please manually modify', 31 | }; 32 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR.ts: -------------------------------------------------------------------------------- 1 | import globalHeader from './pt-BR/globalHeader'; 2 | import menu from './pt-BR/menu'; 3 | import settingDrawer from './pt-BR/settingDrawer'; 4 | import settings from './pt-BR/settings'; 5 | import pwa from './pt-BR/pwa'; 6 | import component from './pt-BR/component'; 7 | 8 | import pageExceptiont403 from '../pages/exception/403/locales/pt-BR'; 9 | import pageExceptiont404 from '../pages/exception/404/locales/pt-BR'; 10 | import pageExceptiont500 from '../pages/exception/500/locales/pt-BR'; 11 | 12 | 13 | export default { 14 | 'navBar.lang': 'Idiomas', 15 | 'layout.user.link.help': 'ajuda', 16 | 'layout.user.link.privacy': 'política de privacidade', 17 | 'layout.user.link.terms': 'termos de serviços', 18 | 'app.preview.down.block': 'Download this page to your local project', 19 | ...globalHeader, 20 | ...menu, 21 | ...settingDrawer, 22 | ...settings, 23 | ...pwa, 24 | ...component, 25 | 26 | 27 | ...pageExceptiont403, 28 | ...pageExceptiont404, 29 | ...pageExceptiont500, 30 | }; 31 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': 'Expandir', 3 | 'component.tagSelect.collapse': 'Diminuir', 4 | 'component.tagSelect.all': 'Todas', 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': 'Busca', 3 | 'component.globalHeader.search.example1': 'Exemplo de busca 1', 4 | 'component.globalHeader.search.example2': 'Exemplo de busca 2', 5 | 'component.globalHeader.search.example3': 'Exemplo de busca 3', 6 | 'component.globalHeader.help': 'Ajuda', 7 | 'component.globalHeader.notification': 'Notificação', 8 | 'component.globalHeader.notification.empty': 'Você visualizou todas as notificações.', 9 | 'component.globalHeader.message': 'Mensagem', 10 | 'component.globalHeader.message.empty': 'Você visualizou todas as mensagens.', 11 | 'component.globalHeader.event': 'Evento', 12 | 'component.globalHeader.event.empty': 'Você visualizou todos os eventos.', 13 | 'component.noticeIcon.clear': 'Limpar', 14 | 'component.noticeIcon.cleared': 'Limpo', 15 | 'component.noticeIcon.empty': 'Sem notificações', 16 | 'component.noticeIcon.loaded': 'Carregado', 17 | 'component.noticeIcon.view-more': 'Veja mais', 18 | }; 19 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': 'Welcome', 3 | 'menu.more-blocks': 'More Blocks', 4 | 5 | 'menu.home': 'Início', 6 | 'menu.login': 'Login', 7 | 'menu.register': 'Registro', 8 | 'menu.register.result': 'Resultado de registro', 9 | 'menu.dashboard': 'Dashboard', 10 | 'menu.dashboard.analysis': 'Análise', 11 | 'menu.dashboard.monitor': 'Monitor', 12 | 'menu.dashboard.workplace': 'Ambiente de Trabalho', 13 | 'menu.exception.403': '403', 14 | 'menu.exception.404': '404', 15 | 'menu.exception.500': '500', 16 | 'menu.form': 'Formulário', 17 | 'menu.form.basic-form': 'Formulário Básico', 18 | 'menu.form.step-form': 'Formulário Assistido', 19 | 'menu.form.step-form.info': 'Formulário Assistido(gravar informações de transferência)', 20 | 'menu.form.step-form.confirm': 'Formulário Assistido(confirmar informações de transferência)', 21 | 'menu.form.step-form.result': 'Formulário Assistido(finalizado)', 22 | 'menu.form.advanced-form': 'Formulário Avançado', 23 | 'menu.list': 'Lista', 24 | 'menu.list.table-list': 'Tabela de Busca', 25 | 'menu.list.basic-list': 'Lista Básica', 26 | 'menu.list.card-list': 'Lista de Card', 27 | 'menu.list.search-list': 'Lista de Busca', 28 | 'menu.list.search-list.articles': 'Lista de Busca(artigos)', 29 | 'menu.list.search-list.projects': 'Lista de Busca(projetos)', 30 | 'menu.list.search-list.applications': 'Lista de Busca(aplicações)', 31 | 'menu.profile': 'Perfil', 32 | 'menu.profile.basic': 'Perfil Básico', 33 | 'menu.profile.advanced': 'Perfil Avançado', 34 | 'menu.result': 'Resultado', 35 | 'menu.result.success': 'Sucesso', 36 | 'menu.result.fail': 'Falha', 37 | 'menu.exception': 'Exceção', 38 | 'menu.exception.not-permission': '403', 39 | 'menu.exception.not-find': '404', 40 | 'menu.exception.server-error': '500', 41 | 'menu.exception.trigger': 'Disparar', 42 | 'menu.account': 'Conta', 43 | 'menu.account.center': 'Central da Conta', 44 | 'menu.account.settings': 'Configurar Conta', 45 | 'menu.account.trigger': 'Disparar Erro', 46 | 'menu.account.logout': 'Sair', 47 | 'menu.editor': 'Graphic Editor', 48 | 'menu.editor.flow': 'Flow Editor', 49 | 'menu.editor.mind': 'Mind Editor', 50 | 'menu.editor.koni': 'Koni Editor', 51 | }; 52 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': 'Você está offline agora', 3 | 'app.pwa.serviceworker.updated': 'Novo conteúdo está disponível', 4 | 'app.pwa.serviceworker.updated.hint': 5 | 'Por favor, pressione o botão "Atualizar" para recarregar a página atual', 6 | 'app.pwa.serviceworker.updated.ok': 'Atualizar', 7 | }; 8 | -------------------------------------------------------------------------------- /src/app/locales/pt-BR/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': 'Configuração de estilo da página', 3 | 'app.setting.pagestyle.dark': 'Dark style', 4 | 'app.setting.pagestyle.light': 'Light style', 5 | 'app.setting.content-width': 'Largura do conteúdo', 6 | 'app.setting.content-width.fixed': 'Fixo', 7 | 'app.setting.content-width.fluid': 'Fluido', 8 | 'app.setting.themecolor': 'Cor do Tema', 9 | 'app.setting.themecolor.dust': 'Dust Red', 10 | 'app.setting.themecolor.volcano': 'Volcano', 11 | 'app.setting.themecolor.sunset': 'Sunset Orange', 12 | 'app.setting.themecolor.cyan': 'Cyan', 13 | 'app.setting.themecolor.green': 'Polar Green', 14 | 'app.setting.themecolor.daybreak': 'Daybreak Blue (default)', 15 | 'app.setting.themecolor.geekblue': 'Geek Glue', 16 | 'app.setting.themecolor.purple': 'Golden Purple', 17 | 'app.setting.navigationmode': 'Modo de Navegação', 18 | 'app.setting.sidemenu': 'Layout do Menu Lateral', 19 | 'app.setting.topmenu': 'Layout do Menu Superior', 20 | 'app.setting.fixedheader': 'Cabeçalho fixo', 21 | 'app.setting.fixedsidebar': 'Barra lateral fixa', 22 | 'app.setting.fixedsidebar.hint': 'Funciona no layout do menu lateral', 23 | 'app.setting.hideheader': 'Esconder o cabeçalho quando rolar', 24 | 'app.setting.hideheader.hint': 'Funciona quando o esconder cabeçalho está abilitado', 25 | 'app.setting.othersettings': 'Outras configurações', 26 | 'app.setting.weakmode': 'Weak Mode', 27 | 'app.setting.copy': 'Copiar Configuração', 28 | 'app.setting.copyinfo': 29 | 'copiado com sucesso,por favor trocar o defaultSettings em src/models/setting.js', 30 | 'app.setting.production.hint': 31 | 'O painel de configuração apenas é exibido no ambiente de desenvolvimento, por favor modifique manualmente o', 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import globalHeader from './zh-CN/globalHeader'; 2 | import menu from './zh-CN/menu'; 3 | import settingDrawer from './zh-CN/settingDrawer'; 4 | import settings from './zh-CN/settings'; 5 | import pwa from './zh-CN/pwa'; 6 | import component from './zh-CN/component'; 7 | import pageLogin from '../pages/user/login/locales/zh-CN'; 8 | import pageRegister from '../pages/user/register/locales/zh-CN'; 9 | import pageRegisterResult from '../pages/user/register-result/locales/zh-CN'; 10 | 11 | import pageExceptiont403 from '../pages/exception/403/locales/zh-CN'; 12 | import pageExceptiont404 from '../pages/exception/404/locales/zh-CN'; 13 | import pageExceptiont500 from '../pages/exception/500/locales/zh-CN'; 14 | 15 | 16 | export default { 17 | 'navBar.lang': '语言', 18 | 'layout.user.link.help': '帮助', 19 | 'layout.user.link.privacy': '隐私', 20 | 'layout.user.link.terms': '条款', 21 | 'app.preview.down.block': '下载此页面到本地项目', 22 | ...globalHeader, 23 | ...menu, 24 | ...settingDrawer, 25 | ...settings, 26 | ...pwa, 27 | ...component, 28 | 29 | ...pageLogin, 30 | ...pageRegister, 31 | ...pageRegisterResult, 32 | ...pageExceptiont403, 33 | ...pageExceptiont404, 34 | ...pageExceptiont500, 35 | }; 36 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': '展开', 3 | 'component.tagSelect.collapse': '收起', 4 | 'component.tagSelect.all': '全部', 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': '站内搜索', 3 | 'component.globalHeader.search.example1': '搜索提示一', 4 | 'component.globalHeader.search.example2': '搜索提示二', 5 | 'component.globalHeader.search.example3': '搜索提示三', 6 | 'component.globalHeader.help': '使用文档', 7 | 'component.globalHeader.notification': '通知', 8 | 'component.globalHeader.notification.empty': '你已查看所有通知', 9 | 'component.globalHeader.message': '消息', 10 | 'component.globalHeader.message.empty': '您已读完所有消息', 11 | 'component.globalHeader.event': '待办', 12 | 'component.globalHeader.event.empty': '你已完成所有待办', 13 | 'component.noticeIcon.clear': '清空', 14 | 'component.noticeIcon.cleared': '清空了', 15 | 'component.noticeIcon.empty': '暂无数据', 16 | 'component.noticeIcon.view-more': '查看更多', 17 | }; 18 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': '欢迎', 3 | 'menu.more-blocks': '更多区块', 4 | 'menu.home': '首页', 5 | 'menu.login': '登录', 6 | 'menu.register': '注册', 7 | 'menu.register.result': '注册结果', 8 | 'menu.dashboard': 'Dashboard', 9 | 'menu.dashboard.analysis': '分析页', 10 | 'menu.dashboard.monitor': '监控页', 11 | 'menu.dashboard.workplace': '工作台', 12 | 'menu.exception.403': '403', 13 | 'menu.exception.404': '404', 14 | 'menu.exception.500': '500', 15 | 'menu.form': '表单页', 16 | 'menu.form.basic-form': '基础表单', 17 | 'menu.form.step-form': '分步表单', 18 | 'menu.form.step-form.info': '分步表单(填写转账信息)', 19 | 'menu.form.step-form.confirm': '分步表单(确认转账信息)', 20 | 'menu.form.step-form.result': '分步表单(完成)', 21 | 'menu.form.advanced-form': '高级表单', 22 | 'menu.list': '列表页', 23 | 'menu.list.table-list': '查询表格', 24 | 'menu.list.basic-list': '标准列表', 25 | 'menu.list.card-list': '卡片列表', 26 | 'menu.list.search-list': '搜索列表', 27 | 'menu.list.search-list.articles': '搜索列表(文章)', 28 | 'menu.list.search-list.projects': '搜索列表(项目)', 29 | 'menu.list.search-list.applications': '搜索列表(应用)', 30 | 'menu.profile': '详情页', 31 | 'menu.profile.basic': '基础详情页', 32 | 'menu.profile.advanced': '高级详情页', 33 | 'menu.result': '结果页', 34 | 'menu.result.success': '成功页', 35 | 'menu.result.fail': '失败页', 36 | 'menu.exception': '异常页', 37 | 'menu.exception.not-permission': '403', 38 | 'menu.exception.not-find': '404', 39 | 'menu.exception.server-error': '500', 40 | 'menu.exception.trigger': '触发错误', 41 | 'menu.account': '个人页', 42 | 'menu.account.center': '个人中心', 43 | 'menu.account.settings': '个人设置', 44 | 'menu.account.trigger': '触发报错', 45 | 'menu.account.logout': '退出登录', 46 | 'menu.editor': '图形编辑器', 47 | 'menu.editor.flow': '流程编辑器', 48 | 'menu.editor.mind': '脑图编辑器', 49 | 'menu.editor.koni': '拓扑编辑器', 50 | }; 51 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': '当前处于离线状态', 3 | 'app.pwa.serviceworker.updated': '有新内容', 4 | 'app.pwa.serviceworker.updated.hint': '请点击“刷新”按钮或者手动刷新页面', 5 | 'app.pwa.serviceworker.updated.ok': '刷新', 6 | }; 7 | -------------------------------------------------------------------------------- /src/app/locales/zh-CN/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': '整体风格设置', 3 | 'app.setting.pagestyle.dark': '暗色菜单风格', 4 | 'app.setting.pagestyle.light': '亮色菜单风格', 5 | 'app.setting.content-width': '内容区域宽度', 6 | 'app.setting.content-width.fixed': '定宽', 7 | 'app.setting.content-width.fluid': '流式', 8 | 'app.setting.themecolor': '主题色', 9 | 'app.setting.themecolor.dust': '薄暮', 10 | 'app.setting.themecolor.volcano': '火山', 11 | 'app.setting.themecolor.sunset': '日暮', 12 | 'app.setting.themecolor.cyan': '明青', 13 | 'app.setting.themecolor.green': '极光绿', 14 | 'app.setting.themecolor.daybreak': '拂晓蓝(默认)', 15 | 'app.setting.themecolor.geekblue': '极客蓝', 16 | 'app.setting.themecolor.purple': '酱紫', 17 | 'app.setting.navigationmode': '导航模式', 18 | 'app.setting.sidemenu': '侧边菜单布局', 19 | 'app.setting.topmenu': '顶部菜单布局', 20 | 'app.setting.fixedheader': '固定 Header', 21 | 'app.setting.fixedsidebar': '固定侧边菜单', 22 | 'app.setting.fixedsidebar.hint': '侧边菜单布局时可配置', 23 | 'app.setting.hideheader': '下滑时隐藏 Header', 24 | 'app.setting.hideheader.hint': '固定 Header 时可配置', 25 | 'app.setting.othersettings': '其他设置', 26 | 'app.setting.weakmode': '色弱模式', 27 | 'app.setting.copy': '拷贝设置', 28 | 'app.setting.copyinfo': '拷贝成功,请到 src/defaultSettings.js 中替换默认配置', 29 | 'app.setting.production.hint': 30 | '配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件', 31 | }; 32 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | import globalHeader from './zh-TW/globalHeader'; 2 | import menu from './zh-TW/menu'; 3 | import settingDrawer from './zh-TW/settingDrawer'; 4 | import settings from './zh-TW/settings'; 5 | import pwa from './zh-TW/pwa'; 6 | import component from './zh-TW/component'; 7 | import pageLogin from '../pages/user/login/locales/zh-TW'; 8 | import pageRegister from '../pages/user/register/locales/zh-TW'; 9 | import pageRegisterResult from '../pages/user/register-result/locales/zh-TW'; 10 | import pageExceptiont403 from '../pages/exception/403/locales/zh-TW'; 11 | import pageExceptiont404 from '../pages/exception/404/locales/zh-TW'; 12 | import pageExceptiont500 from '../pages/exception/500/locales/zh-TW'; 13 | 14 | 15 | export default { 16 | 'navBar.lang': '語言', 17 | 'layout.user.link.help': '幫助', 18 | 'layout.user.link.privacy': '隱私', 19 | 'layout.user.link.terms': '條款', 20 | 'app.preview.down.block': '下載此頁面到本地項目', 21 | ...globalHeader, 22 | ...menu, 23 | ...settingDrawer, 24 | ...settings, 25 | ...pwa, 26 | ...component, 27 | 28 | ...pageLogin, 29 | ...pageRegister, 30 | ...pageRegisterResult, 31 | ...pageExceptiont403, 32 | ...pageExceptiont404, 33 | ...pageExceptiont500, 34 | 35 | }; 36 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW/component.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.tagSelect.expand': '展開', 3 | 'component.tagSelect.collapse': '收起', 4 | 'component.tagSelect.all': '全部', 5 | }; 6 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW/globalHeader.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'component.globalHeader.search': '站內搜索', 3 | 'component.globalHeader.search.example1': '搜索提示壹', 4 | 'component.globalHeader.search.example2': '搜索提示二', 5 | 'component.globalHeader.search.example3': '搜索提示三', 6 | 'component.globalHeader.help': '使用手冊', 7 | 'component.globalHeader.notification': '通知', 8 | 'component.globalHeader.notification.empty': '妳已查看所有通知', 9 | 'component.globalHeader.message': '消息', 10 | 'component.globalHeader.message.empty': '您已讀完所有消息', 11 | 'component.globalHeader.event': '待辦', 12 | 'component.globalHeader.event.empty': '妳已完成所有待辦', 13 | 'component.noticeIcon.clear': '清空', 14 | 'component.noticeIcon.cleared': '清空了', 15 | 'component.noticeIcon.empty': '暫無資料', 16 | 'component.noticeIcon.view-more': '查看更多', 17 | }; 18 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW/menu.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'menu.welcome': '歡迎', 3 | 'menu.more-blocks': '更多區塊', 4 | 5 | 'menu.home': '首頁', 6 | 'menu.login': '登錄', 7 | 'menu.exception.403': '403', 8 | 'menu.exception.404': '404', 9 | 'menu.exception.500': '500', 10 | 'menu.register': '註冊', 11 | 'menu.register.resultt': '註冊結果', 12 | 'menu.dashboard': 'Dashboard', 13 | 'menu.dashboard.analysis': '分析頁', 14 | 'menu.dashboard.monitor': '監控頁', 15 | 'menu.dashboard.workplace': '工作臺', 16 | 'menu.form': '表單頁', 17 | 'menu.form.basic-form': '基礎表單', 18 | 'menu.form.step-form': '分步表單', 19 | 'menu.form.step-form.info': '分步表單(填寫轉賬信息)', 20 | 'menu.form.step-form.confirm': '分步表單(確認轉賬信息)', 21 | 'menu.form.step-form.result': '分步表單(完成)', 22 | 'menu.form.advanced-form': '高級表單', 23 | 'menu.list': '列表頁', 24 | 'menu.list.table-list': '查詢表格', 25 | 'menu.list.basic-list': '標淮列表', 26 | 'menu.list.card-list': '卡片列表', 27 | 'menu.list.search-list': '搜索列表', 28 | 'menu.list.search-list.articles': '搜索列表(文章)', 29 | 'menu.list.search-list.projects': '搜索列表(項目)', 30 | 'menu.list.search-list.applications': '搜索列表(應用)', 31 | 'menu.profile': '詳情頁', 32 | 'menu.profile.basic': '基礎詳情頁', 33 | 'menu.profile.advanced': '高級詳情頁', 34 | 'menu.result': '結果頁', 35 | 'menu.result.success': '成功頁', 36 | 'menu.result.fail': '失敗頁', 37 | 'menu.account': '個人頁', 38 | 'menu.account.center': '個人中心', 39 | 'menu.account.settings': '個人設置', 40 | 'menu.account.trigger': '觸發報錯', 41 | 'menu.account.logout': '退出登錄', 42 | 'menu.exception': '异常页', 43 | 'menu.exception.not-permission': '403', 44 | 'menu.exception.not-find': '404', 45 | 'menu.exception.server-error': '500', 46 | 'menu.exception.trigger': '触发错误', 47 | 'menu.editor': '圖形編輯器', 48 | 'menu.editor.flow': '流程編輯器', 49 | 'menu.editor.mind': '腦圖編輯器', 50 | 'menu.editor.koni': '拓撲編輯器', 51 | }; 52 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW/pwa.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.pwa.offline': '當前處於離線狀態', 3 | 'app.pwa.serviceworker.updated': '有新內容', 4 | 'app.pwa.serviceworker.updated.hint': '請點擊“刷新”按鈕或者手動刷新頁面', 5 | 'app.pwa.serviceworker.updated.ok': '刷新', 6 | }; 7 | -------------------------------------------------------------------------------- /src/app/locales/zh-TW/settingDrawer.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'app.setting.pagestyle': '整體風格設置', 3 | 'app.setting.pagestyle.dark': '暗色菜單風格', 4 | 'app.setting.pagestyle.light': '亮色菜單風格', 5 | 'app.setting.content-width': '內容區域寬度', 6 | 'app.setting.content-width.fixed': '定寬', 7 | 'app.setting.content-width.fluid': '流式', 8 | 'app.setting.themecolor': '主題色', 9 | 'app.setting.themecolor.dust': '薄暮', 10 | 'app.setting.themecolor.volcano': '火山', 11 | 'app.setting.themecolor.sunset': '日暮', 12 | 'app.setting.themecolor.cyan': '明青', 13 | 'app.setting.themecolor.green': '極光綠', 14 | 'app.setting.themecolor.daybreak': '拂曉藍(默認)', 15 | 'app.setting.themecolor.geekblue': '極客藍', 16 | 'app.setting.themecolor.purple': '醬紫', 17 | 'app.setting.navigationmode': '導航模式', 18 | 'app.setting.sidemenu': '側邊菜單布局', 19 | 'app.setting.topmenu': '頂部菜單布局', 20 | 'app.setting.fixedheader': '固定 Header', 21 | 'app.setting.fixedsidebar': '固定側邊菜單', 22 | 'app.setting.fixedsidebar.hint': '側邊菜單布局時可配置', 23 | 'app.setting.hideheader': '下滑時隱藏 Header', 24 | 'app.setting.hideheader.hint': '固定 Header 時可配置', 25 | 'app.setting.othersettings': '其他設置', 26 | 'app.setting.weakmode': '色弱模式', 27 | 'app.setting.copy': '拷貝設置', 28 | 'app.setting.copyinfo': '拷貝成功,請到 src/defaultSettings.js 中替換默認配置', 29 | 'app.setting.production.hint': 30 | '配置欄只在開發環境用於預覽,生產環境不會展現,請拷貝後手動修改配置文件', 31 | }; 32 | -------------------------------------------------------------------------------- /src/app/pages/account/account-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {CenterComponent} from "./center/center.component"; 4 | import {SettingsComponent} from "./settings/settings.component"; 5 | 6 | const routes: Routes = [ 7 | {path: '', redirectTo: 'center', pathMatch: 'full'}, 8 | {path: 'center', component: CenterComponent, data: {name: '个人中心'}}, 9 | {path: 'settings', component: SettingsComponent, data: {name: '个人设置'}} 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule] 15 | }) 16 | export class AccountRoutingModule { 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/account/account.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {CenterComponent} from "./center/center.component"; 4 | import {SharedModule} from "../../shared/shared.module"; 5 | import {AccountRoutingModule} from "./account-routing.module"; 6 | import {SettingsComponent} from "./settings/settings.component"; 7 | import {SecurityViewComponent} from "./settings/components/security-view/security-view.component"; 8 | 9 | const centerComponents = [ 10 | CenterComponent, 11 | ]; 12 | 13 | const settingComponents = [ 14 | SettingsComponent, 15 | SecurityViewComponent 16 | ]; 17 | 18 | @NgModule({ 19 | imports: [SharedModule, AccountRoutingModule], 20 | exports: [], 21 | declarations: [ 22 | ...centerComponents, 23 | ...settingComponents 24 | ] 25 | }) 26 | export class AccountModule { 27 | } 28 | -------------------------------------------------------------------------------- /src/app/pages/account/center/center.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .avatarHolder { 4 | margin-bottom: 24px; 5 | text-align: center; 6 | 7 | & > img { 8 | width: 104px; 9 | height: 104px; 10 | margin-bottom: 20px; 11 | } 12 | 13 | .name { 14 | margin-bottom: 4px; 15 | color: @heading-color; 16 | font-weight: 500; 17 | font-size: 20px; 18 | line-height: 28px; 19 | } 20 | } 21 | 22 | .detail { 23 | p { 24 | position: relative; 25 | margin-bottom: 8px; 26 | padding-left: 26px; 27 | 28 | &:last-child { 29 | margin-bottom: 0; 30 | } 31 | } 32 | 33 | i { 34 | position: absolute; 35 | top: 4px; 36 | left: 0; 37 | width: 14px; 38 | height: 14px; 39 | background: url(https://gw.alipayobjects.com/zos/rmsportal/pBjWzVAHnOOtAUvZmZfy.svg); 40 | 41 | &.title { 42 | background-position: 0 0; 43 | } 44 | 45 | &.group { 46 | background-position: 0 -22px; 47 | } 48 | 49 | &.address { 50 | background-position: 0 -44px; 51 | } 52 | } 53 | } 54 | 55 | .tagsTitle, 56 | .teamTitle { 57 | margin-bottom: 12px; 58 | color: @heading-color; 59 | font-weight: 500; 60 | } 61 | 62 | .tags { 63 | :global { 64 | .ant-tag { 65 | margin-bottom: 8px; 66 | } 67 | } 68 | } 69 | 70 | .team { 71 | :global { 72 | .ant-avatar { 73 | margin-right: 12px; 74 | } 75 | } 76 | 77 | a { 78 | display: block; 79 | margin-bottom: 24px; 80 | overflow: hidden; 81 | color: @text-color; 82 | white-space: nowrap; 83 | text-overflow: ellipsis; 84 | word-break: break-all; 85 | transition: color 0.3s; 86 | 87 | &:hover { 88 | color: @primary-color; 89 | } 90 | } 91 | } 92 | 93 | .tabsCard { 94 | :global { 95 | .ant-card-head { 96 | padding: 0 16px; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/app/pages/account/center/center.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; 2 | import {HttpClient} from "@angular/common/http"; 3 | import {zip} from "rxjs"; 4 | import {CurrentUser} from "./_mock"; 5 | 6 | @Component({ 7 | selector: 'app-center', 8 | templateUrl: 'center.component.html', 9 | styleUrls: ['center.component.less'] 10 | }) 11 | export class CenterComponent implements OnInit { 12 | 13 | @ViewChild('tagInput') 14 | private tagInput: ElementRef; 15 | tagValue = ''; 16 | inputVisible:boolean = false; 17 | 18 | dataLoading: boolean = true; 19 | 20 | currentUser: CurrentUser; 21 | 22 | 23 | constructor(private httpClient: HttpClient, 24 | private cdr: ChangeDetectorRef) { 25 | } 26 | 27 | ngOnInit() { 28 | this.httpClient.get('/api/currentUser').subscribe((currentUser:any)=>{ 29 | console.log(currentUser); 30 | this.dataLoading = false; 31 | this.currentUser = currentUser; 32 | }) 33 | } 34 | 35 | tagShowIpt() { 36 | this.inputVisible = true; 37 | this.cdr.detectChanges(); 38 | (this.tagInput.nativeElement as HTMLInputElement).focus(); 39 | } 40 | 41 | tagBlur() { 42 | const { currentUser, cdr, tagValue } = this; 43 | if (tagValue && currentUser.tags.filter(tag => tag.label === tagValue).length === 0) { 44 | currentUser.tags.push({ key: '6' ,label: tagValue }); 45 | } 46 | this.tagValue = ''; 47 | this.inputVisible = false; 48 | cdr.detectChanges(); 49 | } 50 | 51 | tagEnter(e: KeyboardEvent) { 52 | if (e.keyCode === 13) this.tagBlur(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/pages/account/settings/components/security-view/security-view.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 修改 5 | 6 | 7 | 当前密码强度: 8 | 9 | 10 | 11 | 12 | 修改 13 | 14 | 15 | 16 | 已绑定手机:159****2231 17 | 18 | 19 | 20 | 21 | 22 | 修改 23 | 24 | 25 | 26 | 未设置密保问题,密保问题可有效保护账户安全 27 | 28 | 29 | 30 | 31 | 32 | 修改 33 | 34 | 35 | 36 | 已绑定邮箱:cip*****.com 37 | 38 | 39 | 40 | 41 | 42 | 修改 43 | 44 | 45 | 46 | 未绑定 MFA 设备,绑定后,可以进行二次确认 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/app/pages/account/settings/components/security-view/security-view.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {NzMessageService} from "ng-zorro-antd/message"; 3 | 4 | @Component({ 5 | selector: 'app-security-view', 6 | templateUrl: 'security-view.component.html' 7 | }) 8 | export class SecurityViewComponent implements OnInit { 9 | 10 | constructor(public msg: NzMessageService) { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/account/settings/settings.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
    5 |
  • 6 | {{menuMap[item]}} 7 |
  • 8 |
9 |
10 |
11 |
12 | {{menuMap[selectKey]}} 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /src/app/pages/account/settings/settings.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | 4 | type SettingsStateKeys = 'base' | 'security' | 'binding' | 'notification'; 5 | 6 | @Component({ 7 | selector: 'app-settings', 8 | templateUrl: 'settings.component.html' 9 | }) 10 | export class SettingsComponent implements OnInit { 11 | 12 | mode: 'inline' | 'horizontal' = 'inline'; 13 | selectKey: SettingsStateKeys = 'base'; 14 | menuMap: any = { 15 | base: '基本设置', 16 | security: '安全设置', 17 | binding: '账号绑定', 18 | notification: '新消息通知' 19 | }; 20 | 21 | constructor() { 22 | } 23 | 24 | ngOnInit() { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/analysis.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 | 15 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/analysis.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {NzMessageService} from "ng-zorro-antd/message"; 3 | import {HttpClient} from "@angular/common/http"; 4 | import {AnalysisData} from "./data"; 5 | 6 | @Component({ 7 | selector: 'app-analysis', 8 | templateUrl: 'analysis.component.html', 9 | styleUrls: ['analysis.component.less'] 10 | }) 11 | export class AnalysisComponent implements OnInit { 12 | 13 | analysisData: any = {}; 14 | 15 | constructor(private nzMessageService: NzMessageService, 16 | private httpClient: HttpClient) { 17 | } 18 | 19 | 20 | ngOnInit() { 21 | this.httpClient.get('/api/fake_chart_data').subscribe((result: AnalysisData) => { 22 | console.log(result); 23 | this.analysisData = result; 24 | }) 25 | } 26 | 27 | cancel(): void { 28 | this.nzMessageService.info('click cancel'); 29 | } 30 | 31 | confirm(): void { 32 | this.nzMessageService.info('click confirm'); 33 | } 34 | 35 | get settings() { 36 | return null; 37 | // return this.settingsService.settings; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/charts/bar/bar.component.html: -------------------------------------------------------------------------------- 1 |
2 |

{{title}}

3 |
4 |
5 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/charts/bar/bar.component.ts: -------------------------------------------------------------------------------- 1 | import {AfterViewInit, Component, ElementRef, Input, NgZone, ViewChild} from '@angular/core'; 2 | import {inNextTick} from "ng-zorro-antd/core/util"; 3 | 4 | declare var G2; 5 | 6 | @Component({ 7 | selector: 'g2-bar', 8 | templateUrl: 'bar.component.html' 9 | }) 10 | export class BarComponent implements AfterViewInit { 11 | 12 | @Input() title: string; 13 | color: string = 'rgba(24, 144, 255, 0.85)'; 14 | padding: [number, number, number, number]; 15 | @Input() height: number = 1; 16 | @Input() data: { x: string; y: number; }[]; 17 | forceFit: boolean = true; 18 | autoLabel: boolean; 19 | style: { [key: string]: string; }; 20 | 21 | @ViewChild('container', {static: true}) private container: ElementRef; 22 | 23 | constructor(private ngZone: NgZone) { 24 | } 25 | 26 | ngAfterViewInit() { 27 | inNextTick().subscribe(() => { 28 | this.renderChart(); 29 | }); 30 | } 31 | 32 | renderChart() { 33 | this.ngZone.runOutsideAngular(() => { 34 | const chart = new G2.Chart({ 35 | container: this.container.nativeElement, 36 | height: this.title ? this.height - 41 : this.height, 37 | forceFit: this.forceFit, 38 | padding: this.padding || 'auto' 39 | }); 40 | chart.source(this.data, {x: {type: 'cat'}, y: {min: 0}}); 41 | // chart.axis('x', false); 42 | // chart.axis('y', false); 43 | chart.tooltip({ 44 | showTitle: false, 45 | }); 46 | chart.interval() 47 | .position('x*y') 48 | .color(this.color) 49 | .tooltip('x*y', (x: string, y: string) => ({name: x, value: y})); 50 | chart.render(); 51 | }) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/introduce-row/introduce-row.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | 7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/introduce-row/introduce-row.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-introduce-row', 5 | templateUrl: 'introduce-row.component.html' 6 | }) 7 | export class IntroduceRowComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/offline-data/offline-data.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/pages/dashboard/analysis/components/offline-data/offline-data.component.html -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/offline-data/offline-data.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-offline-data', 5 | templateUrl: 'offline-data.component.html' 6 | }) 7 | export class OfflineDataComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/proportion-sales/proportion-sales.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/pages/dashboard/analysis/components/proportion-sales/proportion-sales.component.html -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/proportion-sales/proportion-sales.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-proportion-sales', 5 | templateUrl: 'proportion-sales.component.html' 6 | }) 7 | export class ProportionSalesComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/sales-card/sales-card.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnInit} from '@angular/core'; 2 | import {VisitDataType} from "../../data"; 3 | 4 | @Component({ 5 | selector: 'app-sales-card', 6 | templateUrl: 'sales-card.component.html' 7 | }) 8 | export class SalesCardComponent implements OnInit { 9 | 10 | rangePickerValue: { title: string; total: number }[] = []; 11 | isActive: (key: 'today' | 'week' | 'month' | 'year') => string; 12 | @Input() salesData: VisitDataType[]; 13 | loading: boolean; 14 | handleRangePickerChange: (dates: any, dateStrings: [string, string]) => void; 15 | selectDate: (key: 'today' | 'week' | 'month' | 'year') => void; 16 | rankingListData: { title: string; total: number }[] = []; 17 | 18 | constructor() { 19 | } 20 | 21 | ngOnInit() { 22 | for (let i = 0; i < 7; i += 1) { 23 | this.rankingListData.push({ 24 | title: `工专路 ${i} 号店`, 25 | total: 323234, 26 | }); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/top-search/top-search.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/pages/dashboard/analysis/components/top-search/top-search.component.html -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/components/top-search/top-search.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-top-search', 5 | templateUrl: 'top-search.component.html' 6 | }) 7 | export class TopSearchComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/data.d.ts: -------------------------------------------------------------------------------- 1 | export interface VisitDataType { 2 | x: string; 3 | y: number; 4 | } 5 | 6 | export interface SearchDataType { 7 | index: number; 8 | keyword: string; 9 | count: number; 10 | range: number; 11 | status: number; 12 | } 13 | 14 | export interface OfflineDataType { 15 | name: string; 16 | cvr: number; 17 | } 18 | 19 | export interface OfflineChartData { 20 | x: any; 21 | y1: number; 22 | y2: number; 23 | } 24 | 25 | export interface RadarData { 26 | name: string; 27 | label: string; 28 | value: number; 29 | } 30 | 31 | export interface AnalysisData { 32 | visitData: VisitDataType[]; 33 | visitData2: VisitDataType[]; 34 | salesData: VisitDataType[]; 35 | searchData: SearchDataType[]; 36 | offlineData: OfflineDataType[]; 37 | offlineChartData: OfflineChartData[]; 38 | salesTypeData: VisitDataType[]; 39 | salesTypeDataOnline: VisitDataType[]; 40 | salesTypeDataOffline: VisitDataType[]; 41 | radarData: RadarData[]; 42 | } 43 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/analysis/index.ts: -------------------------------------------------------------------------------- 1 | import {AnalysisComponent} from "./analysis.component"; 2 | import {SalesCardComponent} from "./components/sales-card/sales-card.component"; 3 | import {IntroduceRowComponent} from "./components/introduce-row/introduce-row.component"; 4 | import {OfflineDataComponent} from "./components/offline-data/offline-data.component"; 5 | import {TopSearchComponent} from "./components/top-search/top-search.component"; 6 | import {ProportionSalesComponent} from "./components/proportion-sales/proportion-sales.component"; 7 | import {BarComponent} from "./components/charts/bar/bar.component"; 8 | 9 | export const AnalysisComponents = [ 10 | AnalysisComponent, 11 | 12 | SalesCardComponent, 13 | IntroduceRowComponent, 14 | OfflineDataComponent, 15 | TopSearchComponent, 16 | ProportionSalesComponent, 17 | 18 | BarComponent 19 | ]; 20 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/dashboard-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {AnalysisComponent} from "./analysis/analysis.component"; 4 | import {MonitorComponent} from "./monitor/monitor.component"; 5 | import {WorkplaceComponent} from "./workplace/workplace.component"; 6 | 7 | const routes: Routes = [ 8 | {path: '', redirectTo: 'analysis', pathMatch: 'full'}, 9 | {path: 'analysis', component: AnalysisComponent, data: {name: '分析页'}}, 10 | {path: 'monitor', component: MonitorComponent, data: {name: '监控页'}}, 11 | {path: 'workplace', component: WorkplaceComponent, data: {name: '工作台'}} 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class DashboardRoutingModule { 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/dashboard.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {SharedModule} from "../../shared/shared.module"; 3 | import {DashboardRoutingModule} from "./dashboard-routing.module"; 4 | import {MonitorComponents} from "./monitor"; 5 | import {WorkplaceComponents} from "./workplace"; 6 | import {AnalysisComponents} from "./analysis"; 7 | 8 | @NgModule({ 9 | imports: [SharedModule, DashboardRoutingModule], 10 | exports: [], 11 | declarations: [ 12 | ...WorkplaceComponents, 13 | ...MonitorComponents, 14 | ...AnalysisComponents, 15 | ] 16 | }) 17 | export class DashboardModule { 18 | } 19 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/_mock.ts: -------------------------------------------------------------------------------- 1 | import mockjs from 'mockjs'; 2 | 3 | export const monitor = { 4 | 'GET /api/tags': mockjs.mock({ 5 | 'list|100': [{name: '@city', 'value|1-100': 150, 'type|0-2': 1}], 6 | }), 7 | }; 8 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/components/active-chart/active-chart.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 |
16 |

xxx 亿元

17 |

xxx 亿元

18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 |
29 | 00:00 30 | 12:00 31 | 23:00 32 | 33 | 34 |
35 |
36 |
37 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/components/active-chart/active-chart.component.less: -------------------------------------------------------------------------------- 1 | .activeChart { 2 | position: relative; 3 | } 4 | .activeChartGrid { 5 | p { 6 | position: absolute; 7 | top: 80px; 8 | } 9 | p:last-child { 10 | top: 115px; 11 | } 12 | } 13 | .activeChartLegend { 14 | position: relative; 15 | height: 20px; 16 | margin-top: 8px; 17 | font-size: 0; 18 | line-height: 20px; 19 | span { 20 | display: inline-block; 21 | width: 33.33%; 22 | font-size: 12px; 23 | text-align: center; 24 | } 25 | span:first-child { 26 | text-align: left; 27 | } 28 | span:last-child { 29 | text-align: right; 30 | } 31 | } 32 | .dashedLine { 33 | position: relative; 34 | top: -70px; 35 | left: -3px; 36 | height: 1px; 37 | 38 | .line { 39 | position: absolute; 40 | top: 0; 41 | left: 0; 42 | width: 100%; 43 | height: 100%; 44 | background-image: linear-gradient(to right, transparent 50%, #e9e9e9 50%); 45 | background-size: 6px; 46 | } 47 | } 48 | 49 | .dashedLine:last-child { 50 | top: -36px; 51 | } 52 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/components/active-chart/active-chart.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-active-chart', 5 | templateUrl: 'active-chart.component.html', 6 | styleUrls: ['active-chart.component.less'] 7 | }) 8 | export class ActiveChartComponent implements OnInit { 9 | 10 | activeData: any; 11 | 12 | constructor() { 13 | } 14 | 15 | ngOnInit() { 16 | this.activeData = this.getActiveData(); 17 | console.log(this.activeData); 18 | } 19 | 20 | getActiveData() { 21 | const activeData = []; 22 | for (let i = 0; i < 24; i += 1) { 23 | activeData.push({ 24 | x: `${this.fixedZero(i)}:00`, 25 | y: Math.floor(Math.random() * 200) + i * 50, 26 | }); 27 | } 28 | return activeData; 29 | } 30 | 31 | fixedZero(val: number) { 32 | return val * 1 < 10 ? `0${val}` : val; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/components/chart/mini-area/mini-area.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/components/chart/mini-area/mini-area.component.less: -------------------------------------------------------------------------------- 1 | .miniChart { 2 | position: relative; 3 | width: 100%; 4 | .chartContent { 5 | position: absolute; 6 | bottom: -28px; 7 | width: 100%; 8 | > div { 9 | margin: 0 -5px; 10 | overflow: hidden; 11 | } 12 | } 13 | .chartLoading { 14 | position: absolute; 15 | top: 16px; 16 | left: 50%; 17 | margin-left: -7px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/index.ts: -------------------------------------------------------------------------------- 1 | import {ActiveChartComponent} from "./components/active-chart/active-chart.component"; 2 | import {MonitorComponent} from "./monitor.component"; 3 | import {MiniAreaComponent} from "./components/chart/mini-area/mini-area.component"; 4 | 5 | export const MonitorComponents = [ 6 | MonitorComponent, 7 | ActiveChartComponent, 8 | MiniAreaComponent 9 | ]; 10 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/monitor.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 | 27 | 28 |
29 |
30 |
31 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/monitor.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .mapChart { 4 | height: 452px; 5 | padding-top: 24px; 6 | text-align: center; 7 | img { 8 | display: inline-block; 9 | max-width: 100%; 10 | max-height: 437px; 11 | } 12 | } 13 | 14 | //.pieCard :global(.pie-stat) { 15 | // font-size: 24px !important; 16 | //} 17 | 18 | .pieCard ::ng-deep(.pie-stat) { 19 | font-size: 24px !important; 20 | } 21 | 22 | @media screen and (max-width: @screen-lg) { 23 | .mapChart { 24 | height: auto; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/monitor/monitor.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-monitor', 5 | templateUrl: 'monitor.component.html', 6 | styleUrls: ['monitor.component.less'] 7 | }) 8 | export class MonitorComponent implements OnInit { 9 | constructor() { 10 | } 11 | 12 | ngOnInit() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/components/editable-link-group/editable-link-group.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{ link.title }} 3 | 11 |
12 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/components/editable-link-group/editable-link-group.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .linkGroup { 4 | padding: 20px 0 8px 24px; 5 | font-size: 0; 6 | & > a { 7 | display: inline-block; 8 | width: 25%; 9 | margin-bottom: 13px; 10 | color: @text-color; 11 | font-size: @font-size-base; 12 | &:hover { 13 | color: @primary-color; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/components/editable-link-group/editable-link-group.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, OnInit, Output, TemplateRef} from '@angular/core'; 2 | 3 | export interface EditableLink { 4 | title: string; 5 | href: string; 6 | id?: string; 7 | } 8 | 9 | @Component({ 10 | selector: 'app-editable-link-group', 11 | templateUrl: 'editable-link-group.component.html', 12 | styleUrls: ['editable-link-group.component.less'] 13 | }) 14 | export class EditableLinkGroupComponent implements OnInit { 15 | 16 | @Input() links: EditableLink[]; 17 | // @Input() linkElement: TemplateRef; 18 | @Output() readonly onAdd = new EventEmitter(); 19 | 20 | constructor() { 21 | } 22 | 23 | ngOnInit() { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/components/radar/radar.component.html: -------------------------------------------------------------------------------- 1 | 2 |

{{title}}

3 |
4 |
5 |
6 | 7 |
10 |
11 |

12 | 14 | 15 | {{item.name}} 16 |

17 |
{{item.value}}
18 |
19 |
20 |
21 |
22 | 23 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/components/radar/radar.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .radar { 4 | .legend { 5 | margin-top: 16px; 6 | .legendItem { 7 | position: relative; 8 | color: @text-color-secondary; 9 | line-height: 22px; 10 | text-align: center; 11 | cursor: pointer; 12 | p { 13 | margin: 0; 14 | } 15 | h6 { 16 | margin-top: 4px; 17 | margin-bottom: 0; 18 | padding-left: 16px; 19 | color: @heading-color; 20 | font-size: 24px; 21 | line-height: 32px; 22 | } 23 | &::after { 24 | position: absolute; 25 | top: 8px; 26 | right: 0; 27 | width: 1px; 28 | height: 40px; 29 | background-color: @border-color-split; 30 | content: ''; 31 | } 32 | } 33 | > :last-child .legendItem::after { 34 | display: none; 35 | } 36 | .dot { 37 | position: relative; 38 | top: -1px; 39 | display: inline-block; 40 | width: 6px; 41 | height: 6px; 42 | margin-right: 6px; 43 | border-radius: 6px; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/app/pages/dashboard/workplace/index.ts: -------------------------------------------------------------------------------- 1 | import {WorkplaceComponent} from "./workplace.component"; 2 | import {RadarComponent} from "./components/radar/radar.component"; 3 | import {EditableLinkGroupComponent} from "./components/editable-link-group/editable-link-group.component"; 4 | 5 | export const WorkplaceComponents = [ 6 | WorkplaceComponent, 7 | RadarComponent, 8 | EditableLinkGroupComponent 9 | ]; 10 | -------------------------------------------------------------------------------- /src/app/pages/exception/403/403.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-exception-403', 5 | template: ` 6 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | ` 20 | }) 21 | export class Exception403Component implements OnInit { 22 | 23 | constructor() { 24 | } 25 | 26 | ngOnInit() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/pages/exception/403/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-403.exception.back': 'Back to home', 3 | 'exception-403.description.403': "Sorry, you don't have access to this page.", 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/403/locales/pt-BR.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-403.exception.back': 'Voltar para Início', 3 | 'exception-403.description.403': 'Desculpe, você não tem acesso a esta página.', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/403/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-403.exception.back': '返回首页', 3 | 'exception-403.description.403': '抱歉,你无权访问该页面。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/403/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-403.exception.back': '返回首頁', 3 | 'exception-403.description.403': '抱歉,妳無權訪問該頁面。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/404/404.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-exception-404', 5 | template: ` 6 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | ` 20 | }) 21 | export class Exception404Component implements OnInit { 22 | 23 | constructor() { 24 | } 25 | 26 | ngOnInit() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/pages/exception/404/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-404.exception.back': 'Back to home', 3 | 'exception-404.description.404': 'Sorry, the page you visited does not exist.', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/404/locales/pt-BR.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-404.exception.back': 'Voltar para Início', 3 | 'exception-404.description.404': 'Desculpe, a página que você visitou não existe.', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/404/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-404.exception.back': '返回首页', 3 | 'exception-404.description.404': '抱歉,你访问的页面不存在。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/404/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-404.exception.back': '返回首頁', 3 | 'exception-404.description.404': '抱歉,妳訪問的頁面不存在。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/500/500.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-exception-500', 5 | template: ` 6 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | ` 20 | }) 21 | export class Exception500Component implements OnInit { 22 | 23 | constructor() { 24 | } 25 | 26 | ngOnInit() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/pages/exception/500/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-500.exception.back': 'Back to home', 3 | 'exception-500.description.500': 'Sorry, the server is reporting an fail.', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/500/locales/pt-BR.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-500.exception.back': 'Voltar para Início', 3 | 'exception-500.description.500': 'Desculpe, o servidor está reportando um erro.', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/500/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-500.exception.back': '返回首页', 3 | 'exception-500.description.500': '抱歉,服务器出错了。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/500/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'exception-500.exception.back': '返回首頁', 3 | 'exception-500.description.500': '抱歉,服務器出錯了。', 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/pages/exception/exception-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {Exception403Component} from "./403/403.component"; 4 | import {Exception404Component} from "./404/404.component"; 5 | import {Exception500Component} from "./500/500.component"; 6 | 7 | const routes: Routes = [ 8 | {path: '', redirectTo: '403', pathMatch: 'full'}, 9 | {path: '403', component: Exception403Component, data: {}}, 10 | {path: '404', component: Exception404Component, data: {}}, 11 | {path: '500', component: Exception500Component, data: {}} 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class ExceptionRoutingModule { 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/exception/exception.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {Exception403Component} from "./403/403.component"; 4 | import {Exception404Component} from "./404/404.component"; 5 | import {Exception500Component} from "./500/500.component"; 6 | import {SharedModule} from "../../shared/shared.module"; 7 | import {ExceptionRoutingModule} from "./exception-routing.module"; 8 | 9 | @NgModule({ 10 | imports: [SharedModule, ExceptionRoutingModule], 11 | exports: [], 12 | declarations: [ 13 | Exception403Component, 14 | Exception404Component, 15 | Exception500Component, 16 | ], 17 | providers: [], 18 | }) 19 | export class ExceptionModule { 20 | } 21 | -------------------------------------------------------------------------------- /src/app/pages/forms/advanced-form/advanced-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/pages/forms/advanced-form/advanced-form.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-advanced-form', 5 | templateUrl: 'advanced-form.component.html', 6 | 7 | }) 8 | export class AdvancedFormComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/forms/basic-form/basic-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/pages/forms/basic-form/basic-form.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-basic-form', 5 | templateUrl: 'basic-form.component.html', 6 | 7 | }) 8 | export class BasicFormComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/forms/forms-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {BasicFormComponent} from "./basic-form/basic-form.component"; 4 | import {StepFormComponent} from "./step-form/step-form.component"; 5 | import {AdvancedFormComponent} from "./advanced-form/advanced-form.component"; 6 | 7 | const routes: Routes = [ 8 | { path: '', redirectTo: 'base-form', pathMatch: 'full'}, 9 | { path: 'basic-form',component: BasicFormComponent,data:{ name: '基础表单'}}, 10 | { path: 'step-form',component: StepFormComponent,data:{ name: '分步表单'}}, 11 | { path: 'advanced-form',component: AdvancedFormComponent,data:{name: '高级表单'}} 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class FormsRoutingModule { 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/forms/forms.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {SharedModule} from "../../shared/shared.module"; 3 | import {AdvancedFormComponent} from "./advanced-form/advanced-form.component"; 4 | import {BasicFormComponent} from "./basic-form/basic-form.component"; 5 | import {StepFormComponent} from "./step-form/step-form.component"; 6 | import {TableFormComponent} from "./table-form/table-form.component"; 7 | import {FormsRoutingModule} from "./forms-routing.module"; 8 | 9 | @NgModule({ 10 | imports: [SharedModule, FormsRoutingModule], 11 | declarations: [ 12 | BasicFormComponent, 13 | StepFormComponent, 14 | AdvancedFormComponent, 15 | TableFormComponent 16 | ], 17 | exports: [] 18 | }) 19 | export class FormsModule { 20 | } 21 | -------------------------------------------------------------------------------- /src/app/pages/forms/step-form/step-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/app/pages/forms/step-form/step-form.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-step-form', 5 | templateUrl: 'step-form.component.html', 6 | 7 | }) 8 | export class StepFormComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/forms/table-form/table-form.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/app/pages/forms/table-form/table-form.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-table-form', 5 | templateUrl: 'table-form.component.html', 6 | 7 | }) 8 | export class TableFormComponent implements OnInit { 9 | 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/list/basic-list/basic-list.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, OnInit} from '@angular/core'; 2 | import {HttpClient} from "@angular/common/http"; 3 | 4 | @Component({ 5 | selector: 'app-basic-list', 6 | templateUrl: 'basic-list.component.html', 7 | 8 | }) 9 | export class BasicListComponent implements OnInit { 10 | 11 | loading: boolean; 12 | paginationProps: any; 13 | list: any[]; 14 | 15 | constructor(private httpClient: HttpClient, 16 | private cdr: ChangeDetectorRef) { 17 | } 18 | 19 | ngOnInit() { 20 | this.getData(); 21 | } 22 | 23 | getData() { 24 | this.loading = true; 25 | this.httpClient.get('/api/list').subscribe((res: any) => { 26 | this.list = res; 27 | this.loading = false; 28 | this.cdr.detectChanges(); 29 | }); 30 | } 31 | 32 | 33 | showModal() { 34 | 35 | } 36 | 37 | showEditModal(item) { 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/app/pages/list/basic-list/data.d.ts: -------------------------------------------------------------------------------- 1 | export interface Member { 2 | avatar: string; 3 | name: string; 4 | id: string; 5 | } 6 | 7 | export interface BasicListItemDataType { 8 | id: string; 9 | owner: string; 10 | title: string; 11 | avatar: string; 12 | cover: string; 13 | status: 'normal' | 'exception' | 'active' | 'success'; 14 | percent: number; 15 | logo: string; 16 | href: string; 17 | body?: any; 18 | updatedAt: number; 19 | createdAt: number; 20 | subDescription: string; 21 | description: string; 22 | activeUser: number; 23 | newUser: number; 24 | star: number; 25 | like: number; 26 | message: number; 27 | content: string; 28 | members: Member[]; 29 | } 30 | -------------------------------------------------------------------------------- /src/app/pages/list/card-list/card-list.component.html: -------------------------------------------------------------------------------- 1 | 2 | card-list.component.html 3 | 4 | 5 | 6 |
7 |

8 | 段落示意:蚂蚁金服务设计平台 ant.design,用最小的工作量,无缝接入蚂蚁金服生态, 9 | 提供跨越设计与开发的体验解决方案。 10 |

11 | 25 |
26 |
27 | 28 | 29 |
30 | 这是一个标题 34 |
35 |
36 | 37 | -------------------------------------------------------------------------------- /src/app/pages/list/card-list/card-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-card-list', 5 | templateUrl: 'card-list.component.html', 6 | styleUrls:['card-list.component.less'], 7 | 8 | }) 9 | export class CardListComponent implements OnInit { 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/list/list-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {TableListComponent} from "./table-list/table-list.component"; 4 | import {BasicListComponent} from "./basic-list/basic-list.component"; 5 | import {CardListComponent} from "./card-list/card-list.component"; 6 | import {ListComponent} from "./list/list.component"; 7 | import {ArticlesComponent} from "./list/articles/articles.component"; 8 | import {ProjectsComponent} from "./list/projects/projects.component"; 9 | import {ApplicationsComponent} from "./list/applications/applications.component"; 10 | import {TableListDetailComponent} from "./table-list/table-list-detail.component"; 11 | 12 | const routes: Routes = [ 13 | {path: '', redirectTo: 'table-list', pathMatch: 'full'}, 14 | { 15 | path: 'table-list', component: TableListComponent, data: { 16 | name: '查询表格', 17 | keepingScroll: true 18 | } 19 | }, 20 | { 21 | path: 'table-list-detail', component: TableListDetailComponent, 22 | data: { 23 | name: '查询表格详情', 24 | reuse: true, 25 | reuseClosable: true, 26 | reuseKeepingScroll: true, 27 | reuseRefreshable: false 28 | } 29 | }, 30 | {path: 'basic-list', component: BasicListComponent, data: {name: '标准列表'}}, 31 | {path: 'card-list', component: CardListComponent, data: {name: '卡片列表'},}, 32 | { 33 | path: 'search', component: ListComponent, data: {name: '搜索列表'}, 34 | children: [ 35 | {path: '', redirectTo: 'articles', pathMatch: 'full'}, 36 | { 37 | path: 'articles', 38 | component: ArticlesComponent, 39 | data: {name: '搜索列表(文章)', guard: {role: ['user1'], ability: [10, 'USER-EDIT'], mode: 'allOf'}} 40 | }, 41 | {path: 'projects', component: ProjectsComponent, data: {name: '搜索列表(项目)'}}, 42 | {path: 'applications', component: ApplicationsComponent, data: {name: '搜索列表(应用)'}} 43 | ] 44 | } 45 | ]; 46 | 47 | @NgModule({ 48 | imports: [RouterModule.forChild(routes)], 49 | exports: [RouterModule] 50 | }) 51 | export class ListRoutingModule { 52 | } 53 | -------------------------------------------------------------------------------- /src/app/pages/list/list.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {BasicListComponent} from "./basic-list/basic-list.component"; 3 | import {CardListComponent} from "./card-list/card-list.component"; 4 | import {ListComponent} from "./list/list.component"; 5 | import {ProjectsComponent} from "./list/projects/projects.component"; 6 | import {ArticlesComponent} from "./list/articles/articles.component"; 7 | import {ApplicationsComponent} from "./list/applications/applications.component"; 8 | import {TableListComponent} from "./table-list/table-list.component"; 9 | import {SharedModule} from "../../shared/shared.module"; 10 | import {ListRoutingModule} from "./list-routing.module"; 11 | import {TableListDetailComponent} from "./table-list/table-list-detail.component"; 12 | 13 | @NgModule({ 14 | imports: [SharedModule, ListRoutingModule], 15 | exports: [], 16 | declarations: [ 17 | BasicListComponent, 18 | CardListComponent, 19 | ListComponent, 20 | ProjectsComponent, 21 | ArticlesComponent, 22 | ApplicationsComponent, 23 | TableListComponent, 24 | TableListDetailComponent 25 | ], 26 | providers: [], 27 | }) 28 | export class ListModule { 29 | } 30 | -------------------------------------------------------------------------------- /src/app/pages/list/list/applications/applications.component.html: -------------------------------------------------------------------------------- 1 | 2 | applications.component.html 3 | 4 | -------------------------------------------------------------------------------- /src/app/pages/list/list/applications/applications.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-list-applications', 5 | templateUrl: 'applications.component.html' 6 | }) 7 | export class ApplicationsComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/list/list/articles/articles.component.html: -------------------------------------------------------------------------------- 1 | 2 | articles.component.html 3 | 4 | -------------------------------------------------------------------------------- /src/app/pages/list/list/articles/articles.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-list-articles', 5 | templateUrl: 'articles.component.html' 6 | }) 7 | export class ArticlesComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/list/list/list.component.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 |
10 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/app/pages/list/list/list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ActivationEnd, Router} from "@angular/router"; 3 | import {filter} from "rxjs/operators"; 4 | 5 | @Component({ 6 | selector: 'app-query-list', 7 | templateUrl: 'list.component.html', 8 | 9 | }) 10 | export class ListComponent implements OnInit { 11 | 12 | tabList = [ 13 | { 14 | key: 'articles', 15 | tab: '文章', 16 | }, 17 | { 18 | key: 'projects', 19 | tab: '项目', 20 | }, 21 | { 22 | key: 'applications', 23 | tab: '应用', 24 | }, 25 | ]; 26 | 27 | tabActiveKey:string; 28 | 29 | constructor(private router: Router) { 30 | } 31 | 32 | ngOnInit() { 33 | this.router.events.pipe( 34 | filter(e => e instanceof ActivationEnd) 35 | ).subscribe(() => this.setActive()); 36 | this.setActive(); 37 | } 38 | 39 | private setActive() { 40 | this.tabActiveKey = this.router.url.substr(this.router.url.lastIndexOf('/') + 1); 41 | } 42 | 43 | 44 | handleFormSubmit() { 45 | console.log('handleFormSubmit'); 46 | } 47 | 48 | handleTabChange(item:{ key: string; tab: string; }){ 49 | this.router.navigateByUrl(`/list/search/${item.key}`); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app/pages/list/list/projects/projects.component.html: -------------------------------------------------------------------------------- 1 | 2 | projects.component.html 3 | 4 | -------------------------------------------------------------------------------- /src/app/pages/list/list/projects/projects.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-list-projects', 5 | templateUrl: 'projects.component.html' 6 | }) 7 | export class ProjectsComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/list/table-list/data.d.ts: -------------------------------------------------------------------------------- 1 | export interface TableListItem { 2 | key: number; 3 | disabled?: boolean; 4 | href: string; 5 | avatar: string; 6 | name: string; 7 | title: string; 8 | owner: string; 9 | desc: string; 10 | callNo: number; 11 | status: number; 12 | updatedAt: Date; 13 | createdAt: Date; 14 | progress: number; 15 | } 16 | 17 | export interface TableListPagination { 18 | total: number; 19 | pageSize: number; 20 | current: number; 21 | } 22 | 23 | export interface TableListData { 24 | list: TableListItem[]; 25 | pagination: Partial; 26 | } 27 | 28 | export interface TableListParams { 29 | sorter: string; 30 | status: string; 31 | name: string; 32 | pageSize: number; 33 | currentPage: number; 34 | } 35 | -------------------------------------------------------------------------------- /src/app/pages/list/table-list/table-list.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | :host ::ng-deep { 4 | .tableList { 5 | .tableListOperator { 6 | margin-bottom: 16px; 7 | button { 8 | margin-right: 8px; 9 | } 10 | } 11 | } 12 | 13 | .tableListForm { 14 | //:global { 15 | .ant-form-item { 16 | display: flex; 17 | margin-right: 0; 18 | margin-bottom: 24px; 19 | > .ant-form-item-label { 20 | width: auto; 21 | padding-right: 8px; 22 | line-height: 32px; 23 | } 24 | .ant-form-item-control { 25 | line-height: 32px; 26 | } 27 | } 28 | .ant-form-item-control-wrapper { 29 | flex: 1; 30 | } 31 | //} 32 | .submitButtons { 33 | display: block; 34 | margin-bottom: 24px; 35 | white-space: nowrap; 36 | } 37 | } 38 | 39 | @media screen and (max-width: @screen-lg) { 40 | .tableListForm :global(.ant-form-item) { 41 | margin-right: 24px; 42 | } 43 | } 44 | 45 | @media screen and (max-width: @screen-md) { 46 | .tableListForm :global(.ant-form-item) { 47 | margin-right: 8px; 48 | } 49 | } 50 | } 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/app/pages/other/other-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {UserListComponent} from "./user-list/user-list.component"; 4 | import {RoleListComponent} from "./role-list/role-list.component"; 5 | import {PermissionListComponent} from "./permission-list/permission-list.component"; 6 | 7 | const routes: Routes = [ 8 | {path: '', redirectTo: 'other', pathMatch: 'full'}, 9 | {path: 'user-list', component: UserListComponent, data: {name: '用户列表'}}, 10 | {path: 'role-list', component: RoleListComponent, data: {name: '角色列表'}}, 11 | {path: 'permission-list', component: PermissionListComponent, data: {name: '权限列表'}} 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class OtherRoutingModule { 19 | } 20 | -------------------------------------------------------------------------------- /src/app/pages/other/other.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {SharedModule} from "@shared/shared.module"; 3 | import {UserListComponent} from "./user-list/user-list.component"; 4 | import {RoleListComponent} from "./role-list/role-list.component"; 5 | import {PermissionListComponent} from "./permission-list/permission-list.component"; 6 | import {OtherRoutingModule} from "./other-routing.module"; 7 | 8 | @NgModule({ 9 | imports: [SharedModule, OtherRoutingModule], 10 | exports: [], 11 | declarations: [ 12 | UserListComponent, 13 | RoleListComponent, 14 | PermissionListComponent 15 | ] 16 | }) 17 | export class OtherModule { 18 | } 19 | -------------------------------------------------------------------------------- /src/app/pages/other/permission-list/permission-list.component.html: -------------------------------------------------------------------------------- 1 | 2 |
权限
3 | 4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /src/app/pages/other/permission-list/permission-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ACLService} from '@delon/acl'; 3 | 4 | @Component({ 5 | selector: 'app-permission-list', 6 | templateUrl: 'permission-list.component.html' 7 | }) 8 | export class PermissionListComponent implements OnInit { 9 | constructor(private aclService: ACLService) { 10 | } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | addRight() { 16 | this.aclService.setAbility([1, 2]) 17 | } 18 | 19 | clearRight(){ 20 | this.aclService.setAbility([]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/app/pages/other/role-list/role-list.component.html: -------------------------------------------------------------------------------- 1 | role-list.component.html 2 | -------------------------------------------------------------------------------- /src/app/pages/other/role-list/role-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-role-list', 5 | templateUrl: 'role-list.component.html' 6 | }) 7 | export class RoleListComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/other/user-list/user-list.component.html: -------------------------------------------------------------------------------- 1 | user-list.component.html 2 | -------------------------------------------------------------------------------- /src/app/pages/other/user-list/user-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user-list', 5 | templateUrl: 'user-list.component.html' 6 | }) 7 | export class UserListComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/pages/profile/advanced-profile/_mock.ts: -------------------------------------------------------------------------------- 1 | const advancedOperation1 = [ 2 | { 3 | key: 'op1', 4 | type: '订购关系生效', 5 | name: '曲丽丽', 6 | status: 'agree', 7 | updatedAt: '2017-10-03 19:23:12', 8 | memo: '-', 9 | }, 10 | { 11 | key: 'op2', 12 | type: '财务复审', 13 | name: '付小小', 14 | status: 'reject', 15 | updatedAt: '2017-10-03 19:23:12', 16 | memo: '不通过原因', 17 | }, 18 | { 19 | key: 'op3', 20 | type: '部门初审', 21 | name: '周毛毛', 22 | status: 'agree', 23 | updatedAt: '2017-10-03 19:23:12', 24 | memo: '-', 25 | }, 26 | { 27 | key: 'op4', 28 | type: '提交订单', 29 | name: '林东东', 30 | status: 'agree', 31 | updatedAt: '2017-10-03 19:23:12', 32 | memo: '很棒', 33 | }, 34 | { 35 | key: 'op5', 36 | type: '创建订单', 37 | name: '汗牙牙', 38 | status: 'agree', 39 | updatedAt: '2017-10-03 19:23:12', 40 | memo: '-', 41 | }, 42 | ]; 43 | 44 | const advancedOperation2 = [ 45 | { 46 | key: 'op1', 47 | type: '订购关系生效', 48 | name: '曲丽丽', 49 | status: 'agree', 50 | updatedAt: '2017-10-03 19:23:12', 51 | memo: '-', 52 | }, 53 | ]; 54 | 55 | const advancedOperation3 = [ 56 | { 57 | key: 'op1', 58 | type: '创建订单', 59 | name: '汗牙牙', 60 | status: 'agree', 61 | updatedAt: '2017-10-03 19:23:12', 62 | memo: '-', 63 | }, 64 | ]; 65 | 66 | const getProfileAdvancedData = { 67 | advancedOperation1, 68 | advancedOperation2, 69 | advancedOperation3, 70 | }; 71 | 72 | export const profile_advanced = { 73 | 'GET /api/profile/advanced': getProfileAdvancedData, 74 | }; 75 | -------------------------------------------------------------------------------- /src/app/pages/profile/advanced-profile/advanced-profile.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .main { 4 | table { 5 | table-layout: fixed; 6 | } 7 | } 8 | 9 | .headerList { 10 | margin-bottom: 4px; 11 | :global { 12 | .ant-descriptions-row > td { 13 | padding-bottom: 8px; 14 | } 15 | } 16 | } 17 | 18 | .tabsCard { 19 | :global { 20 | .ant-card-head { 21 | padding: 0 16px; 22 | } 23 | } 24 | } 25 | 26 | .noData { 27 | color: @disabled-color; 28 | font-size: 16px; 29 | line-height: 64px; 30 | text-align: center; 31 | i { 32 | position: relative; 33 | top: 3px; 34 | margin-right: 16px; 35 | font-size: 24px; 36 | } 37 | } 38 | 39 | .heading { 40 | color: @heading-color; 41 | font-size: 20px; 42 | } 43 | 44 | .stepDescription { 45 | position: relative; 46 | left: 38px; 47 | padding-top: 8px; 48 | font-size: 14px; 49 | text-align: left; 50 | 51 | > div { 52 | margin-top: 8px; 53 | margin-bottom: 4px; 54 | } 55 | } 56 | 57 | .textSecondary { 58 | color: @text-color-secondary; 59 | } 60 | 61 | @media screen and (max-width: @screen-sm) { 62 | .stepDescription { 63 | left: 8px; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/app/pages/profile/advanced-profile/advanced-profile.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, OnInit} from '@angular/core'; 2 | import {HttpClient} from "@angular/common/http"; 3 | import {NzMessageService} from "ng-zorro-antd/message"; 4 | 5 | @Component({ 6 | selector: 'app-advanced-profile', 7 | templateUrl: 'advanced-profile.component.html', 8 | styleUrls: ['advanced-profile.component.less'], 9 | 10 | }) 11 | export class AdvancedProfileComponent implements OnInit { 12 | 13 | tabList=[{key: 'detail',tab: '详情',},{key: 'rule',tab: '规则',}]; 14 | 15 | data = { 16 | advancedOperation1: [], 17 | advancedOperation2: [], 18 | advancedOperation3: [], 19 | }; 20 | 21 | operationKey:string; 22 | 23 | constructor(public messageService: NzMessageService, 24 | private httpClient: HttpClient, 25 | private cdr: ChangeDetectorRef) { 26 | } 27 | 28 | ngOnInit() { 29 | this.httpClient.get('/api/profile/advanced').subscribe((res: any) => { 30 | this.data = res; 31 | // this.change({ index: 0, tab: null! }); 32 | // this.cdr.detectChanges(); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/pages/profile/basic-profile/_mock.ts: -------------------------------------------------------------------------------- 1 | const basicGoods = [ 2 | { 3 | id: '1234561', 4 | name: '矿泉水 550ml', 5 | barcode: '12421432143214321', 6 | price: '2.00', 7 | num: '1', 8 | amount: '2.00', 9 | }, 10 | { 11 | id: '1234562', 12 | name: '凉茶 300ml', 13 | barcode: '12421432143214322', 14 | price: '3.00', 15 | num: '2', 16 | amount: '6.00', 17 | }, 18 | { 19 | id: '1234563', 20 | name: '好吃的薯片', 21 | barcode: '12421432143214323', 22 | price: '7.00', 23 | num: '4', 24 | amount: '28.00', 25 | }, 26 | { 27 | id: '1234564', 28 | name: '特别好吃的蛋卷', 29 | barcode: '12421432143214324', 30 | price: '8.50', 31 | num: '3', 32 | amount: '25.50', 33 | }, 34 | ]; 35 | 36 | const basicProgress = [ 37 | { 38 | key: '1', 39 | time: '2017-10-01 14:10', 40 | rate: '联系客户', 41 | status: 'processing', 42 | operator: '取货员 ID1234', 43 | cost: '5mins', 44 | }, 45 | { 46 | key: '2', 47 | time: '2017-10-01 14:05', 48 | rate: '取货员出发', 49 | status: 'success', 50 | operator: '取货员 ID1234', 51 | cost: '1h', 52 | }, 53 | { 54 | key: '3', 55 | time: '2017-10-01 13:05', 56 | rate: '取货员接单', 57 | status: 'success', 58 | operator: '取货员 ID1234', 59 | cost: '5mins', 60 | }, 61 | { 62 | key: '4', 63 | time: '2017-10-01 13:00', 64 | rate: '申请审批通过', 65 | status: 'success', 66 | operator: '系统', 67 | cost: '1h', 68 | }, 69 | { 70 | key: '5', 71 | time: '2017-10-01 12:00', 72 | rate: '发起退货申请', 73 | status: 'success', 74 | operator: '用户', 75 | cost: '5mins', 76 | }, 77 | ]; 78 | 79 | const getProfileBasicData = { 80 | basicGoods, 81 | basicProgress, 82 | }; 83 | 84 | export const profile_basic = { 85 | 'GET /api/profile/basic': getProfileBasicData, 86 | }; 87 | -------------------------------------------------------------------------------- /src/app/pages/profile/basic-profile/basic-profile.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1000000000 5 | 已取货 6 | 1234123421 7 | 3214321432 8 | 9 | 10 | 11 | 付小小 12 | 18100000000 13 | 菜鸟仓储 14 | 浙江省杭州市西湖区万塘路18号 15 | 16 | 17 | 18 |
退货商品
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
退货进度
42 |
43 | 44 |
45 | -------------------------------------------------------------------------------- /src/app/pages/profile/basic-profile/basic-profile.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .title { 4 | margin-bottom: 16px; 5 | color: @heading-color; 6 | font-weight: 500; 7 | font-size: 16px; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/pages/profile/basic-profile/basic-profile.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-basic-profile', 5 | templateUrl: 'basic-profile.component.html', 6 | styleUrls: ['basic-profile.component.less'], 7 | 8 | }) 9 | export class BasicProfileComponent implements OnInit { 10 | constructor() { 11 | } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | get settings() { 17 | return null; 18 | // return this.settingsService.settings; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/pages/profile/profile-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {BasicProfileComponent} from "./basic-profile/basic-profile.component"; 4 | import {AdvancedProfileComponent} from "./advanced-profile/advanced-profile.component"; 5 | 6 | const routes: Routes = [ 7 | {path: '', redirectTo: 'basic', pathMatch: 'full'}, 8 | {path: 'basic', component: BasicProfileComponent, data: {name: '基础详情页'}}, 9 | {path: 'advanced', component: AdvancedProfileComponent, data: {name: '高级详情页'}} 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule] 15 | }) 16 | export class ProfileRoutingModule { 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/profile/profile.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {AdvancedProfileComponent} from "./advanced-profile/advanced-profile.component"; 4 | import {BasicProfileComponent} from "./basic-profile/basic-profile.component"; 5 | import {SharedModule} from "@shared/shared.module"; 6 | import {ProfileRoutingModule} from "./profile-routing.module"; 7 | 8 | @NgModule({ 9 | imports: [SharedModule, ProfileRoutingModule], 10 | exports: [], 11 | declarations: [ 12 | AdvancedProfileComponent, 13 | BasicProfileComponent 14 | ], 15 | providers: [], 16 | }) 17 | export class ProfileModule { 18 | } 19 | -------------------------------------------------------------------------------- /src/app/pages/result/fail/fail.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 |
9 | 您提交的内容有如下错误: 10 |
11 |
12 | 13 | 您的账户已被冻结 14 | 15 | 立即解冻 16 | 17 |
18 |
19 | 20 | 您的账户还不具备申请资格 21 | 22 | 立即升级 23 | 24 |
25 |
26 |
27 |
28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/app/pages/result/fail/fail.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .error_icon { 4 | color: @highlight-color; 5 | } 6 | .title { 7 | margin-bottom: 16px; 8 | color: @heading-color; 9 | font-weight: 500; 10 | font-size: 16px; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/pages/result/fail/fail.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'pro-error', 5 | templateUrl: 'fail.component.html', 6 | styleUrls: ['fail.component.less'] 7 | }) 8 | export class FailComponent implements OnInit { 9 | constructor() { 10 | } 11 | 12 | ngOnInit() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/pages/result/result-routing.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {Routes, RouterModule} from '@angular/router'; 3 | import {SuccessComponent} from "./success/success.component"; 4 | import {FailComponent} from "./fail/fail.component"; 5 | 6 | const routes: Routes = [ 7 | {path: '', redirectTo: 'success', pathMatch: 'full'}, 8 | {path: 'success', component: SuccessComponent, data: {name: '成功', reuse: false}}, 9 | {path: 'fail', component: FailComponent, data: {name: '失败', reuse: false}} 10 | ]; 11 | 12 | @NgModule({ 13 | imports: [RouterModule.forChild(routes)], 14 | exports: [RouterModule] 15 | }) 16 | export class ResultRoutingModule { 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/result/result.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {SharedModule} from "../../shared/shared.module"; 3 | import {SuccessComponent} from "./success/success.component"; 4 | import {FailComponent} from "./fail/fail.component"; 5 | import {ResultRoutingModule} from "./result-routing.module"; 6 | 7 | @NgModule({ 8 | imports: [SharedModule, ResultRoutingModule], 9 | exports: [], 10 | declarations: [ 11 | SuccessComponent, 12 | FailComponent 13 | ], 14 | providers: [], 15 | }) 16 | export class ResultModule { 17 | } 18 | -------------------------------------------------------------------------------- /src/app/pages/result/success/success.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 23421 10 | 曲丽丽 11 | 2016-12-12 ~ 2017-12-12 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 | 24 | 25 | 创建项目 26 | 27 | 28 | 部门初审 29 | 30 | 31 | 财务复核 32 | 33 | 34 | 完成 35 | 36 | 37 | 38 |
39 |
40 | 曲丽丽 41 | 42 |
43 |
2016-12-12 12:32
44 |
45 |
46 | 47 |
48 |
49 | 周毛毛 50 | 51 | 52 | 催一下 53 | 54 |
55 |
56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/app/pages/result/success/success.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .title { 4 | position: relative; 5 | color: @text-color; 6 | font-size: 12px; 7 | text-align: center; 8 | } 9 | 10 | .head-title { 11 | margin-bottom: 20px; 12 | color: @heading-color; 13 | font-weight: 500; 14 | font-size: 16px; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/pages/result/success/success.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-success', 5 | templateUrl: 'success.component.html', 6 | styleUrls: ['success.component.less'] 7 | }) 8 | export class SuccessComponent implements OnInit { 9 | constructor() { 10 | } 11 | 12 | ngOnInit() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/pages/user/login/login.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .main { 4 | width: 368px; 5 | margin: 0 auto; 6 | @media screen and (max-width: @screen-sm) { 7 | width: 95%; 8 | } 9 | 10 | .icon { 11 | margin-left: 16px; 12 | color: rgba(0, 0, 0, 0.2); 13 | font-size: 24px; 14 | vertical-align: middle; 15 | cursor: pointer; 16 | transition: color 0.3s; 17 | 18 | &:hover { 19 | color: @primary-color; 20 | } 21 | } 22 | 23 | .other { 24 | margin-top: 24px; 25 | line-height: 22px; 26 | text-align: left; 27 | 28 | .register { 29 | float: right; 30 | } 31 | } 32 | 33 | ::ng-deep { 34 | .antd-pro-login-submit { 35 | width: 100%; 36 | margin-top: 24px; 37 | } 38 | } 39 | 40 | //===== 41 | .login { 42 | ::ng-deep { 43 | .ant-tabs .ant-tabs-bar { 44 | margin-bottom: 24px; 45 | text-align: center; 46 | border-bottom: 0; 47 | } 48 | 49 | .ant-form-item { 50 | margin: 0 2px 24px; 51 | } 52 | } 53 | 54 | .getCaptcha { 55 | display: block; 56 | width: 100%; 57 | } 58 | 59 | .icon { 60 | margin-left: 16px; 61 | color: rgba(0, 0, 0, 0.2); 62 | font-size: 24px; 63 | vertical-align: middle; 64 | cursor: pointer; 65 | transition: color 0.3s; 66 | 67 | &:hover { 68 | color: @primary-color; 69 | } 70 | } 71 | 72 | .other { 73 | margin-top: 24px; 74 | line-height: 22px; 75 | text-align: left; 76 | 77 | .register { 78 | float: right; 79 | } 80 | } 81 | 82 | .prefixIcon { 83 | color: @disabled-color; 84 | font-size: @font-size-base; 85 | } 86 | 87 | .submit { 88 | width: 100%; 89 | margin-top: 24px; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/app/pages/user/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {FormBuilder, FormGroup, Validators} from "@angular/forms"; 3 | import {Router} from "@angular/router"; 4 | 5 | @Component({ 6 | selector: 'app-login', 7 | templateUrl: 'login.component.html', 8 | styleUrls: ['login.component.less'] 9 | }) 10 | export class LoginComponent implements OnInit { 11 | 12 | form: FormGroup; 13 | 14 | constructor(private formBuilder: FormBuilder, 15 | private router:Router) { 16 | this.form = this.formBuilder.group({ 17 | userName: [null, [Validators.required, Validators.minLength(4)]], 18 | password: [null, Validators.required], 19 | mobile: [null, [Validators.required, Validators.pattern(/^1\d{10}$/)]], 20 | captcha: [null, [Validators.required]], 21 | remember: [true], 22 | }); 23 | } 24 | 25 | ngOnInit() { 26 | } 27 | 28 | submit() { 29 | this.router.navigate(['/']); 30 | } 31 | 32 | getCaptcha(event) { 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'user-register-result.login.userName': 'userName', 3 | 'user-register-result.login.password': 'password', 4 | 'user-register-result.login.message-invalid-credentials': 5 | 'Invalid username or password(admin/ant.design)', 6 | 'user-register-result.login.message-invalid-verification-code': 'Invalid verification code', 7 | 'user-register-result.login.tab-login-credentials': 'Credentials', 8 | 'user-register-result.login.tab-login-mobile': 'Mobile number', 9 | 'user-register-result.login.remember-me': 'Remember me', 10 | 'user-register-result.login.forgot-password': 'Forgot your password?', 11 | 'user-register-result.login.sign-in-with': 'Sign in with', 12 | 'user-register-result.login.signup': 'Sign up', 13 | 'user-register-result.login.login': 'Login', 14 | 'user-register-result.register.register': 'Register', 15 | 'user-register-result.register.get-verification-code': 'Get code', 16 | 'user-register-result.register.sign-in': 'Already have an account?', 17 | 'user-register-result.register-result.msg': 'Account:registered at {{email}}', 18 | 'user-register-result.register-result.activation-email': 19 | 'The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.', 20 | 'user-register-result.register-result.back-home': 'Back to home', 21 | 'user-register-result.register-result.view-mailbox': 'View mailbox', 22 | 'user-register-result.navBar.lang': 'Languages', 23 | }; 24 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'user-register-result.login.userName': '用户名', 3 | 'user-register-result.login.password': '密码', 4 | 'user-register-result.login.message-invalid-credentials': '账户或密码错误(admin/ant.design)', 5 | 'user-register-result.login.message-invalid-verification-code': '验证码错误', 6 | 'user-register-result.login.tab-login-credentials': '账户密码登录', 7 | 'user-register-result.login.tab-login-mobile': '手机号登录', 8 | 'user-register-result.login.remember-me': '自动登录', 9 | 'user-register-result.login.forgot-password': '忘记密码', 10 | 'user-register-result.login.sign-in-with': '其他登录方式', 11 | 'user-register-result.login.signup': '注册账户', 12 | 'user-register-result.login.login': '登录', 13 | 'user-register-result.register.register': '注册', 14 | 'user-register-result.register.get-verification-code': '获取验证码', 15 | 'user-register-result.register.sign-in': '使用已有账户登录', 16 | 'user-register-result.register-result.msg': '你的账户:{{email}} 注册成功', 17 | 'user-register-result.register-result.activation-email': 18 | '激活邮件已发送到你的邮箱中,邮件有效期为24小时。请及时登录邮箱,点击邮件中的链接激活帐户。', 19 | 'user-register-result.register-result.back-home': '返回首页', 20 | 'user-register-result.register-result.view-mailbox': '查看邮箱', 21 | 'user-register-result.navBar.lang': '语言', 22 | }; 23 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | 'user-register-result.login.userName': '賬戶', 3 | 'user-register-result.login.password': '密碼', 4 | 'user-register-result.login.message-invalid-credentials': '賬戶或密碼錯誤(admin/ant.design)', 5 | 'user-register-result.login.message-invalid-verification-code': '驗證碼錯誤', 6 | 'user-register-result.login.tab-login-credentials': '賬戶密碼登錄', 7 | 'user-register-result.login.tab-login-mobile': '手機號登錄', 8 | 'user-register-result.login.remember-me': '自動登錄', 9 | 'user-register-result.login.forgot-password': '忘記密碼', 10 | 'user-register-result.login.sign-in-with': '其他登錄方式', 11 | 'user-register-result.login.signup': '註冊賬戶', 12 | 'user-register-result.login.login': '登錄', 13 | 'user-register-result.register.register': '註冊', 14 | 'user-register-result.register.get-verification-code': '獲取驗證碼', 15 | 'user-register-result.register.sign-in': '使用已有賬戶登錄', 16 | 'user-register-result.register-result.msg': '妳的賬戶:{{email}} 註冊成功', 17 | 'user-register-result.register-result.activation-email': 18 | '激活郵件已發送到妳的郵箱中,郵件有效期為24小時。請及時登錄郵箱,點擊郵件中的鏈接激活帳戶。', 19 | 'user-register-result.register-result.back-home': '返回首頁', 20 | 'user-register-result.register-result.view-mailbox': '查看郵箱', 21 | 'user-register-result.navBar.lang': '語言', 22 | }; 23 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/register-result.component.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 |
10 | {{ 'user-register-result.register-result.msg' | translate:params}} 11 |
12 |
13 | 14 | 15 | 27 | 28 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/register-result.component.less: -------------------------------------------------------------------------------- 1 | .antd-pro-pages-user-register-result-registerResult { 2 | 3 | width: 800px; 4 | min-height: 400px; 5 | margin: auto; 6 | padding: 80px; 7 | background: none; 8 | 9 | .anticon { 10 | font-size: 64px; 11 | } 12 | .antd-pro-pages-user-register-result-title { 13 | margin-top: 32px; 14 | font-size: 20px; 15 | line-height: 28px; 16 | } 17 | .antd-pro-pages-user-register-result-actions { 18 | margin-top: 40px; 19 | a + a { 20 | margin-left: 8px; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/app/pages/user/register-result/register-result.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {NzMessageService} from "ng-zorro-antd/message"; 3 | import {ActivatedRoute} from "@angular/router"; 4 | 5 | @Component({ 6 | selector: 'app-register-result', 7 | templateUrl: 'register-result.component.html', 8 | styleUrls: ['register-result.component.less'] 9 | }) 10 | export class RegisterResultComponent implements OnInit { 11 | 12 | prefixedClassName = 'antd-pro-pages-user-register-result'; 13 | params = { email: '' }; 14 | email = ''; 15 | constructor(route: ActivatedRoute, public messageService: NzMessageService) { 16 | this.params.email = this.email = route.snapshot.queryParams.email || 'AntDesign@example.com'; 17 | } 18 | 19 | ngOnInit(): void { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/app/pages/user/register/register.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .main { 4 | width: 368px; 5 | margin: 0 auto; 6 | 7 | :global { 8 | .ant-form-item { 9 | margin-bottom: 24px; 10 | } 11 | } 12 | 13 | h3 { 14 | margin-bottom: 20px; 15 | font-size: 16px; 16 | } 17 | 18 | .getCaptcha { 19 | display: block; 20 | width: 100%; 21 | } 22 | 23 | .submit { 24 | width: 50%; 25 | } 26 | 27 | .login { 28 | float: right; 29 | line-height: @btn-height-lg; 30 | } 31 | } 32 | 33 | .success, 34 | .warning, 35 | .error { 36 | transition: color 0.3s; 37 | } 38 | 39 | .success { 40 | color: @success-color; 41 | } 42 | 43 | .warning { 44 | color: @warning-color; 45 | } 46 | 47 | .error { 48 | color: @error-color; 49 | } 50 | 51 | .progress-pass > .progress { 52 | :global { 53 | .ant-progress-bg { 54 | background-color: @warning-color; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/pages/user/user.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {SharedModule} from "../../shared/shared.module"; 4 | import {LoginComponent} from "./login/login.component"; 5 | import {RegisterComponent} from "./register/register.component"; 6 | import {RegisterResultComponent} from "./register-result/register-result.component"; 7 | 8 | const COMPONENTS=[ 9 | LoginComponent, 10 | RegisterComponent, 11 | RegisterResultComponent, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: [SharedModule], 16 | exports: [...COMPONENTS], 17 | declarations: [...COMPONENTS], 18 | providers: [], 19 | }) 20 | export class UserModule { 21 | } 22 | -------------------------------------------------------------------------------- /src/app/shared/components/copy-block/copy-block.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/shared/components/copy-block/copy-block.component.html -------------------------------------------------------------------------------- /src/app/shared/components/copy-block/copy-block.component.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/shared/components/copy-block/copy-block.component.less -------------------------------------------------------------------------------- /src/app/shared/components/copy-block/copy-block.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'pro-copy-block', 5 | templateUrl: 'copy-block.component.html' 6 | }) 7 | export class CopyBlockComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/shared/components/global-header/avatar-dropdown/avatar-dropdown.component.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |
    12 |
  • 13 | 14 | {{ 'menu.account.center' | translate }} 15 |
  • 16 |
  • 17 | 18 | {{ 'menu.account.settings'| translate}} 19 |
  • 20 |
  • 21 | 22 | {{ 'menu.account.logout'| translate}} 23 |
  • 24 |
25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 | -------------------------------------------------------------------------------- /src/app/shared/components/global-header/avatar-dropdown/avatar-dropdown.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core'; 2 | import {CurrentUser} from '../../../models/user'; 3 | import {Router} from "@angular/router"; 4 | 5 | export interface GlobalHeaderRightProps { 6 | currentUser?: CurrentUser; 7 | menu?: boolean; 8 | } 9 | 10 | @Component({ 11 | selector: 'pro-avatar-dropdown', 12 | templateUrl: 'avatar-dropdown.component.html', 13 | 14 | }) 15 | export class AvatarDropdownComponent implements OnInit { 16 | 17 | @Input() className: any = 'action'; 18 | @Input() currentUser: GlobalHeaderRightProps['currentUser']; 19 | @Input() menu = true; 20 | 21 | constructor(private cdf: ChangeDetectorRef, 22 | private router: Router) { 23 | } 24 | 25 | ngOnInit() { 26 | this.currentUser = { 27 | avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', 28 | name: 'ant design' 29 | }; 30 | } 31 | 32 | logout() { 33 | this.router.navigate(['/user/login'],{ replaceUrl: true }).then(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/app/shared/components/global-header/notice-icon-view/notice-icon-view.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/shared/components/global-header/right-content/right-content.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | -------------------------------------------------------------------------------- /src/app/shared/components/global-header/right-content/right-content.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'pro-right-content', 5 | templateUrl: 'right-content.component.html', 6 | styleUrls: ['right-content.component.less'], 7 | changeDetection: ChangeDetectionStrategy.OnPush, 8 | }) 9 | export class RightContentComponent { 10 | 11 | @Input() theme: any; 12 | @Input() layout: string; 13 | 14 | constructor() { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/shared/components/header-dropdown/header-dropdown.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/app/shared/components/header-dropdown/header-dropdown.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .container > * { 4 | background-color: #fff; 5 | border-radius: 4px; 6 | box-shadow: @shadow-1-down; 7 | } 8 | 9 | @media screen and (max-width: @screen-xs) { 10 | .container { 11 | width: 100% !important; 12 | } 13 | .container > * { 14 | border-radius: 0 !important; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/shared/components/header-dropdown/header-dropdown.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input, OnInit, TemplateRef, ViewEncapsulation} from '@angular/core'; 2 | 3 | export interface HeaderDropdownProps { 4 | overlayClassName?: string; 5 | overlay: TemplateRef; 6 | placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter'; 7 | } 8 | 9 | @Component({ 10 | selector: 'pro-header-dropdown', 11 | templateUrl: 'header-dropdown.component.html', 12 | styleUrls: ['header-dropdown.component.less'], 13 | 14 | encapsulation: ViewEncapsulation.None, 15 | exportAs: 'proHeaderDropdown', 16 | preserveWhitespaces: false 17 | }) 18 | export class HeaderDropdownComponent implements OnInit { 19 | 20 | @Input() overlayClassName: string; 21 | @Input() overlay: TemplateRef; 22 | @Input() placement: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter' 23 | 24 | 25 | prefixedClassName = 'antd-pro-components-header-dropdown-index'; 26 | 27 | 28 | constructor() { 29 | } 30 | 31 | ngOnInit() { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/shared/components/header-search/header-search.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/app/shared/components/header-search/header-search.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | :host ::ng-deep { 4 | 5 | .headerSearch { 6 | //:global(.anticon-search) { 7 | .anticon-search { 8 | font-size: 16px; 9 | cursor: pointer; 10 | } 11 | .input { 12 | width: 0; 13 | background: transparent; 14 | border-radius: 0; 15 | transition: width 0.3s, margin-left 0.3s; 16 | //:global(.ant-select-selection) { 17 | .ant-select-selection { 18 | background: transparent; 19 | } 20 | input { 21 | padding-right: 0; 22 | padding-left: 0; 23 | border: 0; 24 | box-shadow: none !important; 25 | } 26 | &, 27 | &:hover, 28 | &:focus { 29 | border-bottom: 1px solid @border-color-base; 30 | } 31 | &.show { 32 | width: 210px; 33 | margin-left: 8px; 34 | } 35 | } 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/shared/components/header-search/header-search.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | ElementRef, 4 | EventEmitter, 5 | Input, 6 | OnInit, 7 | Output, 8 | ViewChild, 9 | } from '@angular/core'; 10 | 11 | @Component({ 12 | selector: 'pro-header-search', 13 | templateUrl: 'header-search.component.html', 14 | styleUrls: ['header-search.component.less'], 15 | }) 16 | export class HeaderSearchComponent implements OnInit { 17 | 18 | @Input() dataSource: Array; 19 | @Input() placeholder = 'Search'; 20 | @Output() search: EventEmitter = new EventEmitter(); 21 | 22 | @ViewChild('input', {static: true}) inputRef: ElementRef; 23 | searchMode = false; 24 | inputValue = ''; 25 | options = []; 26 | 27 | constructor() { 28 | } 29 | 30 | ngOnInit() { 31 | this.options = this.dataSource; 32 | } 33 | 34 | onInput(event): void { 35 | this.inputValue = event.target && event.target.value; 36 | } 37 | 38 | onSearch(option) { 39 | this.searchMode = true; 40 | this.search.emit(option); 41 | } 42 | 43 | onKeyDown() { 44 | 45 | } 46 | 47 | enterSearchMode(event: Event): void { 48 | this.searchMode = true; 49 | if (this.searchMode && this.inputRef) { 50 | this.inputRef.nativeElement.focus(); 51 | } 52 | } 53 | 54 | leaveSearchMode(): void { 55 | this.inputValue = ''; 56 | this.searchMode = false; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/app/shared/components/index.ts: -------------------------------------------------------------------------------- 1 | import {BasicLayoutComponent} from '../layout/basic-layout/basic-layout.component'; 2 | import {RightContentComponent} from './global-header/right-content/right-content.component'; 3 | import {AvatarDropdownComponent} from './global-header/avatar-dropdown/avatar-dropdown.component'; 4 | import {NoticeIconViewComponent} from './global-header/notice-icon-view/notice-icon-view.component'; 5 | import {HeaderSearchComponent} from './header-search/header-search.component'; 6 | import {SelectLangComponent} from './select-lang/select-lang.component'; 7 | import {HeaderDropdownComponent} from './header-dropdown/header-dropdown.component'; 8 | import {CopyBlockComponent} from "./copy-block/copy-block.component"; 9 | import {PageLoadingComponent} from "./page-loading/page-loading.component"; 10 | import {NoticeIconComponent} from "./notice-icon/notice-icon.component"; 11 | import {ResultComponent} from "@shared/components/result/result.component"; 12 | import {NoticeListComponent} from "@shared/components/notice-icon/notice-list/notice-list.component"; 13 | 14 | export const Components = [ 15 | BasicLayoutComponent, 16 | RightContentComponent, 17 | AvatarDropdownComponent, 18 | NoticeIconViewComponent, 19 | HeaderSearchComponent, 20 | SelectLangComponent, 21 | HeaderDropdownComponent, 22 | CopyBlockComponent, 23 | PageLoadingComponent, 24 | NoticeIconComponent, 25 | ResultComponent, 26 | NoticeListComponent 27 | ]; 28 | -------------------------------------------------------------------------------- /src/app/shared/components/notice-icon/notice-icon.component.html: -------------------------------------------------------------------------------- 1 |
8 | 9 |
10 | 11 | 12 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/app/shared/components/notice-icon/notice-icon.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .popover { 4 | position: relative; 5 | width: 336px; 6 | } 7 | 8 | .noticeButton { 9 | display: inline-block; 10 | cursor: pointer; 11 | transition: all 0.3s; 12 | } 13 | .icon { 14 | padding: 4px; 15 | vertical-align: middle; 16 | } 17 | 18 | .badge { 19 | font-size: 16px; 20 | } 21 | 22 | .tabs { 23 | //:global { 24 | ::ng-deep.ant-tabs-nav-scroll { 25 | text-align: center; 26 | } 27 | ::ng-deep.ant-tabs-bar { 28 | margin-bottom: 0; 29 | } 30 | //} 31 | } 32 | -------------------------------------------------------------------------------- /src/app/shared/components/notice-icon/notice-icon.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; 2 | import {NoticeIconData} from "@shared/components/notice-icon/notice-list/notice-list.component"; 3 | 4 | export interface NoticeItem { 5 | title: string; 6 | list: NoticeIconData[]; 7 | emptyText: string; //空列表文本,默认:`无通知` 8 | emptyImage: string; //空列表图像 9 | clearText: string; //清空文本,默认:`清空`, 10 | viewMoreText: string; 11 | } 12 | 13 | @Component({ 14 | selector: 'pro-notice-icon', 15 | templateUrl: 'notice-icon.component.html', 16 | styleUrls: ['notice-icon.component.less'] 17 | }) 18 | export class NoticeIconComponent { 19 | 20 | @Input() data: NoticeItem[] = []; 21 | 22 | @Input() count: number = 2; 23 | @Input() bell: any; 24 | @Input() className: string; 25 | @Input() loading: boolean; 26 | @Output() readonly onClear = new EventEmitter(); 27 | @Output() readonly onItemClick = new EventEmitter(); 28 | @Output() readonly onViewMore = new EventEmitter(); 29 | @Output() readonly onTabChange = new EventEmitter(); 30 | @Input() style: string; 31 | @Output() readonly onPopupVisibleChange = new EventEmitter(); 32 | @Input() popupVisible: boolean; 33 | @Input() clearText: string; 34 | @Input() viewMoreText: string; 35 | @Input() clearClose: boolean; 36 | 37 | constructor() { 38 | } 39 | 40 | handleVisibleChange(result: boolean) { 41 | this.popupVisible = !this.popupVisible; 42 | this.onPopupVisibleChange.emit(result); 43 | } 44 | 45 | onClick(item: NoticeIconData) { 46 | 47 | } 48 | 49 | clearNotice(event: Event) { 50 | } 51 | 52 | viewMore(event: Event) { 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/app/shared/components/notice-icon/notice-list/notice-list.component.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 10 | 11 |
12 | {{item.title}} 13 |
14 | {{item.extra}} 15 |
16 |
17 |
18 | 19 |
{{item.description}}
20 |
{{item.datetime}}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | {{clearText}} {{title}} 29 |
30 |
31 | {{viewMoreText}} 32 |
33 |
34 | -------------------------------------------------------------------------------- /src/app/shared/components/notice-icon/notice-list/notice-list.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; 2 | 3 | export interface NoticeIconData { 4 | avatar?: string; //头像图片链接 5 | title?: string;//标题 6 | description?: string;//描述信息 7 | datetime?: string;//时间戳 8 | extra?: string; //额外信息,在列表项右上角 9 | style?: any; 10 | key?: string | number; 11 | read?: boolean; //是否已读状态 12 | } 13 | 14 | @Component({ 15 | selector: 'pro-notice-list', 16 | templateUrl: 'notice-list.component.html', 17 | styleUrls: ['notice-list.component.less'] 18 | }) 19 | export class NoticeListComponent implements OnInit { 20 | 21 | @Input() data: NoticeIconData[] = []; 22 | @Output() readonly onClick = new EventEmitter(); 23 | @Output() readonly onClear = new EventEmitter(); 24 | @Input() title: string; 25 | @Output() readonly onViewMore = new EventEmitter(); 26 | @Input() emptyText: string; 27 | @Input() showClear = true; 28 | @Input() clearText: string; 29 | @Input() viewMoreText: string; 30 | @Input() showViewMore = false; 31 | 32 | constructor() { 33 | } 34 | 35 | ngOnInit() { 36 | } 37 | 38 | handleClick(item) { 39 | this.onClick.emit(item); 40 | } 41 | 42 | 43 | clearNotice(event: Event) { 44 | this.onClear.emit(event); 45 | } 46 | 47 | viewMore(event: Event) { 48 | this.onViewMore.emit(event); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/shared/components/page-loading/page-loading.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/shared/components/page-loading/page-loading.component.html -------------------------------------------------------------------------------- /src/app/shared/components/page-loading/page-loading.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page-loading', 5 | templateUrl: 'page-loading.component.html' 6 | }) 7 | export class PageLoadingComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/shared/components/result/result.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | @result-prefix-cls: ~'@{ant-prefix}-result'; 4 | 5 | .@{result-prefix-cls} { 6 | padding: 48px 32px; 7 | // status color 8 | &-success &-icon > .anticon { 9 | color: @success-color; 10 | } 11 | 12 | &-error &-icon > .anticon { 13 | color: @error-color; 14 | } 15 | 16 | &-info &-icon > .anticon { 17 | color: @info-color; 18 | } 19 | 20 | &-warning &-icon > .anticon { 21 | color: @warning-color; 22 | } 23 | 24 | // Exception Status image 25 | &-image { 26 | width: 250px; 27 | height: 295px; 28 | margin: auto; 29 | } 30 | 31 | &-icon { 32 | margin-bottom: 24px; 33 | text-align: center; 34 | 35 | > .anticon { 36 | font-size: 72px; 37 | } 38 | } 39 | 40 | &-title { 41 | color: @heading-color; 42 | font-size: 24px; 43 | line-height: 1.8; 44 | text-align: center; 45 | } 46 | 47 | &-subtitle { 48 | color: @text-color-secondary; 49 | font-size: 14px; 50 | line-height: 1.6; 51 | text-align: center; 52 | } 53 | 54 | &-extra { 55 | margin-top: 32px; 56 | text-align: center; 57 | > * { 58 | margin-right: 8px; 59 | } 60 | } 61 | 62 | &-content { 63 | margin-top: 24px; 64 | padding: 24px 40px; 65 | background-color: @background-color-light; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/app/shared/components/result/result.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | Renderer2, 8 | TemplateRef, 9 | ViewChild, ViewEncapsulation 10 | } from '@angular/core'; 11 | import { isNil } from 'ng-zorro-antd/core/util'; 12 | 13 | export const IconMap = { 14 | 'success': 'check-circle', 15 | 'error': 'close-circle', 16 | 'info': 'exclamation-circle', 17 | 'warning': 'warning', 18 | }; 19 | 20 | export const ExceptionMap = { 21 | '404': '404', 22 | '500': '500', 23 | '403': '403', 24 | }; 25 | 26 | export type ExceptionStatusType = keyof typeof ExceptionMap; 27 | export type ResultStatusType = ExceptionStatusType | keyof typeof IconMap; 28 | 29 | @Component({ 30 | selector: 'pro-result', 31 | templateUrl: 'result.component.html', 32 | styleUrls: ['result.component.less'], 33 | 34 | encapsulation: ViewEncapsulation.None, 35 | exportAs: 'proResult', 36 | preserveWhitespaces: false 37 | }) 38 | export class ResultComponent implements OnInit, AfterViewInit { 39 | 40 | @Input() title: string | TemplateRef; 41 | @Input() subTitle: string | TemplateRef; 42 | @Input() status: ResultStatusType; 43 | @Input() icon: string | TemplateRef; 44 | @Input() extra: TemplateRef; 45 | 46 | @ViewChild('contentTemplate', {static: true}) 47 | private contentTemplate: ElementRef; 48 | 49 | exceptionStatus = Object.keys(ExceptionMap); 50 | iconStatus=Object.keys(IconMap); 51 | iconMap = IconMap; 52 | 53 | constructor(private renderer: Renderer2) { 54 | } 55 | 56 | ngOnInit() { 57 | console.log(this.contentTemplate); 58 | 59 | } 60 | 61 | ngAfterViewInit(): void { 62 | this.checkContent(); 63 | } 64 | 65 | checkContent() { 66 | if (isNil(this.contentTemplate.nativeElement)) { 67 | this.renderer.setStyle(this.contentTemplate.nativeElement, 'display', 'none'); 68 | } else { 69 | this.renderer.removeStyle(this.contentTemplate.nativeElement, 'display'); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/app/shared/components/select-lang/select-lang.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
    6 | 7 |
  • 10 | 11 | {{languages[locale].icon}} 12 | 13 | {{ languages[locale].label }} 14 |
  • 15 |
    16 |
17 |
18 | 19 | -------------------------------------------------------------------------------- /src/app/shared/components/select-lang/select-lang.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | :host ::ng-deep { 4 | .menu { 5 | .anticon { 6 | margin-right: 8px; 7 | } 8 | .ant-dropdown-menu-item { 9 | min-width: 160px; 10 | } 11 | } 12 | 13 | .dropDown { 14 | line-height: @layout-header-height; 15 | vertical-align: top; 16 | cursor: pointer; 17 | > i { 18 | font-size: 16px !important; 19 | transform: none !important; 20 | svg { 21 | position: relative; 22 | top: -1px; 23 | } 24 | } 25 | } 26 | } 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/app/shared/layout/basic-layout/basic-layout.component.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Copyright {{footer.copyright}} 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/app/shared/layout/blank-layout/blank-layout.component.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/app/shared/layout/blank-layout/blank-layout.component.html -------------------------------------------------------------------------------- /src/app/shared/layout/blank-layout/blank-layout.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-blank-layout', 5 | templateUrl: 'blank-layout.component.html' 6 | }) 7 | export class BlankLayoutComponent implements OnInit { 8 | constructor() { 9 | } 10 | 11 | ngOnInit() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/shared/layout/index.ts: -------------------------------------------------------------------------------- 1 | import {BasicLayoutComponent} from "./basic-layout/basic-layout.component"; 2 | import {BlankLayoutComponent} from "./blank-layout/blank-layout.component"; 3 | import {UserLayoutComponent} from "./user-layout/user-layout.component"; 4 | 5 | export const LayoutComponents=[ 6 | BasicLayoutComponent, 7 | BlankLayoutComponent, 8 | UserLayoutComponent 9 | ]; 10 | -------------------------------------------------------------------------------- /src/app/shared/layout/user-layout/user-layout.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |
7 | 13 |
Ant Design 是西湖区最具影响力的 Web 设计规范
14 |
15 | 16 |
17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | Copyright {{footer.copyright}} 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/app/shared/layout/user-layout/user-layout.component.less: -------------------------------------------------------------------------------- 1 | @import '~ng-zorro-antd/style/themes/index.less'; 2 | 3 | .container { 4 | display: flex; 5 | flex-direction: column; 6 | height: 100vh; 7 | overflow: auto; 8 | background: @layout-body-background; 9 | } 10 | 11 | .lang { 12 | width: 100%; 13 | height: 40px; 14 | line-height: 44px; 15 | text-align: right; 16 | //:global(.ant-dropdown-trigger) { 17 | // margin-right: 24px; 18 | //} 19 | ::ng-deep .ant-dropdown-trigger{ 20 | margin-right: 24px; 21 | } 22 | } 23 | 24 | .content { 25 | flex: 1; 26 | padding: 32px 0; 27 | } 28 | 29 | @media (min-width: @screen-md-min) { 30 | .container { 31 | background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg'); 32 | background-repeat: no-repeat; 33 | background-position: center 110px; 34 | background-size: 100%; 35 | } 36 | 37 | .content { 38 | padding: 32px 0 24px; 39 | } 40 | } 41 | 42 | .top { 43 | text-align: center; 44 | } 45 | 46 | .header { 47 | height: 44px; 48 | line-height: 44px; 49 | a { 50 | text-decoration: none; 51 | } 52 | } 53 | 54 | .logo { 55 | height: 44px; 56 | margin-right: 16px; 57 | vertical-align: top; 58 | } 59 | 60 | .title { 61 | position: relative; 62 | top: 2px; 63 | color: @heading-color; 64 | font-weight: 600; 65 | font-size: 33px; 66 | font-family: Avenir, 'Helvetica Neue', Arial, Helvetica, sans-serif; 67 | } 68 | 69 | .desc { 70 | margin-top: 12px; 71 | margin-bottom: 40px; 72 | color: @text-color-secondary; 73 | font-size: @font-size-base; 74 | } 75 | -------------------------------------------------------------------------------- /src/app/shared/layout/user-layout/user-layout.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectionStrategy, Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-user-layout', 5 | templateUrl: 'user-layout.component.html', 6 | styleUrls: ['user-layout.component.less'], 7 | changeDetection: ChangeDetectionStrategy.OnPush, 8 | encapsulation: ViewEncapsulation.Emulated, 9 | exportAs: 'appUserLayout', 10 | preserveWhitespaces: false 11 | }) 12 | export class UserLayoutComponent implements OnInit { 13 | 14 | @ViewChild('linkIconTemplate', {static: true}) 15 | linkIconTemplate: TemplateRef; 16 | 17 | footer: any; 18 | 19 | constructor() { 20 | } 21 | 22 | ngOnInit() { 23 | this.footer = { 24 | links: [ 25 | { 26 | key: 'Ant Design Pro', 27 | title: 'Ant Design Pro', 28 | href: 'https://pro.ant.design', 29 | blankTarget: true, 30 | }, 31 | { 32 | key: 'github', 33 | title: this.linkIconTemplate, 34 | href: 'https://github.com/CK110/ant-design-pro-angular', 35 | blankTarget: true, 36 | }, 37 | { 38 | key: 'Ant Design', 39 | title: 'Ant Design', 40 | href: 'https://ng.ant.design', 41 | blankTarget: true, 42 | }, 43 | ], 44 | copyright: '2019 CK110出品' 45 | }; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/shared/models/user.ts: -------------------------------------------------------------------------------- 1 | export interface CurrentUser { 2 | avatar?: string; 3 | name?: string; 4 | title?: string; 5 | group?: string; 6 | signature?: string; 7 | geographic?: any; 8 | tags?: { 9 | key: string; 10 | label: string; 11 | }[]; 12 | unreadCount?: number; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {FormsModule, ReactiveFormsModule} from '@angular/forms'; 4 | import {RouterModule} from '@angular/router'; 5 | import {Components} from './components'; 6 | import {LayoutComponents} from "./layout"; 7 | import {DelonACLModule} from "@delon/acl"; 8 | import {TranslateModule} from "@ngx-translate/core"; 9 | import {SHARED_ZORRO_MODULES} from "@shared/shared-zorro.module"; 10 | 11 | const Modules = [ 12 | CommonModule, 13 | FormsModule, 14 | ReactiveFormsModule, 15 | RouterModule, 16 | 17 | ...SHARED_ZORRO_MODULES, 18 | DelonACLModule, 19 | TranslateModule 20 | ]; 21 | 22 | @NgModule({ 23 | imports: [ 24 | ...Modules, 25 | ], 26 | exports: [ 27 | ...Modules, 28 | ...Components, 29 | ...LayoutComponents 30 | ], 31 | declarations: [ 32 | ...Components, 33 | ...LayoutComponents 34 | ] 35 | }) 36 | export class SharedModule { 37 | } 38 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related fail stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an fail is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-fail'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CK110/ant-design-pro-angular/1c0a4745f85c440511c984b914021b8458a8a496/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ant Design Pro 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 30 |
31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 |
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/styles.less: -------------------------------------------------------------------------------- 1 | @import 'styles/theme'; 2 | @import 'styles/global'; 3 | -------------------------------------------------------------------------------- /src/styles/global.less: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | } 6 | 7 | .colorWeak { 8 | filter: invert(80%); 9 | } 10 | 11 | .ant-layout { 12 | min-height: 100vh; 13 | } 14 | 15 | canvas { 16 | display: block; 17 | } 18 | 19 | body { 20 | text-rendering: optimizeLegibility; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | ul, 26 | ol { 27 | list-style: none; 28 | } 29 | 30 | @media (max-width: @screen-xs) { 31 | .ant-table { 32 | width: 100%; 33 | overflow-x: auto; 34 | &-thead > tr, 35 | &-tbody > tr { 36 | > th, 37 | > td { 38 | white-space: pre; 39 | > span { 40 | display: block; 41 | } 42 | } 43 | } 44 | } 45 | } 46 | 47 | /* 滚动槽 */ 48 | ::-webkit-scrollbar { 49 | width: 2px; 50 | height: 2px; 51 | } 52 | ::-webkit-scrollbar-track { 53 | border-radius: 3px; 54 | background: rgba(0,0,0,0.06); 55 | -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.08); 56 | } 57 | /* 滚动条滑块 */ 58 | ::-webkit-scrollbar-thumb { 59 | border-radius: 3px; 60 | background: rgba(0,0,0,0.12); 61 | -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.2); 62 | } 63 | -------------------------------------------------------------------------------- /src/styles/theme.less: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/ng-zorro-antd/ng-zorro-antd"; 2 | @import "../../components/ng-zorro-pro"; 3 | 4 | @primary-color: red; 5 | -------------------------------------------------------------------------------- /src/styles/utils.less: -------------------------------------------------------------------------------- 1 | .textOverflow() { 2 | overflow: hidden; 3 | white-space: nowrap; 4 | text-overflow: ellipsis; 5 | word-break: break-all; 6 | } 7 | 8 | .textOverflowMulti(@line: 3, @bg: #fff) { 9 | position: relative; 10 | max-height: @line * 1.5em; 11 | margin-right: -1em; 12 | padding-right: 1em; 13 | overflow: hidden; 14 | line-height: 1.5em; 15 | text-align: justify; 16 | &::before { 17 | position: absolute; 18 | right: 14px; 19 | bottom: 0; 20 | padding: 0 1px; 21 | background: @bg; 22 | content: '...'; 23 | } 24 | &::after { 25 | position: absolute; 26 | right: 14px; 27 | width: 1em; 28 | height: 1em; 29 | margin-top: 0.2em; 30 | background: white; 31 | content: ''; 32 | } 33 | } 34 | 35 | // mixins for clearfix 36 | // ------------------------ 37 | .clearfix() { 38 | zoom: 1; 39 | &::before, 40 | &::after { 41 | display: table; 42 | content: ' '; 43 | } 44 | &::after { 45 | clear: both; 46 | height: 0; 47 | font-size: 0; 48 | visibility: hidden; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "downlevelIteration": true, 8 | "experimentalDecorators": true, 9 | "module": "es2020", 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "target": "es2015", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2018", 18 | "dom" 19 | ], 20 | "baseUrl": ".", 21 | "paths": { 22 | "pro-layout": ["components"], 23 | "pro-layout/*": ["components/*"], 24 | "@shared": [ "src/app/shared" ], 25 | "@shared/*": [ "src/app/shared/*" ], 26 | "@core": [ "src/app/core" ], 27 | "@core/*": [ "src/app/core/*" ], 28 | "@page": [ "src/app/page" ], 29 | "@page/*": [ "src/app/page/*" ], 30 | "@env/*": [ "src/environments/*" ] 31 | } 32 | }, 33 | "angularCompilerOptions": { 34 | "fullTemplateTypeCheck": true, 35 | "strictInjectionParameters": true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------