├── .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 | [](https://www.npmjs.com/package/pro-layout)
2 |
3 |
4 |
Ant Design Pro Angular
5 |
6 |
7 |
8 | 
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 |
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 |
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 |
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 |
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 |
22 |
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 |
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 |
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 |
26 |
27 |
28 |
29 |
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 |
18 |
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 |
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 |
3 |
7 |
8 | {{currentUser.name}}
9 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------