├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .storybook
├── block
│ ├── ImportInfo.tsx
│ └── docPage.tsx
├── main.js
├── manager.js
├── nzx-antd.theme.js
├── preview.js
├── tsconfig.json
└── typings.d.ts
├── .vscode
├── extensions.json
├── launch.json
└── tasks.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── angular.json
├── lib
├── README.md
├── base.less
├── between-datetime
│ ├── BetweenDatetime.stories.ts
│ ├── between-datetime.component.html
│ ├── between-datetime.component.ts
│ ├── between-datetime.module.ts
│ ├── datetime-utils.ts
│ ├── index.ts
│ ├── ng-package.json
│ └── public-api.ts
├── between-input
│ ├── BetweenInput.stories.ts
│ ├── between-input.component.html
│ ├── between-input.component.ts
│ ├── between-input.module.ts
│ ├── index.ts
│ ├── ng-package.json
│ └── public-api.ts
├── between-time
│ ├── BetweenTime.stories.ts
│ ├── between-time.component.html
│ ├── between-time.component.ts
│ ├── between-time.module.ts
│ ├── index.ts
│ ├── ng-package.json
│ └── public-api.ts
├── between
│ ├── Between.stories.ts
│ ├── between.component.html
│ ├── between.component.less
│ ├── between.component.ts
│ ├── between.module.ts
│ ├── index.ts
│ ├── ng-package.json
│ └── public-api.ts
├── button
│ ├── Button.stories.ts
│ ├── button.directive.ts
│ ├── button.less
│ ├── button.module.ts
│ ├── index.ts
│ ├── mixin.less
│ ├── ng-package.json
│ └── public-api.ts
├── checkbox
│ ├── Checkbox.stories.ts
│ ├── checkbox.component.html
│ ├── checkbox.component.ts
│ ├── checkbox.module.ts
│ ├── index.ts
│ ├── ng-package.json
│ └── public-api.ts
├── directive
│ ├── auth.directive.ts
│ ├── auth.not.directive.ts
│ ├── click-outside.directive.ts
│ ├── click.once.directive.ts
│ ├── directive.module.ts
│ ├── down-file.directive.ts
│ ├── fa-icon.directive.ts
│ ├── index.ts
│ ├── let.directive.ts
│ ├── named-template.ts
│ ├── ng-package.json
│ ├── ngx-for.directive.ts
│ └── public-api.ts
├── http-interceptor
│ ├── HttpInterceptor.stories.mdx
│ ├── http-custom-server-error.interceptor.ts
│ ├── http-default-encoder.ts
│ ├── http-error.interceptor.ts
│ ├── http-header.interceptor.ts
│ ├── http-interceptor.config.ts
│ ├── http-interceptor.module.ts
│ ├── http-loading.interceptor.ts
│ ├── http-loading.service.ts
│ ├── http-params.interceptor.ts
│ ├── http-response-parse.interceptor.ts
│ ├── http-url.interceptor.ts
│ ├── http.model.ts
│ ├── index.ts
│ ├── logout.service.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ └── xhr.ts
├── index.less
├── karma.conf.js
├── layout-page
│ ├── content.component.ts
│ ├── header.component.ts
│ ├── index.ts
│ ├── is-content-empty.ts
│ ├── layout-page.less
│ ├── layout-page.module.ts
│ ├── ng-package.json
│ ├── page.component.ts
│ └── public-api.ts
├── modal
│ ├── index.ts
│ ├── modal-drag.directive.ts
│ ├── modal-drag.service.ts
│ ├── modal.module.ts
│ ├── ng-package.json
│ ├── nzx-modal.service.ts
│ └── public-api.ts
├── ng-package.json
├── nzx-antd.less
├── nzx-antd.module.ts
├── nzx-antd.service.ts
├── package.json
├── pipe
│ ├── defaultify.pipe.ts
│ ├── dic.pipe.ts
│ ├── filter.pipe.ts
│ ├── index.ts
│ ├── math.pipe.ts
│ ├── ng-package.json
│ ├── path-value.pipe.ts
│ ├── pipe.module.ts
│ ├── public-api.ts
│ ├── time-unit.pipe.ts
│ ├── to-async.pipe.ts
│ └── trust-resource.pipe.ts
├── public-api.ts
├── repeat
│ ├── index.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── repeat.component.html
│ ├── repeat.component.less
│ ├── repeat.component.ts
│ └── repeat.module.ts
├── service
│ ├── auth-guard.service.ts
│ ├── dic.service.ts
│ ├── download.service.ts
│ ├── fetcher.service.ts
│ ├── index.ts
│ ├── loading.service.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── service.module.ts
│ └── storage.service.ts
├── switch
│ ├── index.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── switch.component.ts
│ └── switch.module.ts
├── table
│ ├── Table.stories.ts
│ ├── const.ts
│ ├── header
│ │ ├── column-setting
│ │ │ ├── column-setting.component.html
│ │ │ ├── column-setting.component.less
│ │ │ └── column-setting.component.ts
│ │ └── table-header
│ │ │ ├── table-header.component.html
│ │ │ └── table-header.component.ts
│ ├── index.less
│ ├── index.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── table-widget.directive.ts
│ ├── table-widget.service.ts
│ ├── table-widget
│ │ ├── table-button
│ │ │ └── table-button.component.ts
│ │ ├── table-input
│ │ │ └── table-input.component.ts
│ │ ├── table-link
│ │ │ └── table-link.component.ts
│ │ ├── table-tag
│ │ │ └── table-tag.component.ts
│ │ └── table-widget.module.ts
│ ├── table.component.html
│ ├── table.component.less
│ ├── table.component.ts
│ ├── table.module.ts
│ ├── table.type.ts
│ └── transform
│ │ ├── col-button-visible.pipe.ts
│ │ ├── col-buttons.pipe.ts
│ │ ├── col-format.pipe.ts
│ │ ├── col-span.pipe.ts
│ │ ├── has-auth.pipe.ts
│ │ └── link-href.pipe.ts
├── test.ts
├── tsconfig.lib.json
├── tsconfig.lib.prod.json
├── tsconfig.spec.json
├── upload
│ ├── index.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── upload.component.html
│ ├── upload.component.ts
│ └── upload.module.ts
└── util
│ ├── base-control.ts
│ ├── form-utils.ts
│ ├── index.ts
│ ├── ng-package.json
│ ├── public-api.ts
│ ├── utils-fn.ts
│ └── utils.ts
├── package-lock.json
├── package.json
├── stories
├── @types
│ └── index.ts
├── Introduction.stories.mdx
├── index.ts
└── styles.less
├── tsconfig.json
└── version.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": [
4 | "dist/**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "./lib/tsconfig.lib.json"
14 | ],
15 | "createDefaultProgram": true
16 | },
17 | "extends": [
18 | "plugin:@angular-eslint/recommended",
19 | "eslint:recommended",
20 | "plugin:@typescript-eslint/recommended",
21 | "plugin:@typescript-eslint/recommended-requiring-type-checking",
22 | "plugin:@angular-eslint/template/process-inline-templates"
23 | ],
24 | "rules": {
25 | "@typescript-eslint/no-empty-function": 0,
26 | "@typescript-eslint/no-explicit-any": 0,
27 | "@typescript-eslint/no-unsafe-assignment": 0,
28 | "@typescript-eslint/no-unsafe-call": 0,
29 | "@typescript-eslint/no-unsafe-member-access": 0,
30 | "prefer-arrow/prefer-arrow-functions": 0,
31 | "@angular-eslint/directive-selector": 0,
32 | "@angular-eslint/component-selector": [
33 | "error",
34 | {
35 | "type": "element",
36 | "prefix": "nzx,app",
37 | "style": "kebab-case"
38 | }
39 | ],
40 | "jsdoc/newline-after-description": 0
41 | }
42 | },
43 | {
44 | "files": [
45 | "*.html"
46 | ],
47 | "extends": [
48 | "plugin:@angular-eslint/template/recommended"
49 | ],
50 | "rules": {
51 | }
52 | }
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/.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 | /bazel-out
8 |
9 | # Node
10 | /node_modules
11 | npm-debug.log
12 | yarn-error.log
13 |
14 | # IDEs and editors
15 | .idea/
16 | .project
17 | .classpath
18 | .c9/
19 | *.launch
20 | .settings/
21 | *.sublime-workspace
22 |
23 | # Visual Studio Code
24 | .vscode/*
25 | !.vscode/settings.json
26 | !.vscode/tasks.json
27 | !.vscode/launch.json
28 | !.vscode/extensions.json
29 | .history/*
30 |
31 | # Miscellaneous
32 | /.angular/cache
33 | .sass-cache/
34 | /connect.lock
35 | /coverage
36 | /libpeerconnection.log
37 | testem.log
38 | /typings
39 |
40 | # System files
41 | .DS_Store
42 | Thumbs.db
43 |
44 | storybook-static
45 | documentation.json
46 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | **/*.md
2 | **/*.svg
3 | # **/*.html
4 | **/test.ts
5 | src/index.html
6 |
7 | .stylelintrc
8 | .prettierrc
9 |
10 | _nginx/
11 | _screenshot/
12 | node_modules/
13 | dist/
14 | package.json
15 | src/templates/
16 | assets/
17 | **/*.min.*
18 | package-lock.json
19 | documentation
20 | e2e
21 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "useTabs": false,
4 | "printWidth": 120,
5 | "tabWidth": 2,
6 | "semi": true,
7 | "htmlWhitespaceSensitivity": "ignore",
8 | "arrowParens": "avoid",
9 | "bracketSpacing": true,
10 | "proseWrap": "preserve",
11 | "trailingComma": "none",
12 | "endOfLine": "lf",
13 | "jsxBracketSameLine": true,
14 | "overrides": [
15 | {
16 | "files": ".prettierrc",
17 | "options": {
18 | "parser": "json"
19 | }
20 | },
21 | {
22 | "files": ["*.html"],
23 | "options": {
24 | "printWidth": 120,
25 | "htmlWhitespaceSensitivity": "ignore"
26 | }
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/.storybook/block/ImportInfo.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { DocsContext } from '@storybook/addon-docs';
3 | import { SyntaxHighlighter } from '@storybook/components';
4 |
5 | export const ImportInfo = () => {
6 | const context = useContext(DocsContext);
7 | console.log(context);
8 | // @ts-ignore
9 | const componentName = context.component?.name;
10 | if (!componentName) {
11 | return null;
12 | }
13 | const moduleName = componentName.replace(/(Component|Directive|Service|Pipe)$/, 'Module');
14 | const importName = componentName
15 | .replace(/(^Nzx)|((Component|Directive|Service|Pipe)$)/g, '')
16 | .replace(/\w([A-Z])/g, '-$1')
17 | .toLowerCase();
18 | const importStatement = `import { ${moduleName} } from '@xmagic/nzx-antd/${importName}';`;
19 | return (
20 |
21 | {importStatement}
22 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/.storybook/block/docPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { PRIMARY_STORY, ArgsTable, Title, Subtitle, Primary, Description, Stories } from '@storybook/addon-docs';
3 | import { H2 } from '@storybook/components';
4 | import { ImportInfo } from './ImportInfo';
5 |
6 | export const page = () => (
7 | <>
8 |
9 |
10 |
11 |
12 |
13 | 参数定义
14 |
15 |
16 | >
17 | );
18 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | stories: [
3 | '../stories/**/*.stories.mdx',
4 | '../stories/**/*.stories.@(js|jsx|ts|tsx)',
5 | '../lib/**/*.stories.mdx',
6 | '../lib/**/*.stories.@(js|jsx|ts|tsx)'
7 | ],
8 | addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
9 | framework: '@storybook/angular',
10 | core: {
11 | builder: '@storybook/builder-webpack5'
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/.storybook/manager.js:
--------------------------------------------------------------------------------
1 | import { addons } from '@storybook/addons';
2 | import { nzxAntdTheme } from './nzx-antd.theme';
3 |
4 | /**
5 | * 此文件为固定名称, 管理storybook配置
6 | */
7 | // 更多配置参考 https://storybook.js.org/docs/angular/configure/features-and-behavior
8 | addons.setConfig({
9 | theme: nzxAntdTheme
10 | });
11 |
--------------------------------------------------------------------------------
/.storybook/nzx-antd.theme.js:
--------------------------------------------------------------------------------
1 | import { create } from '@storybook/theming';
2 | // 定制主题参考 https://storybook.js.org/docs/react/configure/theming
3 | export const nzxAntdTheme = create({
4 | brandTitle: 'Nzx Antd',
5 | brandUrl: 'https://github.com/m310851010/nzx-antd',
6 | // brandImage: './static/media/stories/assets/colors.svg',
7 | brandTarget: '_blank'
8 | });
9 |
--------------------------------------------------------------------------------
/.storybook/preview.js:
--------------------------------------------------------------------------------
1 | import { setCompodocJson } from '@storybook/addon-docs/angular';
2 | import docJson from '../documentation.json';
3 | import { CommonModule, registerLocaleData } from '@angular/common';
4 | import zh from '@angular/common/locales/zh';
5 | import { moduleMetadata } from '@storybook/angular';
6 |
7 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
8 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
9 | import { NZ_I18N, zh_CN } from 'ng-zorro-antd/i18n';
10 | import { BrowserModule } from '@angular/platform-browser';
11 | import { EXCLUDE_PARAMS } from '@stories';
12 | import { page } from './block/docPage';
13 | setCompodocJson(docJson);
14 |
15 | registerLocaleData(zh);
16 |
17 | export const parameters = {
18 | actions: { argTypesRegex: '^on[A-Z].*' },
19 | controls: {
20 | matchers: {
21 | color: /(background|color)$/i,
22 | date: /(Date|Time)$/
23 | },
24 | exclude: EXCLUDE_PARAMS
25 | },
26 | docs: {
27 | inlineStories: true,
28 | source: {
29 | language: 'typescript',
30 | format: true
31 | },
32 | page
33 | },
34 | options: {
35 | storySort: {
36 | // order: ['介绍', '组件', '指令', '管道', '服务', '工具类']
37 | }
38 | }
39 | };
40 |
41 | // 全局模块配置
42 | export const decorators = [
43 | moduleMetadata({
44 | imports: [CommonModule, BrowserModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule],
45 | providers: [{ provide: NZ_I18N, useValue: zh_CN }]
46 | })
47 | // (Story, { id, kind, name, story, parameters, hooks, args, argTypes, globals, viewMode, loaded }) => {
48 | // console.log('==================');
49 | // }
50 | ];
51 |
--------------------------------------------------------------------------------
/.storybook/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig",
3 | "compilerOptions": {
4 | "types": [
5 | "node"
6 | ],
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "exclude": [
10 | "../lib/test.ts",
11 | "../lib/**/*.spec.ts",
12 | "../projects/**/*.spec.ts",
13 | ],
14 | "include": [
15 | "../lib/**/*",
16 | "../projects/**/*",
17 | "../stories/**/*",
18 | "./block/**/*"
19 | ],
20 | "files": [
21 | "./typings.d.ts"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/.storybook/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | const content: string;
3 | export default content;
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
3 | "recommendations": ["angular.ng-template"]
4 | }
5 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3 | "version": "0.2.0",
4 | "configurations": [
5 | {
6 | "name": "ng serve",
7 | "type": "pwa-chrome",
8 | "request": "launch",
9 | "preLaunchTask": "npm: start",
10 | "url": "http://localhost:4200/"
11 | },
12 | {
13 | "name": "ng test",
14 | "type": "chrome",
15 | "request": "launch",
16 | "preLaunchTask": "npm: test",
17 | "url": "http://localhost:9876/debug.html"
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
3 | "version": "2.0.0",
4 | "tasks": [
5 | {
6 | "type": "npm",
7 | "script": "start",
8 | "isBackground": true,
9 | "problemMatcher": {
10 | "owner": "typescript",
11 | "pattern": "$tsc",
12 | "background": {
13 | "activeOnStart": true,
14 | "beginsPattern": {
15 | "regexp": "(.*?)"
16 | },
17 | "endsPattern": {
18 | "regexp": "bundle generation complete"
19 | }
20 | }
21 | }
22 | },
23 | {
24 | "type": "npm",
25 | "script": "test",
26 | "isBackground": true,
27 | "problemMatcher": {
28 | "owner": "typescript",
29 | "pattern": "$tsc",
30 | "background": {
31 | "activeOnStart": true,
32 | "beginsPattern": {
33 | "regexp": "(.*?)"
34 | },
35 | "endsPattern": {
36 | "regexp": "bundle generation complete"
37 | }
38 | }
39 | }
40 | }
41 | ]
42 | }
43 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 2022/8/8
2 |
3 | 增加 storybook支持
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 m310851010
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 |
2 | # NzxAntd
3 |
4 | `NzxAntd`是一个`angular`组件库,基于`ng-zorro-antd`进行二次扩展,并加入开发常用功能。全部代码开源并遵循 `MIT` 协议,任何企业、组织及个人均可免费使用。
5 |
6 | [](https://npmjs.com/package/@xmagic/nzx-antd)
7 | 
8 | [](https://www.github.com/angular/angular)
9 | [](https://m310851010.github.io/nzx-antd)
10 |
11 | ## ✨特性
12 |
13 | - 扩展`HttpInterceptor`拦截器,简化通用业务处理
14 | - 封装常用组件 使之支持`FormControl`和`NgModal`
15 | - 封装表格组件, 简单易用, 功能强大
16 | - 常用工具类, 服务, 指令,管道
17 | - 集中化配置,统一配置入口
18 |
19 | ## 文档和示例
20 |
21 | 有关文档与示例,请访问 [https://m310851010.github.io/nzx-antd](https://m310851010.github.io/nzx-antd)
22 |
23 |
24 | ## 🖥使用环境
25 |
26 | - [Angular](https://angular.io) >= v16.0.0
27 | - [ng-zorro-antd](https://ng.ant.design) >= v16.0.0
28 |
29 | ## 📦安装
30 |
31 | ```shell
32 | npm i @xmagic/nzx-antd --save
33 | ```
34 |
35 | ## 🔨使用
36 |
37 |
38 | ## 🍏引入样式
39 |
40 | > 有两种方式引入样式, 在 `angular.json` 中 或者 `style.less`中, 任选其一
41 |
42 | - 在 `angular.json` 中引入
43 |
44 | ```json
45 | {
46 | "styles": [
47 | "node_modules/@xmagic/nzx-antd/nzx-antd.less"
48 | ]
49 | }
50 | ```
51 |
52 | - 在 `style.less` 中引入 `less` 样式文件
53 |
54 | ```css
55 | @import "node_modules/@xmagic/nzx-antd/nzx-antd.less";
56 | ```
57 |
58 | ## 🍎引入模块
59 |
60 | 1. 配置`NzxAntdService`
61 |
62 | ```ts
63 | // nzx-antd-config.service.ts
64 |
65 | import { Injectable } from '@angular/core';
66 | import { NzxAntdService } from '@xmagic/nzx-antd';
67 | import { environment } from '../environments/environment';
68 |
69 | @Injectable({
70 | providedIn: 'root'
71 | })
72 | export class NzxAntdConfigService extends NzxAntdService {
73 | override basePath = environment.basePath;
74 | override response = { data: 'data' };
75 | constructor() {
76 | super();
77 | }
78 | }
79 |
80 | ```
81 |
82 | 2. 修改`AppModule`
83 |
84 | ```diff
85 | // app.module.ts
86 |
87 | import { NgModule } from '@angular/core';
88 | import { AppComponent } from './app.component';
89 | import { NzxModalModule } from '@xmagic/nzx-antd/modal';
90 | import { NzxHttpInterceptorModule } from '@xmagic/nzx-antd/http-interceptor';
91 | +import { NzxAntdService } from '@xmagic/nzx-antd';
92 | +import { NzxAntdConfigService } from './nzx-antd-config.service';
93 |
94 | @NgModule({
95 | imports: [
96 | NzxModalModule,
97 | NzxHttpInterceptorModule
98 | ],
99 | providers: [
100 | + { provide: NzxAntdService, useExisting: NzxAntdConfigService }
101 | ],
102 | bootstrap: [AppComponent]
103 | })
104 | export class AppComponent {}
105 | ```
106 |
107 | 3. 修改`AppComponent`
108 |
109 | ```ts
110 | //app.component.ts
111 |
112 | import { Component, OnInit } from '@angular/core';
113 | import { HttpLoadingService, LogoutService } from '@xmagic/nzx-antd/http-interceptor';
114 | import { NzMessageService } from 'ng-zorro-antd/message';
115 | import { NzxModalWrapService } from '@xmagic/nzx-antd/modal';
116 | import { loadingService } from '@xmagic/nzx-antd/service';
117 |
118 | @Component({
119 | selector: 'app-root',
120 | template: '',
121 | })
122 | export class AppComponent implements OnInit {
123 | constructor(
124 | protected loading: HttpLoadingService,
125 | protected notifyService: LogoutService,
126 | protected modalService: NzxModalWrapService,
127 | protected message: NzMessageService,
128 | ) {}
129 |
130 | ngOnInit(): void {
131 | this.loading.subscribe(status => loadingService.loading(status));
132 |
133 | this.notifyService.onLogout(error => {
134 | this.modalService.closeAll();
135 | if (error.timeout) {
136 | this.message.info(error.message || '登录超时,请重新登录');
137 | }
138 | window.top!.location.href = error?.url || '#/login';
139 | });
140 | }
141 | }
142 | ```
143 |
144 | ## 🏴授权协议
145 |
146 | [MIT](https://raw.githubusercontent.com/m310851010/nzx-antd/main/LICENSE)
147 |
148 | ## 👍支持
149 |
150 | 为该项目点个免费的星⭐
151 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "nzx-antd": {
7 | "projectType": "library",
8 | "root": "lib",
9 | "sourceRoot": "lib",
10 | "prefix": "nzx",
11 | "architect": {
12 | "build": {
13 | "builder": "@angular-devkit/build-angular:ng-packagr",
14 | "options": {
15 | "project": "lib/ng-package.json"
16 | },
17 | "configurations": {
18 | "production": {
19 | "tsConfig": "lib/tsconfig.lib.prod.json"
20 | },
21 | "development": {
22 | "tsConfig": "lib/tsconfig.lib.json"
23 | }
24 | },
25 | "defaultConfiguration": "production"
26 | },
27 | "test": {
28 | "builder": "@angular-devkit/build-angular:karma",
29 | "options": {
30 | "main": "lib/test.ts",
31 | "tsConfig": "lib/tsconfig.spec.json",
32 | "karmaConfig": "lib/karma.conf.js"
33 | }
34 | }
35 | }
36 | },
37 | "storybook": {
38 | "projectType": "application",
39 | "root": "",
40 | "sourceRoot": "stories",
41 | "architect": {
42 | "build": {
43 | "builder": "@angular-devkit/build-angular:browser",
44 | "options": {
45 | "outputPath": "",
46 | "index": "",
47 | "main": "",
48 | "tsConfig": "tsconfig.json",
49 | "styles": ["stories/styles.less"],
50 | "scripts": [],
51 | "assets": [
52 | {
53 | "glob": "**/*",
54 | "ignore": ["fill/*", "twotone/*"],
55 | "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
56 | "output": "/assets/"
57 | }
58 | ],
59 | "stylePreprocessorOptions": {
60 | "includePaths": ["node_modules"]
61 | }
62 | }
63 | },
64 |
65 | "storybook": {
66 | "builder": "@storybook/angular:start-storybook",
67 | "options": {
68 | "configDir": ".storybook",
69 | "browserTarget": "storybook:build",
70 | "compodoc": true,
71 | "compodocArgs": ["-e", "json", "-d", "."],
72 | "port": 6006
73 | }
74 | },
75 | "build-storybook": {
76 | "builder": "@storybook/angular:build-storybook",
77 | "options": {
78 | "configDir": ".storybook",
79 | "browserTarget": "storybook:build",
80 | "compodoc": true,
81 | "compodocArgs": ["-e", "json", "-d", "."],
82 | "outputDir": "storybook-static"
83 | }
84 | }
85 |
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/lib/README.md:
--------------------------------------------------------------------------------
1 | # NzxAntd
2 |
3 | `NzxAntd`是一个`angular`组件库,基于`ng-zorro-antd`进行二次扩展,并加入开发常用功能。全部代码开源并遵循 `MIT` 协议,任何企业、组织及个人均可免费使用。
4 |
5 | [](https://npmjs.com/package/@xmagic/nzx-antd)
6 | 
7 | [](https://www.github.com/angular/angular)
8 | [](https://m310851010.github.io/nzx-antd)
9 |
10 | ## ✨ 特性
11 |
12 | - 扩展`HttpInterceptor`拦截器,简化通用业务处理
13 | - 封装常用组件 使之支持`FormControl`和`NgModal`
14 | - 封装表格组件, 简单易用, 功能强大
15 | - 常用工具类, 服务, 指令,管道
16 | - 集中化配置,统一配置入口
17 |
18 | ## 文档和示例
19 |
20 | 有关文档与示例,请访问 [https://m310851010.github.io/nzx-antd](https://m310851010.github.io/nzx-antd)
21 |
22 | ## 🖥 使用环境
23 |
24 | - [Angular](https://angular.io) >= v16.0.0
25 | - [ng-zorro-antd](https://ng.ant.design) >= v16.0.0
26 |
27 | ## 📦 安装
28 |
29 | ```shell
30 | npm i @xmagic/nzx-antd --save
31 | ```
32 |
33 | ## 🔨 使用
34 |
35 | ## 🍏 引入样式
36 |
37 | > 有两种方式引入样式, 在 `angular.json` 中 或者 `style.less`中, 任选其一
38 |
39 | - 在 `angular.json` 中引入
40 |
41 | ```json
42 | {
43 | "styles": ["node_modules/@xmagic/nzx-antd/nzx-antd.less"]
44 | }
45 | ```
46 |
47 | - 在 `style.less` 中引入 `less` 样式文件
48 |
49 | ```css
50 | @import 'node_modules/@xmagic/nzx-antd/nzx-antd.less';
51 | ```
52 |
53 | ## 🍎 引入模块
54 |
55 | 1. 配置`NzxAntdService`
56 |
57 | ```ts
58 | // nzx-antd-config.service.ts
59 |
60 | import { Injectable } from '@angular/core';
61 | import { NzxAntdService } from '@xmagic/nzx-antd';
62 | import { environment } from '../environments/environment';
63 |
64 | @Injectable({
65 | providedIn: 'root'
66 | })
67 | export class NzxAntdConfigService extends NzxAntdService {
68 | override basePath = environment.basePath;
69 | override response = { data: 'data' };
70 | constructor() {
71 | super();
72 | }
73 | }
74 | ```
75 |
76 | 2. 修改`AppModule`
77 |
78 | ```diff
79 | // app.module.ts
80 |
81 | import { NgModule } from '@angular/core';
82 | import { AppComponent } from './app.component';
83 | import { NzxModalModule } from '@xmagic/nzx-antd/modal';
84 | import { NzxHttpInterceptorModule } from '@xmagic/nzx-antd/http-interceptor';
85 | +import { NzxAntdService } from '@xmagic/nzx-antd';
86 | +import { NzxAntdConfigService } from './nzx-antd-config.service';
87 |
88 | @NgModule({
89 | imports: [
90 | NzxModalModule,
91 | NzxHttpInterceptorModule
92 | ],
93 | providers: [
94 | + { provide: NzxAntdService, useExisting: NzxAntdConfigService }
95 | ],
96 | bootstrap: [AppComponent]
97 | })
98 | export class AppComponent {}
99 | ```
100 |
101 | 3. 修改`AppComponent`
102 |
103 | ```ts
104 | //app.component.ts
105 |
106 | import { Component, OnInit } from '@angular/core';
107 | import { HttpLoadingService, LogoutService } from '@xmagic/nzx-antd/http-interceptor';
108 | import { NzMessageService } from 'ng-zorro-antd/message';
109 | import { NzxModalWrapService } from '@xmagic/nzx-antd/modal';
110 | import { loadingService } from '@xmagic/nzx-antd/service';
111 |
112 | @Component({
113 | selector: 'app-root',
114 | template: ''
115 | })
116 | export class AppComponent implements OnInit {
117 | constructor(
118 | protected loading: HttpLoadingService,
119 | protected notifyService: LogoutService,
120 | protected modalService: NzxModalWrapService,
121 | protected message: NzMessageService
122 | ) {}
123 |
124 | ngOnInit(): void {
125 | this.loading.subscribe(status => loadingService.loading(status));
126 |
127 | this.notifyService.onLogout(error => {
128 | this.modalService.closeAll();
129 | if (error.timeout) {
130 | this.message.info(error.message || '登录超时,请重新登录');
131 | }
132 | window.top!.location.href = error?.url || '#/login';
133 | });
134 | }
135 | }
136 | ```
137 |
138 | ## 🏴 授权协议
139 |
140 | [MIT](https://raw.githubusercontent.com/m310851010/nzx-antd/main/LICENSE)
141 |
142 | ## 👍 支持
143 |
144 | 为该项目点个免费的星 ⭐
145 |
--------------------------------------------------------------------------------
/lib/base.less:
--------------------------------------------------------------------------------
1 | // Config global less under antd
2 | @nzx-prefix: nzx;
3 |
4 | .nowrap {
5 | white-space: nowrap;
6 | }
7 |
--------------------------------------------------------------------------------
/lib/between-datetime/BetweenDatetime.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata, Story, Meta } from '@storybook/angular';
2 | import { NzxBetweenDatetimeComponent } from './between-datetime.component';
3 | import { NzFormModule } from 'ng-zorro-antd/form';
4 | import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
5 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
6 | import { EXCLUDE_PARAMS, hideControlArgType, SIZE_ARG_TYPE, storyFactory } from '@stories';
7 | import { action } from '@storybook/addon-actions';
8 |
9 | export default {
10 | title: '组件/BetweenDatetime 日期区间',
11 | component: NzxBetweenDatetimeComponent,
12 | decorators: [
13 | moduleMetadata({
14 | declarations: [NzxBetweenDatetimeComponent],
15 | imports: [NzFormModule, NzxBetweenModule, NzDatePickerModule]
16 | })
17 | ],
18 | argTypes: {
19 | nzxSize: SIZE_ARG_TYPE,
20 | nzMode: { control: 'select', options: ['date', 'week', 'month', 'year'] },
21 | defaultDisabledTime: { table: { disable: true } },
22 | nzShowTime: { control: { type: 'boolean' }, type: 'boolean' },
23 | nzxStartShowTime: { control: { type: 'boolean' }, type: 'boolean' },
24 | nzxEndShowTime: { control: { type: 'boolean' }, type: 'boolean' },
25 | nzLocale: { control: false },
26 | ...hideControlArgType(
27 | 'nzxStartOnOpenChange',
28 | 'nzxEndOnOpenChange',
29 | 'nzxStartOnOk',
30 | 'nzxEndOnOk',
31 | 'nzxStartOnCalendarChange',
32 | 'nzxEndOnCalendarChange',
33 | 'nzxStartOnPanelChange',
34 | 'nzxEndOnPanelChange'
35 | )
36 | },
37 | args: {
38 | nzxStartOnOpenChange: action('nzxStartOnOpenChange'),
39 | nzxEndOnOpenChange: action('nzxEndOnOpenChange'),
40 | nzxStartOnOk: action('nzxStartOnOk'),
41 | nzxEndOnOk: action('nzxEndOnOk'),
42 | nzxStartOnCalendarChange: action('nzxStartOnCalendarChange'),
43 | nzxEndOnCalendarChange: action('nzxEndOnCalendarChange'),
44 | nzxStartOnPanelChange: action('nzxStartOnPanelChange'),
45 | nzxEndOnPanelChange: action('nzxEndOnPanelChange')
46 | },
47 | parameters: {
48 | controls: {
49 | exclude: [
50 | 'nzxStartDisabledDate',
51 | 'nzxEndDisabledDate',
52 | 'nzxStartDisabledTime',
53 | 'nzxEndDisabledTime',
54 | 'getDisabledMaxDate',
55 | 'getDisabledMinDate',
56 | 'getDisabledTime',
57 | ...EXCLUDE_PARAMS
58 | ]
59 | }
60 | }
61 | } as Meta;
62 |
63 | const Template: (props?: Partial) => Story = storyFactory;
64 |
65 | export const Default = Template();
66 |
67 | export const NzxSize = Template({ nzxSize: 'large' });
68 |
69 | export const NzxDisabled = Template({ nzxDisabled: true });
70 |
71 | export const NzxStartDisabled = Template({ nzxStartDisabled: true });
72 |
73 | export const NzxEndDisabled = Template({ nzxEndDisabled: true });
74 |
75 | const start = new Date();
76 | start.setDate(start.getDate() - 2);
77 | export const StartMinDate = Template({ startMinDateTime: start });
78 |
79 | export const EndMaxDateTime = Template({ endMaxDateTime: new Date() });
80 |
81 | export const ShowTimeStart = Template({ nzxStartShowTime: true });
82 |
83 | export const ShowTimeEnd = Template({ nzxEndShowTime: true });
84 |
85 | export const ShowTime = Template({ nzShowTime: true });
86 |
87 | export const ShowToday = Template({ nzShowToday: true });
88 |
89 | export const ShowTodayStart = Template({ nzxStartShowToday: true });
90 |
91 | export const ShowTodayEnd = Template({ nzxEndShowToday: true });
92 |
93 | export const NzMode = Template({ nzMode: 'week' });
94 |
95 | export const NzAllowClear = Template({ nzAllowClear: true });
96 |
--------------------------------------------------------------------------------
/lib/between-datetime/between-datetime.component.html:
--------------------------------------------------------------------------------
1 |
7 |
41 |
75 |
76 |
77 |
78 |
108 |
109 |
--------------------------------------------------------------------------------
/lib/between-datetime/between-datetime.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxBetweenDatetimeComponent } from './between-datetime.component';
4 | import { FormsModule } from '@angular/forms';
5 | import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
6 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
7 |
8 | @NgModule({
9 | declarations: [NzxBetweenDatetimeComponent],
10 | imports: [CommonModule, FormsModule, NzxBetweenModule, NzDatePickerModule],
11 | exports: [NzxBetweenDatetimeComponent]
12 | })
13 | export class NzxBetweenDatetimeModule {}
14 |
--------------------------------------------------------------------------------
/lib/between-datetime/datetime-utils.ts:
--------------------------------------------------------------------------------
1 | import { NzxUtils } from '@xmagic/nzx-antd/util';
2 |
3 | export function getStartDate(date: Date) {
4 | const time = new Date(date.getTime());
5 | time.setHours(0, 0, 0, 0);
6 | return time.getTime();
7 | }
8 |
9 | export function getEndDate(date: Date) {
10 | const time = new Date(date.getTime());
11 | time.setHours(23, 59, 59, 999);
12 | return time.getTime();
13 | }
14 |
15 | export function getStartWeekDate(date: Date) {
16 | const time = new Date(date.getTime());
17 | const day = time.getDay();
18 | time.setDate(time.getDate() - (day === 0 ? 7 : day));
19 | time.setHours(0, 0, 0, 0);
20 | return time.getTime();
21 | }
22 |
23 | export function getEndWeekDate(date: Date) {
24 | const time = new Date(date.getTime());
25 | const day = time.getDay();
26 | time.setDate(time.getDate() + 7 - (day === 0 ? 7 : day));
27 | time.setHours(23, 59, 59, 999);
28 | return time.getTime();
29 | }
30 |
31 | export function getStartMonthDate(date: Date) {
32 | const time = new Date(date.getTime());
33 | time.setDate(1);
34 | time.setHours(0, 0, 0, 0);
35 | return time.getTime();
36 | }
37 |
38 | export function getEndMonthDate(date: Date) {
39 | const time = new Date(date.getTime());
40 | time.setDate(0);
41 | time.setHours(23, 59, 59, 999);
42 | return time.getTime();
43 | }
44 |
45 | export function getStartYearDate(date: Date) {
46 | const time = new Date(date.getTime());
47 | time.setMonth(1, 1);
48 | time.setHours(0, 0, 0, 0);
49 | return time.getTime();
50 | }
51 |
52 | export function getEndYearDate(date: Date) {
53 | const time = new Date(date.getTime());
54 | time.setMonth(12, 0);
55 | time.setHours(23, 59, 59, 999);
56 | return time.getTime();
57 | }
58 |
59 | export function getTimeValue(date: Date, value?: Date | null): { hour: number; minute: number; second: number } | null {
60 | // 检查是否在同一天, 不在同一天不禁用时间
61 | if (!value || getStartDate(value) !== getStartDate(date)) {
62 | return null;
63 | }
64 | return { hour: value.getHours(), minute: value.getMinutes(), second: value.getSeconds() };
65 | }
66 |
67 | /**
68 | * 获取Datetime 真实值
69 | * @param date,
70 | * @param disabledDateType
71 | */
72 | export function getRealDateTime(date: Date, disabledDateType?: DisabledDateType): Date | null | undefined {
73 | if (!disabledDateType) {
74 | return null;
75 | }
76 | if (NzxUtils.isFunction(disabledDateType)) {
77 | return disabledDateType(date);
78 | }
79 | if (NzxUtils.isDate(disabledDateType)) {
80 | return disabledDateType;
81 | }
82 | return new Date(disabledDateType);
83 | }
84 |
85 | export type DisabledDateType = Date | null | ((current: Date) => Date | null);
86 | export type DatetimeValueType = Record;
87 |
--------------------------------------------------------------------------------
/lib/between-datetime/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/between-datetime/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/between-datetime/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './between-datetime.component';
2 | export * from './datetime-utils';
3 | export * from './between-datetime.module';
4 |
--------------------------------------------------------------------------------
/lib/between-input/BetweenInput.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata, Story, Meta } from '@storybook/angular';
2 | import { NzxBetweenInputComponent } from './between-input.component';
3 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
4 | import { EXCLUDE_PARAMS, SIZE_ARG_TYPE, storyFactory } from '@stories';
5 | import { NzInputModule } from 'ng-zorro-antd/input';
6 | import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
7 |
8 | export default {
9 | title: '组件/BetweenInput 输入框区间',
10 | component: NzxBetweenInputComponent,
11 | decorators: [
12 | moduleMetadata({
13 | declarations: [NzxBetweenInputComponent],
14 | imports: [NzxBetweenModule, NzInputModule, NzInputNumberModule]
15 | })
16 | ],
17 | args: {
18 | nzxStartFormatter: (v: number | string) => v,
19 | nzxEndFormatter: (v: number | string) => v,
20 | nzxStartMax: Infinity,
21 | nzxEndMax: Infinity,
22 | nzxStartMin: -Infinity,
23 | nzxEndMin: -Infinity
24 | },
25 | argTypes: {
26 | nzxSize: SIZE_ARG_TYPE,
27 | nzxType: { control: 'inline-radio' },
28 | nzxStartMax: { control: 'number' },
29 | nzxEndMax: { control: 'number' },
30 | nzxStartMin: { control: 'number' },
31 | nzxEndMin: { control: 'number' }
32 | },
33 | parameters: {
34 | controls: {
35 | exclude: EXCLUDE_PARAMS
36 | }
37 | }
38 | } as Meta;
39 |
40 | const Template: (props?: Partial) => Story = storyFactory;
41 |
42 | export const Default = Template();
43 |
44 | export const NzxSize = Template({ nzxSize: 'large' });
45 |
46 | export const NzxDisabled = Template({ nzxDisabled: true });
47 |
48 | export const NzxStartDisabled = Template({ nzxStartDisabled: true });
49 |
50 | export const NzxEndDisabled = Template({ nzxEndDisabled: true });
51 |
52 | export const NzxType = Template({ nzxType: 'number' });
53 |
--------------------------------------------------------------------------------
/lib/between-input/between-input.component.html:
--------------------------------------------------------------------------------
1 |
7 |
25 |
43 |
44 |
45 |
46 |
47 |
56 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/lib/between-input/between-input.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeDetectionStrategy,
3 | ChangeDetectorRef,
4 | Component,
5 | forwardRef,
6 | Input,
7 | ViewEncapsulation
8 | } from '@angular/core';
9 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
10 | import { NzxBetweenComponent } from '@xmagic/nzx-antd/between';
11 | import { NzInputNumberComponent } from 'ng-zorro-antd/input-number';
12 |
13 | @Component({
14 | selector: 'nzx-between-input',
15 | templateUrl: './between-input.component.html',
16 | preserveWhitespaces: false,
17 | encapsulation: ViewEncapsulation.None,
18 | changeDetection: ChangeDetectionStrategy.OnPush,
19 | providers: [
20 | {
21 | provide: NG_VALUE_ACCESSOR,
22 | useExisting: forwardRef(() => NzxBetweenInputComponent),
23 | multi: true
24 | }
25 | ]
26 | })
27 | export class NzxBetweenInputComponent extends NzxBetweenComponent implements ControlValueAccessor {
28 | nzxValue: InputValueType = {};
29 |
30 | /**
31 | * 控件类型, 输入框 或 数字框
32 | */
33 | @Input() nzxType: 'input' | 'number' = 'input';
34 | /**
35 | * 开始字段Placeholder
36 | */
37 | @Input() nzxStartPlaceholder = '起始值';
38 | /**
39 | * 结束字段Placeholder
40 | */
41 | @Input() nzxEndPlaceholder = '结束值';
42 |
43 | /**
44 | * 最大值-开始
45 | */
46 | @Input() nzxStartMax = Infinity;
47 | /**
48 | * 最大值-结束
49 | */
50 | @Input() nzxEndMax = Infinity;
51 | /**
52 | * 最小值-开始
53 | */
54 | @Input() nzxStartMin = -Infinity;
55 | /**
56 | * 最小值-结束
57 | */
58 | @Input() nzxEndMin = -Infinity;
59 | /**
60 | * 数值精度-开始
61 | */
62 | @Input() nzxStarPrecision?: number;
63 | /**
64 | * 数值精度-结束
65 | */
66 | @Input() nzxEndPrecision?: number;
67 | /**
68 | * 每次改变步数,可以为小数-开始
69 | */
70 | @Input() nzxStarStep = 1;
71 | /**
72 | * 每次改变步数,可以为小数-结束
73 | */
74 | @Input() nzxEndStep = 1;
75 |
76 | /**
77 | * 组件内部 input 的 id 值-开始
78 | */
79 | @Input() nzxStarId?: string;
80 | /**
81 | * 组件内部 input 的 id 值-结束
82 | */
83 | @Input() nzxEndId?: string;
84 | /**
85 | * 开始字段重命名
86 | */
87 | @Input() nzxStartReName?: string;
88 | /**
89 | * 结束字段重命名
90 | */
91 | @Input() nzxEndReName?: string;
92 |
93 | /**
94 | * 指定输入框展示值的格式-开始
95 | */
96 | @Input() nzxStartFormatter?: NzInputNumberComponent['nzFormatter'];
97 | /**
98 | * 指定输入框展示值的格式-结束
99 | */
100 | @Input() nzxEndFormatter?: NzInputNumberComponent['nzFormatter'];
101 |
102 | defaultFormat = (v: number) => v;
103 | constructor(protected cdr: ChangeDetectorRef) {
104 | super();
105 | }
106 |
107 | ngModelChange() {
108 | this.onChange(this.nzxValue);
109 | }
110 |
111 | writeValue(value: InputValueType): void {
112 | this.nzxValue = value || {};
113 | this.cdr.markForCheck();
114 | }
115 |
116 | setDisabledState(isDisabled: boolean): void {
117 | this.nzxDisabled = isDisabled;
118 | }
119 |
120 | registerOnChange(fn: (_: InputValueType) => void): void {
121 | this.onChange = fn;
122 | }
123 |
124 | registerOnTouched(fn: () => void): void {
125 | this.onTouched = fn;
126 | }
127 |
128 | onChange: (value: InputValueType) => void = () => null;
129 | onTouched: () => void = () => null;
130 | }
131 |
132 | export type InputValueType = Record | null;
133 |
--------------------------------------------------------------------------------
/lib/between-input/between-input.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxBetweenInputComponent } from './between-input.component';
4 | import { NzInputModule } from 'ng-zorro-antd/input';
5 | import { FormsModule } from '@angular/forms';
6 | import { NzInputNumberModule } from 'ng-zorro-antd/input-number';
7 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
8 |
9 | @NgModule({
10 | declarations: [NzxBetweenInputComponent],
11 | imports: [CommonModule, FormsModule, NzxBetweenModule, NzInputModule, NzInputNumberModule],
12 | exports: [NzxBetweenInputComponent]
13 | })
14 | export class NzxBetweenInputModule {}
15 |
--------------------------------------------------------------------------------
/lib/between-input/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/between-input/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/between-input/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './between-input.component';
2 | export * from './between-input.module';
3 |
--------------------------------------------------------------------------------
/lib/between-time/BetweenTime.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata, Story, Meta } from '@storybook/angular';
2 | import { NzxBetweenTimeComponent } from './between-time.component';
3 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
4 | import { EXCLUDE_PARAMS, hideControlArgType, SIZE_ARG_TYPE, storyFactory } from '@stories';
5 | import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
6 |
7 | export default {
8 | title: '组件/BetweenDatetime 时间区间',
9 | component: NzxBetweenTimeComponent,
10 | decorators: [
11 | moduleMetadata({
12 | declarations: [NzxBetweenTimeComponent],
13 | imports: [NzTimePickerModule, NzxBetweenModule]
14 | })
15 | ],
16 | argTypes: {
17 | nzxSize: SIZE_ARG_TYPE,
18 | nzxStartStatus: { control: 'inline-radio', options: ['', 'error', 'warning'], defaultValue: '' },
19 | nzxEndStatus: { control: 'inline-radio', options: ['', 'error', 'warning'], defaultValue: '' },
20 | ...hideControlArgType('nzxEndOpenChange', 'nzxStartOpenChange')
21 | },
22 | parameters: {
23 | controls: {
24 | exclude: [
25 | ...EXCLUDE_PARAMS,
26 | 'nzxStartDisabledHours',
27 | 'nzxStartDisabledMinutes',
28 | 'nzxStartDisabledSeconds',
29 | 'nzxEndDisabledHours',
30 | 'nzxEndDisabledMinutes',
31 | 'nzxEndDisabledSeconds',
32 | 'getDefaultMinValue',
33 | 'getDefaultMaxValue',
34 | 'getDisabledHour',
35 | 'getDisabledMinutes',
36 | 'getDisabledSeconds',
37 | 'nzDefaultOpenValue'
38 | ]
39 | }
40 | }
41 | } as Meta;
42 |
43 | const Template: (props?: Partial) => Story = storyFactory;
44 |
45 | export const Default = Template();
46 |
47 | export const NzxSize = Template({ nzxSize: 'large' });
48 |
49 | export const NzxDisabled = Template({ nzxDisabled: true });
50 |
51 | export const NzxStartDisabled = Template({ nzxStartDisabled: true });
52 |
53 | export const NzxEndDisabled = Template({ nzxEndDisabled: true });
54 |
--------------------------------------------------------------------------------
/lib/between-time/between-time.component.html:
--------------------------------------------------------------------------------
1 |
7 |
41 |
75 |
76 |
77 |
78 |
107 |
108 |
--------------------------------------------------------------------------------
/lib/between-time/between-time.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxBetweenTimeComponent } from './between-time.component';
4 | import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
5 | import { FormsModule } from '@angular/forms';
6 | import { NzxBetweenModule } from '@xmagic/nzx-antd/between'
7 |
8 | @NgModule({
9 | declarations: [NzxBetweenTimeComponent],
10 | imports: [CommonModule, NzTimePickerModule, FormsModule, NzxBetweenModule],
11 | exports: [NzxBetweenTimeComponent]
12 | })
13 | export class NzxBetweenTimeModule {}
14 |
--------------------------------------------------------------------------------
/lib/between-time/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/between-time/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/between-time/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './between-time.component';
2 | export * from './between-time.module';
3 |
--------------------------------------------------------------------------------
/lib/between/Between.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata, Story, Meta } from '@storybook/angular';
2 | import { NzxBetweenComponent } from './between.component';
3 | import { NzInputModule } from 'ng-zorro-antd/input';
4 | import { NzSelectModule } from 'ng-zorro-antd/select';
5 | import { NzDatePickerModule } from 'ng-zorro-antd/date-picker';
6 | import { NzFormModule } from 'ng-zorro-antd/form';
7 | import { SIZE_ARG_TYPE } from '@stories';
8 |
9 | export default {
10 | title: '组件/Between 区间',
11 | component: NzxBetweenComponent,
12 | decorators: [
13 | moduleMetadata({
14 | declarations: [NzxBetweenComponent],
15 | imports: [NzInputModule, NzSelectModule, NzDatePickerModule, NzFormModule]
16 | })
17 | ],
18 | argTypes: {
19 | nzxSize: SIZE_ARG_TYPE,
20 | },
21 | parameters: {
22 | docs: {
23 | // 传给
24 | moduleName: '',
25 | importName: ''
26 | }
27 | }
28 | } as Meta;
29 |
30 | const Template: Story = args => {
31 | return {
32 | props: args,
33 | template: `
34 |
39 |
40 |
41 |
42 | `
43 | };
44 | };
45 |
46 | export const NzxSize = Template.bind({});
47 | NzxSize.storyName = 'Nzx Size';
48 | NzxSize.args = {
49 | nzxSize: 'small'
50 | };
51 |
52 | export const NzxDisabled = Template.bind({});
53 | NzxDisabled.args = {
54 | nzxDisabled: true
55 | };
56 |
57 | export const NzxStartDisabled = Template.bind({});
58 | NzxStartDisabled.args = {
59 | nzxStartDisabled: true
60 | };
61 |
62 | export const NzxEndDisabled = Template.bind({});
63 | NzxEndDisabled.args = {
64 | nzxEndDisabled: true
65 | };
66 |
67 | // select控件
68 | export const SelectControl: Story = args => {
69 | return {
70 | props: args,
71 | template: `
72 |
76 |
77 |
78 |
79 | `
80 | };
81 | };
82 | SelectControl.args = {
83 | nzOptions: Array.from({ length: 10 }).map((it, i) => ({ label: `选项-${i + 1}`, value: i }))
84 | };
85 |
86 | // DatePicker控件
87 | export const DatePickerControl: Story = args => {
88 | return {
89 | props: args,
90 | template: `
91 |
95 |
96 |
97 |
98 | `
99 | };
100 | };
101 |
102 | // WidthFormItem
103 | export const WidthFormItem: Story = args => {
104 | return {
105 | props: args,
106 | template: `
107 |
108 | label1
109 |
110 |
114 |
115 |
116 |
117 |
118 |
119 | `
120 | };
121 | };
122 |
--------------------------------------------------------------------------------
/lib/between/between.component.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/lib/between/between.component.less:
--------------------------------------------------------------------------------
1 | @import '../base.less';
2 | @nzx-between-prefix: ~'@{nzx-prefix}-between';
3 |
4 | .@{nzx-between-prefix}{
5 | display: flex !important;
6 |
7 | > :first-child, .between-start {
8 | border-right-color: transparent;
9 | flex: 1;
10 | .ant-select-selector{
11 | border-right-color: transparent;
12 | }
13 | }
14 |
15 | > :last-child, .between-end {
16 | border-left-color: transparent;
17 | flex: 1;
18 | .ant-select-selector{
19 | border-left-color: transparent;
20 | }
21 | }
22 |
23 | &:not(.@{nzx-between-prefix}-disabled) {
24 | .@{nzx-between-prefix}-placeholder{
25 | background-color: #fff !important;
26 | }
27 | }
28 | &-placeholder {
29 | width: 20px !important;
30 | border-left: none;
31 | border-right: none;
32 | pointer-events: none;
33 | padding-left: 0 !important;
34 | padding-right: 0 !important;
35 | text-align: center;
36 | }
37 | }
38 |
39 | .ant-form-item-has-error .@{nzx-between-prefix}-placeholder{
40 | border-top-color: @error-color;
41 | border-bottom-color: @error-color;
42 | }
43 |
--------------------------------------------------------------------------------
/lib/between/between.component.ts:
--------------------------------------------------------------------------------
1 | import { ChangeDetectionStrategy, Component, Input, ViewEncapsulation } from '@angular/core';
2 | import { NzSizeLDSType } from 'ng-zorro-antd/core/types';
3 |
4 | /**
5 | * 包含开始和结束两个控件,子组件使用`start`和`end`属性来插入到对应的容易内。
6 | */
7 | @Component({
8 | selector: 'nzx-between',
9 | exportAs: 'nzxBetween',
10 | templateUrl: './between.component.html',
11 | preserveWhitespaces: false,
12 | encapsulation: ViewEncapsulation.None,
13 | changeDetection: ChangeDetectionStrategy.OnPush
14 | })
15 | export class NzxBetweenComponent {
16 | /**
17 | * 是否禁用
18 | */
19 | @Input() nzxDisabled = false;
20 | /**
21 | * 控件大小
22 | */
23 | @Input() nzxSize: NzSizeLDSType = 'default';
24 | /**
25 | * 开始字段禁用
26 | */
27 | @Input() nzxStartDisabled?: boolean;
28 | /**
29 | * 结束字段禁用
30 | */
31 | @Input() nzxEndDisabled?: boolean;
32 | constructor() {}
33 | }
34 |
--------------------------------------------------------------------------------
/lib/between/between.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxBetweenComponent } from './between.component';
4 | import { NzInputModule } from 'ng-zorro-antd/input';
5 |
6 | @NgModule({
7 | declarations: [NzxBetweenComponent],
8 | imports: [CommonModule, NzInputModule],
9 | exports: [NzxBetweenComponent]
10 | })
11 | export class NzxBetweenModule {}
12 |
--------------------------------------------------------------------------------
/lib/between/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/between/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/between/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './between.component';
2 | export * from './between.module';
3 |
--------------------------------------------------------------------------------
/lib/button/button.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChange, SimpleChanges } from '@angular/core';
2 |
3 | /**
4 | * 按钮指令,增强ng-zorro-antd按钮颜色, 和nz-button组件配合使用, 只增加`nzxColor`属性
5 | *
6 | * 颜色值取自 https://ant.design/docs/spec/colors-cn
7 | */
8 | @Directive({
9 | selector: '[nz-button]',
10 | exportAs: 'nzxButton'
11 | })
12 | export class NzxButtonDirective implements OnInit, OnChanges {
13 | /**
14 | * 按钮颜色名称
15 | */
16 | @Input() nzxColor?: NzxColorType;
17 | constructor(protected renderer: Renderer2, protected elementRef: ElementRef) {}
18 |
19 | ngOnInit(): void {
20 | this.addButtonClass(this.nzxColor);
21 | }
22 |
23 | /**
24 | * 添加按钮class 名称
25 | * @param className class 名称
26 | * @protected
27 | */
28 | protected addButtonClass(className?: NzxColorType): void {
29 | const element = this.elementRef.nativeElement;
30 | const classList = element.classList;
31 | classList.forEach(cls => {
32 | if (cls.indexOf('nzx-button') === 0) {
33 | classList.remove(cls);
34 | }
35 | });
36 |
37 | if (className) {
38 | this.renderer.addClass(element, `nzx-button-${className}`);
39 | }
40 | }
41 |
42 | ngOnChanges(changes: { [K in keyof this]?: SimpleChange } & SimpleChanges): void {
43 | if (changes.nzxColor && !changes.nzxColor.isFirstChange()) {
44 | this.addButtonClass(this.nzxColor);
45 | }
46 | }
47 | }
48 |
49 | export type NzxColorType = 'success' | 'warning' | 'info' | 'error' | 'gray' | 'teal' | 'cyan' | string;
50 |
--------------------------------------------------------------------------------
/lib/button/button.less:
--------------------------------------------------------------------------------
1 | @import 'ng-zorro-antd/style/themes/index.less';
2 | @import 'ng-zorro-antd/button/style/mixin.less';
3 | @import '../base.less';
4 | @import './mixin.less';
5 |
6 | // 颜色值取自 https://ant.design/docs/spec/colors-cn
7 |
8 | @nzx-button-prefix-cls: ~'@{nzx-prefix}-button';
9 | @btn-prefix-cls: ~'@{ant-prefix}-btn';
10 | @btn-ghost-prefix-cls: ~'@{btn-prefix-cls}-background-ghost';
11 |
12 | @info-color: #0dcaf0;
13 | @info-color-hover: color(~`colorPalette('@{info-color}', 5) `);
14 | @info-color-active: color(~`colorPalette('@{info-color}', 7) `);
15 |
16 | @gray-color: #bfbfbf;
17 | @gray-color-hover: color(~`colorPalette('@{gray-color}', 5) `);
18 | @gray-color-active: color(~`colorPalette('@{gray-color}', 7) `);
19 |
20 | @teal-color: #20c997;
21 | @teal-color-hover: color(~`colorPalette('@{teal-color}', 5) `);
22 | @teal-color-active: color(~`colorPalette('@{teal-color}', 7) `);
23 |
24 | @cyan-color: #13c2c2;
25 | @cyan-color-hover: color(~`colorPalette('@{cyan-color}', 5) `);
26 | @cyan-color-active: color(~`colorPalette('@{cyan-color}', 7) `);
27 |
28 | .@{nzx-button-prefix-cls} {
29 | &-success {
30 | .btn-color(@success-color);
31 | }
32 | &-success.@{btn-prefix-cls}-text {
33 | .button-variant-text(@success-color);
34 | }
35 | &-success.@{btn-prefix-cls}-link {
36 | .button-variant-link(@success-color);
37 | }
38 | .@{btn-ghost-prefix-cls}&-success {
39 | .button-variant-ghost(@success-color; @success-color; @success-color-hover; @success-color-active);
40 | }
41 |
42 | &-warning {
43 | .btn-color(@warning-color);
44 | }
45 | &-warning.@{btn-prefix-cls}-text {
46 | .button-variant-text(@warning-color);
47 | }
48 | &-warning.@{btn-prefix-cls}-link {
49 | .button-variant-link(@warning-color);
50 | }
51 | .@{btn-ghost-prefix-cls}&-warning {
52 | .button-variant-ghost(@warning-color; @warning-color; @warning-color-hover; @warning-color-active);
53 | }
54 |
55 | &-error {
56 | .btn-color(@error-color);
57 | }
58 | &-error.@{btn-prefix-cls}-text {
59 | .button-variant-text(@error-color);
60 | }
61 | &-error.@{btn-prefix-cls}-link {
62 | .button-variant-link(@error-color);
63 | }
64 | .@{btn-ghost-prefix-cls}&-error {
65 | .button-variant-ghost(@error-color; @error-color; @error-color-hover; @error-color-active);
66 | }
67 |
68 | &-info {
69 | .btn-color(@info-color);
70 | }
71 | &-info.@{btn-prefix-cls}-text {
72 | .button-variant-text(@info-color);
73 | }
74 | &-info.@{btn-prefix-cls}-link {
75 | .button-variant-link(@info-color);
76 | }
77 | .@{btn-ghost-prefix-cls}&-info {
78 | .button-variant-ghost(@info-color; @info-color; @info-color-hover; @info-color-active);
79 | }
80 |
81 | &-gray {
82 | .btn-color(@gray-color);
83 | }
84 | &-gray.@{btn-prefix-cls}-text {
85 | .button-variant-text(@gray-color);
86 | }
87 | &-gray.@{btn-prefix-cls}-link {
88 | .button-variant-link(@gray-color);
89 | }
90 | .@{btn-ghost-prefix-cls}&-gray {
91 | .button-variant-ghost(@gray-color; @gray-color; @gray-color-hover; @gray-color-active);
92 | }
93 |
94 | &-teal {
95 | .btn-color(@teal-color);
96 | }
97 | &-teal.@{btn-prefix-cls}-text {
98 | .button-variant-text(@teal-color);
99 | }
100 | &-teal.@{btn-prefix-cls}-link {
101 | .button-variant-link(@teal-color);
102 | }
103 | .@{btn-ghost-prefix-cls}&-teal {
104 | .button-variant-ghost(@teal-color; @teal-color; @teal-color-hover; @teal-color-active);
105 | }
106 |
107 | &-cyan {
108 | .btn-color(@cyan-color);
109 | }
110 | &-cyan.@{btn-prefix-cls}-text {
111 | .button-variant-text(@cyan-color);
112 | }
113 | &-cyan.@{btn-prefix-cls}-link {
114 | .button-variant-link(@cyan-color);
115 | }
116 | .@{btn-ghost-prefix-cls}&-cyan {
117 | .button-variant-ghost(@cyan-color; @cyan-color; @cyan-color-hover; @cyan-color-active);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/lib/button/button.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxButtonDirective } from './button.directive';
4 | import { NzButtonModule } from 'ng-zorro-antd/button';
5 |
6 | @NgModule({
7 | declarations: [NzxButtonDirective],
8 | imports: [CommonModule, NzButtonModule],
9 | exports: [NzxButtonDirective, NzButtonModule]
10 | })
11 | export class NzxButtonModule {}
12 |
--------------------------------------------------------------------------------
/lib/button/index.ts:
--------------------------------------------------------------------------------
1 | export * from './public-api';
2 |
--------------------------------------------------------------------------------
/lib/button/mixin.less:
--------------------------------------------------------------------------------
1 |
2 | .active-btn-color(@color) {
3 | &:focus,
4 | &.focus {
5 | box-shadow: 0 0 0 2px fade(@color, 20%);
6 | }
7 | }
8 |
9 | .btn-color(@color) {
10 | .button-variant(@btn-primary-color; @color; @color);
11 |
12 | &:hover,
13 | &:active,
14 | &.active,
15 | &:focus,
16 | &.focus {
17 | color: @btn-primary-color;
18 | }
19 |
20 | .active-btn-color(@color);
21 | }
22 |
23 | .button-variant(@color; @background; @border) {
24 | .button-color(@color; @background; @border);
25 |
26 | &:hover
27 | {
28 | .button-color(tint(@color, 20%); tint(@background, 20%); tint(@border, 20%));
29 | }
30 | &:active,
31 | &.active ,
32 | &:focus,
33 | &.focus{
34 | .button-color(shade(@color, 5%); shade(@background, 5%); shade(@background, 5%));
35 | }
36 |
37 | .button-disabled();
38 | }
39 |
40 |
41 | .button-variant-text(@color;) {
42 | .button-variant-other(@color, transparent, transparent);
43 | box-shadow: none;
44 |
45 | &:hover,
46 | &:focus {
47 | .button-color(~`colorPalette('@{color}', 5) `; @btn-text-hover-bg; transparent);
48 | }
49 |
50 | &:active {
51 | .button-color(~`colorPalette('@{color}', 7) `; fadein(@btn-text-hover-bg, 1%); transparent);
52 | }
53 | .button-disabled(@disabled-color; transparent; transparent);
54 | }
55 |
56 |
57 | .button-variant-link(@color) {
58 | .button-variant-other(@color, transparent, transparent);
59 | box-shadow: none;
60 |
61 | &:hover,
62 | &:focus {
63 | .button-color(~`colorPalette('@{color}', 5) `; transparent; transparent);
64 | }
65 |
66 | &:active {
67 | .button-color(~`colorPalette('@{color}', 7) `; transparent; transparent);
68 | }
69 | .button-disabled(@disabled-color; transparent; transparent);
70 | }
71 |
--------------------------------------------------------------------------------
/lib/button/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/button/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './button.directive';
2 | export * from './button.module';
3 |
--------------------------------------------------------------------------------
/lib/checkbox/Checkbox.stories.ts:
--------------------------------------------------------------------------------
1 | import { moduleMetadata, Story, Meta, componentWrapperDecorator } from '@storybook/angular';
2 | import { NzxCheckboxComponent, NzxCheckboxOption } from './checkbox.component';
3 | import { EXCLUDE_PARAMS, hideControlArgType, storyFactory } from '@stories';
4 | import { action } from '@storybook/addon-actions';
5 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
6 | import { NzOutletModule } from 'ng-zorro-antd/core/outlet';
7 | import { Component, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
8 |
9 | export default {
10 | title: '组件/Checkbox 复选框',
11 | component: NzxCheckboxComponent,
12 | decorators: [
13 | moduleMetadata({
14 | declarations: [NzxCheckboxComponent],
15 | imports: [NzCheckboxModule, NzOutletModule]
16 | })
17 | ],
18 | argTypes: {
19 | ...hideControlArgType('nzxBlur', 'nzxFocus')
20 | },
21 | args: {
22 | nzxBlur: action('nzxBlur'),
23 | nzxFocus: action('nzxFocus'),
24 | nzxValue: []
25 | },
26 | parameters: {
27 | controls: {
28 | exclude: EXCLUDE_PARAMS
29 | }
30 | }
31 | } as Meta;
32 |
33 | const Template = (props: Partial): Story => {
34 | return storyFactory(
35 | props,
36 | `
37 |
44 | `
45 | );
46 | };
47 |
48 | function getNzxOptions(): NzxCheckboxOption[] {
49 | return Array(5)
50 | .fill(0)
51 | .map((v, i) => ({ label: `label-${i}`, value: `value-${i}` }));
52 | }
53 |
54 | export const Default = Template({ nzxOptions: getNzxOptions() });
55 |
56 | export const Checked = Template({ nzxValue: ['value-1'], nzxOptions: getNzxOptions() });
57 |
58 | export const NzxDisabled = Template({ nzxOptions: getNzxOptions(), nzxDisabled: true });
59 |
60 | export const HideOption = Template({
61 | nzxOptions: getNzxOptions().map((v, i) => {
62 | if (i < 3) {
63 | v.hide = true;
64 | }
65 | return v;
66 | })
67 | });
68 |
69 | export const DisabledOption = Template({
70 | nzxOptions: getNzxOptions().map((v, i) => {
71 | if (i == 1) {
72 | v.disabled = true;
73 | }
74 | return v;
75 | })
76 | });
77 |
78 | export const IndeterminateOption = Template({
79 | nzxOptions: getNzxOptions().map((v, i) => {
80 | if (i < 3) {
81 | v.indeterminate = true;
82 | }
83 | return v;
84 | })
85 | });
86 |
87 | export const NgModelChangeOption = Template({
88 | nzxOptions: getNzxOptions().map((v, i) => {
89 | v.ngModelChange = action('ngModelChange');
90 | return v;
91 | })
92 | });
93 |
94 | @Component({
95 | selector: 'test',
96 | template: `
97 | Hello
98 | `
99 | })
100 | export class FakeComponent implements OnInit {
101 | @ViewChild('hello', { static: true }) hello!: TemplateRef;
102 | @Input() nzxValue: any;
103 | @Input() nzxBlur: (evt: NzxCheckboxOption) => void = () => void 0;
104 | @Input() nzxFocus: (evt: NzxCheckboxOption) => void = () => void 0;
105 | @Input() nzxDisabled!: boolean;
106 | @Input() nzxOptions: NzxCheckboxOption[] = [];
107 |
108 | ngOnInit(): void {
109 | this.nzxOptions.forEach((v, i) => {
110 | if (i === 1) {
111 | v.label = this.hello;
112 | }
113 | });
114 | }
115 | }
116 |
117 | export const LabelOption = Template({
118 | nzxOptions: getNzxOptions()
119 | });
120 |
121 | LabelOption.decorators = [
122 | moduleMetadata({
123 | declarations: [FakeComponent],
124 | imports: [NzCheckboxModule, NzOutletModule]
125 | }),
126 | componentWrapperDecorator(FakeComponent)
127 | ];
128 |
--------------------------------------------------------------------------------
/lib/checkbox/checkbox.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/lib/checkbox/checkbox.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
5 | import { NzxCheckboxComponent } from './checkbox.component';
6 | import { NzOutletModule } from 'ng-zorro-antd/core/outlet';
7 |
8 | @NgModule({
9 | declarations: [NzxCheckboxComponent],
10 | imports: [CommonModule, FormsModule, ReactiveFormsModule, NzCheckboxModule, NzOutletModule],
11 | exports: [NzxCheckboxComponent]
12 | })
13 | export class NzxCheckboxModule {}
14 |
--------------------------------------------------------------------------------
/lib/checkbox/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/checkbox/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/checkbox/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './checkbox.component';
2 | export * from './checkbox.module';
3 |
--------------------------------------------------------------------------------
/lib/directive/auth.not.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
2 | import { NzxAntdService } from '@xmagic/nzx-antd';
3 | import { AuthContext, AuthDirective } from './auth.directive';
4 |
5 | /**
6 | * 权限指令, 无权限渲染模板,否则渲染else模板
7 | * @example
8 | *
9 | *
10 | * 有权限时显示
11 | */
12 | @Directive({
13 | selector: '[auth.not]'
14 | })
15 | export class AuthNotDirective extends AuthDirective {
16 | /** @internal */
17 | static authNotUseIfTypeGuard: void;
18 | static ngTemplateGuard_authNot: 'binding';
19 |
20 | /**
21 | * 布尔表达式,将其作为显示模板的条件进行计算。
22 | *
23 | */
24 | @Input('auth.not')
25 | set authNot(condition: T) {
26 | super.auth = condition;
27 | }
28 |
29 | /**
30 | * 当此条件表达式计算为 true 时要显示的模板。
31 | */
32 | @Input('auth.notThen')
33 | set authNotThen(templateRef: TemplateRef> | null) {
34 | super.authThen = templateRef;
35 | }
36 |
37 | /**
38 | * 当此条件表达式计算为 false 时要显示的模板。
39 | */
40 | @Input('auth.notElse')
41 | set authNotElse(templateRef: TemplateRef> | null) {
42 | super.authElse = templateRef;
43 | }
44 |
45 | /**
46 | * 是否允许渲染, 没有权限的时候渲染
47 | * @param hasAuth 是否有权限
48 | * @param value 权限码
49 | * @protected
50 | */
51 | protected override canRender(hasAuth: boolean, value: T) {
52 | return !hasAuth;
53 | }
54 |
55 | constructor(
56 | protected override _viewContainer: ViewContainerRef,
57 | public override templateRef: TemplateRef>,
58 | public override antdService: NzxAntdService
59 | ) {
60 | super(_viewContainer, templateRef, antdService);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/directive/click.once.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
2 | import { InputBoolean } from 'ng-zorro-antd/core/util';
3 |
4 | /**
5 | * 防止重复触发点击
6 | * @example
7 | *
8 | */
9 | @Directive({
10 | selector: '[click.once]'
11 | })
12 | export class ClickOnceDirective {
13 | constructor() {}
14 |
15 | /**
16 | * 点击延迟时间(单位:ms)
17 | */
18 | @Input() delay = 500;
19 | @Input() @InputBoolean() disabled = false;
20 | /**
21 | * neClick事件
22 | */
23 | @Output('click.once') clickEvent = new EventEmitter();
24 | /**
25 | * 原始点击事件
26 | * delay - 是否处于延迟状态
27 | */
28 | @Output() originClick = new EventEmitter<{ target: MouseEvent; delay: boolean }>();
29 | private _delayDisabled = false;
30 |
31 | @HostListener('click', ['$event'])
32 | clickEventHandle(event: MouseEvent): void {
33 | if (this.disabled) {
34 | return;
35 | }
36 |
37 | this.originClick.emit({ target: event, delay: this._delayDisabled });
38 | if (this._delayDisabled) {
39 | event.preventDefault();
40 | event.stopPropagation();
41 | return;
42 | }
43 |
44 | this._delayDisabled = true;
45 | setTimeout(() => (this._delayDisabled = false), this.delay);
46 | this.clickEvent.emit(event);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/lib/directive/directive.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NamedTemplate } from './named-template';
4 | import { ClickOnceDirective } from './click.once.directive';
5 | import { FaIconDirective } from './fa-icon.directive';
6 | import { ClickOutsideDirective } from './click-outside.directive';
7 | import { LetDirective } from './let.directive';
8 | import { DownFileDirective } from './down-file.directive';
9 | import { AuthDirective } from './auth.directive';
10 | import { AuthNotDirective } from './auth.not.directive';
11 | import { NzxServiceModule } from '@xmagic/nzx-antd/service';
12 | import { NgxFor } from './ngx-for.directive';
13 |
14 | const DIRECTIVE = [
15 | NamedTemplate,
16 | ClickOnceDirective,
17 | FaIconDirective,
18 | ClickOutsideDirective,
19 | LetDirective,
20 | DownFileDirective,
21 | AuthDirective,
22 | AuthNotDirective,
23 | NgxFor
24 | ];
25 | @NgModule({
26 | declarations: [DIRECTIVE],
27 | imports: [CommonModule, NzxServiceModule],
28 | exports: [DIRECTIVE]
29 | })
30 | export class NzxDirectiveModule {}
31 |
--------------------------------------------------------------------------------
/lib/directive/down-file.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, HostListener, Input } from '@angular/core';
2 | import { DownloadOption, NzxDownloadService, FetchOptions } from '@xmagic/nzx-antd/service';
3 |
4 | @Directive({
5 | selector: '[down-file]',
6 | exportAs: 'downFile'
7 | })
8 | export class DownFileDirective {
9 | /**
10 | * 下载文件的url
11 | */
12 | @Input('down-file') url!: string;
13 | /**
14 | * 是否禁用点击下载
15 | */
16 | @Input() disabled = false;
17 | /**
18 | * 请求方式
19 | */
20 | @Input() method: FetchOptions['method'] = 'get';
21 | /**
22 | * 请求参数
23 | */
24 | @Input() data?: FetchOptions['data'];
25 | /**
26 | * 发送之前的回调函数
27 | */
28 | @Input() beforeSend?: FetchOptions['beforeSend'];
29 |
30 | /**
31 | * 请求完成后的回调
32 | */
33 | @Input() afterDownload?: DownloadOption['afterDownload'];
34 |
35 | /**
36 | * 下载并保存完成的回调
37 | */
38 | @Input() downloadDone?: DownloadOption['downloadDone'];
39 | /**
40 | * 下载发生错误回调
41 | * @param error
42 | */
43 | @Input() downloadError?: DownloadOption['downloadError'];
44 |
45 | /**
46 | * 获取下载文件名函数
47 | */
48 | @Input() getFileName?: DownloadOption['getFileName'];
49 |
50 | constructor(private downloadService: NzxDownloadService) {}
51 |
52 | @HostListener('click', ['$event'])
53 | clickEventHandler(event: MouseEvent) {
54 | event.preventDefault();
55 | event.stopPropagation();
56 |
57 | if (this.disabled) {
58 | return;
59 | }
60 | this.downloadService.download({
61 | url: this.url,
62 | method: this.method,
63 | data: this.data,
64 | beforeSend: this.beforeSend,
65 | afterDownload: this.afterDownload,
66 | downloadDone: this.downloadDone,
67 | getFileName: this.getFileName
68 | });
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/directive/fa-icon.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, Input, OnChanges, OnInit, Renderer2, SimpleChange, SimpleChanges } from '@angular/core';
2 |
3 | /**
4 | * font-awesome 使用指令
5 | * @
6 | * this.render.removeClass(this.element.nativeElement, cls));
56 | }
57 | if (newIcon) {
58 | this.getIconClass(newIcon).forEach(cls => this.render.addClass(this.element.nativeElement, cls));
59 | }
60 | }
61 |
62 | getIconClass(icon: string): string[] {
63 | return icon ? icon.split(/\s/) : [];
64 | }
65 |
66 | renderSize(newSize?: IconSizeType, oldSize?: IconSizeType) {
67 | const newSizeCls = newSize ? `fa-${newSize}` : null;
68 | const oldSizeCls = oldSize ? `fa-${oldSize}` : null;
69 | this.renderIcon(newSizeCls, oldSizeCls);
70 | }
71 |
72 | ngOnChanges(changes: { [K in keyof this]?: SimpleChange } & SimpleChanges): void {
73 | if (changes.icon && !changes.icon.isFirstChange()) {
74 | this.renderIcon(changes.icon.currentValue, changes.icon.previousValue);
75 | }
76 |
77 | if (changes.size && !changes.size.isFirstChange()) {
78 | this.renderSize(changes.size.currentValue, changes.size.previousValue);
79 | }
80 | }
81 | }
82 |
83 | export type IconSizeType = 'xs' | 'lg' | 'sm' | '1x' | '2x' | '3x' | '4x' | '5x' | '6x' | '7x' | '8x' | '9x' | '10x';
84 |
--------------------------------------------------------------------------------
/lib/directive/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/directive/let.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Inject, Input, TemplateRef, ViewContainerRef } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 |
4 | /**
5 | * 允许在模板内复用计算值(包含异步),避免重复重新计算。
6 | * @example
7 | *
8 | *
11 | *
14 | */
15 | @Directive({ selector: '[let]' })
16 | export class LetDirective {
17 | @Input() let!: T;
18 |
19 | constructor(@Inject(ViewContainerRef) vc: ViewContainerRef, @Inject(TemplateRef) ref: TemplateRef>) {
20 | vc.createEmbeddedView(ref, new LetContext(this));
21 | }
22 |
23 | static ngTemplateContextGuard(_dir: LetDirective, _ctx: NzSafeAny): _ctx is LetDirective {
24 | return true;
25 | }
26 | }
27 |
28 | export class LetContext {
29 | constructor(private readonly directive: LetDirective) {}
30 |
31 | get $implicit(): T {
32 | return this.directive.let;
33 | }
34 |
35 | get let(): T {
36 | return this.directive.let;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/directive/named-template.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Input, OnInit, TemplateRef } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 |
4 | /**
5 | * 获取模板名称
6 | * @example
7 | * ``` html
8 | *
9 | *
10 | *
11 | * ```
12 | * ``` javascript
13 | * @Component(...)
14 | * export class TestComponent {
15 | * @ViewChildren(NamedTemplate) list!: QueryList;
16 | *
17 | * trace() {
18 | * this.list.forEach(it => {
19 | * console.log(it.named);
20 | * console.log(it.template);
21 | * });
22 | * }
23 | * }
24 | * ```
25 | */
26 | @Directive({
27 | selector: 'ng-template[named]',
28 | exportAs: 'namedTemplate'
29 | })
30 | export class NamedTemplate implements OnInit {
31 | /**
32 | * 模板名称
33 | */
34 | @Input() named!: string;
35 | constructor(public template: TemplateRef) {}
36 |
37 | ngOnInit(): void {
38 | this.resolveName();
39 | }
40 |
41 | resolveName() {
42 | if (!this.named && this.template) {
43 | const tplRef = this.template as NzSafeAny;
44 | // localNames为数组, 如果没有name则为null
45 | this.named = tplRef._declarationTContainer.localNames?.[0];
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/directive/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/directive/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './click.once.directive';
2 | export * from './named-template';
3 | export * from './fa-icon.directive';
4 | export * from './click-outside.directive';
5 | export * from './let.directive';
6 | export * from './auth.directive';
7 | export * from './auth.not.directive';
8 | export * from './down-file.directive';
9 | export * from './ngx-for.directive';
10 | export * from './directive.module';
11 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-custom-server-error.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
3 | import { Observable, catchError, throwError } from 'rxjs';
4 | import { HttpError } from './http.model';
5 | import { LogoutService } from './logout.service';
6 | import { DEFAULT_RESPONSE_SETTING, NzxAntdService, ResponseSetting } from '@xmagic/nzx-antd';
7 | import { NzxUtils } from '@xmagic/nzx-antd/util';
8 |
9 | /**
10 | * 在 http-error-interceptor 后,进行自定义错误处理。
11 | */
12 | @Injectable()
13 | export class HttpCustomServerErrorInterceptor implements HttpInterceptor {
14 | protected readonly settings: Required;
15 |
16 | constructor(
17 | protected logoutNotify: LogoutService,
18 | protected antdService: NzxAntdService
19 | ) {
20 | this.settings = NzxUtils.extend(
21 | {},
22 | DEFAULT_RESPONSE_SETTING,
23 | this.antdService.response
24 | ) as Required;
25 | }
26 |
27 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
28 | return next.handle(req).pipe(catchError((error, caught) => this.handleError(req, error, caught)));
29 | }
30 |
31 | /**
32 | * 只抛出自定义异常, 对于http内部异常由拦截器统一处理
33 | * @param req
34 | * @param error
35 | * @param caught 原始异常
36 | */
37 | handleError(req: HttpRequest, error: HttpError, caught: Observable>) {
38 | if (error.httpError) {
39 | return this.settings.handleError(req, error);
40 | // 登录超时 强制下线
41 | } else if (this.settings.timeout(error) || this.settings.forceLogout(error)) {
42 | this.logoutNotify.notifyLogin(error);
43 | return throwError(() => error);
44 | }
45 | return this.settings.handleError(req, error);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-default-encoder.ts:
--------------------------------------------------------------------------------
1 | import { HttpParameterCodec } from '@angular/common/http';
2 |
3 | export const HttpDefaultCodec: HttpParameterCodec = {
4 | decodeKey: (key: string): string => {
5 | return key;
6 | },
7 |
8 | decodeValue(value: string): string {
9 | return value;
10 | },
11 |
12 | encodeKey(key: string): string {
13 | return key;
14 | },
15 |
16 | encodeValue(value: string): string {
17 | return value;
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-error.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
3 | import { Observable, throwError } from 'rxjs';
4 | import { catchError } from 'rxjs/operators';
5 | import { HttpError } from './http.model';
6 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
7 | import { NzxAntdService } from '@xmagic/nzx-antd';
8 |
9 | /**
10 | * http 请求发生错误后进行处理
11 | */
12 | @Injectable()
13 | export class HttpErrorInterceptor implements HttpInterceptor {
14 | constructor(protected antdService: NzxAntdService) {}
15 |
16 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
17 | return next.handle(req).pipe(catchError(error => this.handleError(req, error)));
18 | }
19 |
20 | /**
21 | * 将错误响应包装为统一格式
22 | * @param req
23 | * @param errorResponse
24 | */
25 | handleError(req: HttpRequest, errorResponse: HttpErrorResponse) {
26 | if (this.antdService.handleHttpError) {
27 | return this.antdService.handleHttpError(req, errorResponse) as Observable;
28 | }
29 |
30 | const { status: code, error, message } = errorResponse;
31 | return throwError(() => new HttpError(true, code, message, error));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-header.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
3 | import { Observable } from 'rxjs';
4 | import { NzxAntdService } from '@xmagic/nzx-antd';
5 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
6 |
7 | /**
8 | * 对请求头进行处理
9 | */
10 | @Injectable()
11 | export class HttpHeaderInterceptor implements HttpInterceptor {
12 | constructor(protected antdService: NzxAntdService) {}
13 |
14 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
15 | const headers: Record = { 'X-Requested-With': 'XMLHttpRequest' };
16 | if (
17 | !req.headers.has('Content-Type') &&
18 | !(req.body instanceof FormData || req.body instanceof ArrayBuffer || req.body instanceof Blob)
19 | ) {
20 | headers['Content-Type'] =
21 | this.antdService.contentType === 'form'
22 | ? 'application/x-www-form-urlencoded'
23 | : 'application/json;charset=utf-8';
24 | }
25 | const clone = req.clone({
26 | setHeaders: headers
27 | });
28 | return next.handle(clone);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-interceptor.config.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_INTERCEPTORS } from '@angular/common/http';
2 | import { HttpLoadingInterceptor } from './http-loading.interceptor';
3 | import { HttpUrlInterceptor } from './http-url.interceptor';
4 | import { HttpHeaderInterceptor } from './http-header.interceptor';
5 | import { HttpParamsInterceptor } from './http-params.interceptor';
6 | import { HttpCustomServerErrorInterceptor } from './http-custom-server-error.interceptor';
7 | import { HttpResponseParseInterceptor } from './http-response-parse.interceptor';
8 | import { HttpErrorInterceptor } from './http-error.interceptor';
9 |
10 | /**
11 | * 注意,中间件是有序的,谨慎调整下列中间件的顺序
12 | */
13 | export const httpInterceptors = [
14 | { provide: HTTP_INTERCEPTORS, useClass: HttpLoadingInterceptor, multi: true },
15 | { provide: HTTP_INTERCEPTORS, useClass: HttpUrlInterceptor, multi: true },
16 | { provide: HTTP_INTERCEPTORS, useClass: HttpHeaderInterceptor, multi: true },
17 | { provide: HTTP_INTERCEPTORS, useClass: HttpParamsInterceptor, multi: true },
18 | { provide: HTTP_INTERCEPTORS, useClass: HttpCustomServerErrorInterceptor, multi: true },
19 | { provide: HTTP_INTERCEPTORS, useClass: HttpResponseParseInterceptor, multi: true },
20 | { provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true }
21 | ];
22 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-interceptor.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { HttpBackend, HttpClientModule } from '@angular/common/http';
3 | import { httpInterceptors } from './http-interceptor.config';
4 | import { AsyncHttpXhrBackend } from './xhr';
5 |
6 | @NgModule({
7 | imports: [HttpClientModule],
8 | providers: [httpInterceptors, AsyncHttpXhrBackend, { provide: HttpBackend, useExisting: AsyncHttpXhrBackend }]
9 | })
10 | export class NzxHttpInterceptorModule {}
11 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-loading.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
3 | import { Observable, Subject } from 'rxjs';
4 | import { filter, finalize } from 'rxjs/operators';
5 | import { HttpLoadingService } from './http-loading.service';
6 | import { LOADING_ENABLED } from '@xmagic/nzx-antd/service';
7 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
8 |
9 | /**
10 | * http 请求发送时,调用 loading service 显示加载中图标或者做一些其它处理。
11 | */
12 | @Injectable()
13 | export class HttpLoadingInterceptor implements HttpInterceptor {
14 | private showStatusChange = new Subject();
15 | private requestCount = 0;
16 |
17 | constructor(private loadingService: HttpLoadingService) {
18 | this.loadingService.init(this.showStatusChange.pipe(filter(() => this.requestCount === 0)));
19 | }
20 |
21 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
22 | const show = req.context.get(LOADING_ENABLED);
23 | if (show) {
24 | this.show();
25 | }
26 | return next.handle(req).pipe(finalize(() => show && this.hide()));
27 | }
28 |
29 | /**
30 | * 显示loading
31 | */
32 | show() {
33 | this.showStatusChange.next(true);
34 | this.requestCount++;
35 | }
36 |
37 | /**
38 | * 隐藏loading
39 | */
40 | hide() {
41 | this.requestCount--;
42 | this.showStatusChange.next(false);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-loading.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { Observable, Subject, Subscription } from 'rxjs';
3 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
4 |
5 | @Injectable({ providedIn: 'root' })
6 | export class HttpLoadingService {
7 | private httpLoadingStatus = new Subject();
8 |
9 | constructor() {}
10 |
11 | /**
12 | * HttpLoadingService needs a subject to tell the next loading status.
13 | * @param statusChangeObservable The subject who tells the loading status.
14 | */
15 | init(statusChangeObservable: Observable) {
16 | statusChangeObservable.subscribe(this.httpLoadingStatus);
17 | }
18 |
19 | /**
20 | * You have to subscribe the httpLoadingStatus$ in application to set custom loading behaviors through the method.
21 | *
22 | * @example
23 | * `app.component.ts`
24 | * ```ts
25 | * constructor(private loading: HttpLoadingService){}
26 | * ngOnInit() {
27 | * this.loading.subscribe(status => {
28 | * if(status){
29 | * this.modal.show('loading...');
30 | * }else{
31 | * this.modal.hide();
32 | * }
33 | * })
34 | * }
35 | * ```
36 | * @param next
37 | * @param error
38 | * @param complete
39 | */
40 | subscribe(next?: (value: boolean) => void, error?: (error: NzSafeAny) => void, complete?: () => void): Subscription {
41 | return this.httpLoadingStatus.subscribe({ next, error, complete });
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-params.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpParams, HttpRequest } from '@angular/common/http';
3 | import { Observable } from 'rxjs';
4 | import { HttpDefaultCodec } from './http-default-encoder';
5 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
6 | import { NzxUtils } from '@xmagic/nzx-antd/util';
7 |
8 | /**
9 | * 请求参数处理
10 | */
11 | @Injectable()
12 | export class HttpParamsInterceptor implements HttpInterceptor {
13 | constructor() {}
14 |
15 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
16 | return next.handle(this.processParameters(req));
17 | }
18 |
19 | processParameters(req: HttpRequest) {
20 | if (req.params == null) {
21 | return req;
22 | }
23 | return req.clone({
24 | params: this.processGetParams(req.params)
25 | });
26 | }
27 |
28 | processGetParams(params: HttpParams) {
29 | const result: Record = { r: Math.random() };
30 |
31 | params.keys().reduce((acc, key) => {
32 | const values = params.getAll(key);
33 | if (values) {
34 | acc[key] = values.length > 1 ? values : values[0];
35 | return acc;
36 | }
37 | return acc;
38 | }, result);
39 |
40 | return new HttpParams({ fromString: NzxUtils.serialize(result), encoder: HttpDefaultCodec });
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-response-parse.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {
3 | HttpEvent,
4 | HttpEventType,
5 | HttpHandler,
6 | HttpInterceptor,
7 | HttpRequest,
8 | HttpResponse
9 | } from '@angular/common/http';
10 | import { Observable, Subscriber } from 'rxjs';
11 | import { switchMap } from 'rxjs/operators';
12 | import { HttpError, ResponseModel } from './http.model';
13 | import { DEFAULT_RESPONSE_SETTING, NzxAntdService, ResponseSetting } from '@xmagic/nzx-antd';
14 | import { NzxUtils } from '@xmagic/nzx-antd/util';
15 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
16 |
17 | /**
18 | * 处理服务器返回的数据,改变其结构。
19 | */
20 | @Injectable()
21 | export class HttpResponseParseInterceptor implements HttpInterceptor {
22 | protected readonly settings: Required;
23 | constructor(protected antdService: NzxAntdService) {
24 | this.settings = NzxUtils.extend(
25 | {},
26 | DEFAULT_RESPONSE_SETTING,
27 | this.antdService.response
28 | ) as Required;
29 | }
30 |
31 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
32 | return next.handle(req).pipe(
33 | switchMap(response => {
34 | return new Observable>(observ => {
35 | if (response.type !== HttpEventType.Response) {
36 | observ.next(response);
37 | return;
38 | }
39 | this.processData(observ, req, response);
40 | });
41 | })
42 | );
43 | }
44 |
45 | protected processData(
46 | subscriber: Subscriber>,
47 | req: HttpRequest,
48 | response: HttpResponse
49 | ) {
50 | const contentType = (response.headers.get('content-type') || '').toLowerCase();
51 |
52 | const isJsonResponse = contentType.indexOf('application/json') !== -1;
53 | if (!isJsonResponse) {
54 | subscriber.next(response as HttpResponse);
55 | subscriber.complete();
56 | return;
57 | }
58 |
59 | const { data: dataProp, code: codeProp, message: messageProp, success: successProp } = this.settings;
60 |
61 | // 处理下载文件错误
62 | if (isJsonResponse && response.body instanceof Blob) {
63 | const reader = new FileReader();
64 | reader.onload = () => {
65 | const err = JSON.parse(reader.result as string) as ResponseModel;
66 | const httpError = new HttpError(
67 | false,
68 | NzxUtils.get(err, codeProp, 0),
69 | this.getBodyAttr(req, response, err, messageProp),
70 | err
71 | );
72 | subscriber.error(httpError);
73 | };
74 | reader.readAsText(response.body);
75 | return;
76 | }
77 |
78 | const body = response.body || {};
79 | if (successProp(req, response)) {
80 | const resp = response.clone({ body: this.getBodyAttr(req, response, body, dataProp) });
81 | subscriber.next(resp);
82 | subscriber.complete();
83 | } else {
84 | const httpError = new HttpError(
85 | false,
86 | NzxUtils.get(body, codeProp, 0),
87 | this.getBodyAttr(req, response, body, messageProp),
88 | body
89 | );
90 | subscriber.error(httpError);
91 | }
92 | }
93 |
94 | private getBodyAttr(
95 | req: HttpRequest,
96 | response: HttpResponse,
97 | body: NzSafeAny,
98 | attrOrFn: string | ((req: HttpRequest, response: HttpResponse) => NzSafeAny)
99 | ) {
100 | return attrOrFn ? (NzxUtils.isFunction(attrOrFn) ? attrOrFn(req, response) : NzxUtils.get(body, attrOrFn)) : body;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http-url.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
3 | import { Observable } from 'rxjs';
4 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
5 | import { HttpRequestOptions, NzxAntdService } from '@xmagic/nzx-antd';
6 |
7 | /**
8 | * 处理 URL
9 | */
10 | @Injectable()
11 | export class HttpUrlInterceptor implements HttpInterceptor {
12 | constructor(protected antdService: NzxAntdService) {}
13 |
14 | intercept(req: HttpRequest, next: HttpHandler): Observable> {
15 | return next.handle(this.processUrl(req));
16 | }
17 |
18 | processUrl(req: HttpRequest): HttpRequest {
19 | let url = req.url;
20 | if (!/^http/i.test(url)) {
21 | if (!/^\//.test(url)) {
22 | url = '/' + url;
23 | }
24 | url = (this.antdService.basePath || '') + url;
25 | }
26 |
27 | // 使用自定义请求处理器
28 | if (this.antdService.handleRequest) {
29 | const newReq = this.antdService.handleRequest(req, url);
30 | if (newReq) {
31 | if ((newReq as HttpRequest).clone) {
32 | return newReq as HttpRequest;
33 | }
34 | const option = newReq as HttpRequestOptions;
35 | if (!option.url) {
36 | option.url = url;
37 | }
38 | return req.clone(option);
39 | }
40 | }
41 | return req.clone({ url });
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/http-interceptor/http.model.ts:
--------------------------------------------------------------------------------
1 | import { NzSafeAny } from 'ng-zorro-antd/core/types'
2 |
3 | /**
4 | * 服务端响应实体, 可以通过设置 http请求参数
5 | * {observe: 'response'} 拿到完整数据
6 | */
7 | export interface ResponseModel {
8 | /**
9 | * 服务端返回编码
10 | */
11 | code?: number;
12 | message?: string;
13 | data?: T;
14 | }
15 |
16 | /**
17 | * http 请求出错后,在中间件中封闭为统一的格式。
18 | */
19 | export class HttpError {
20 | /**
21 | *
22 | * @param httpError 是否是HTTP原始异常
23 | * @param code 错误码, 如果是HTTP原始异常,则为status code
24 | * @param message 错误消息
25 | * @param body 返回数据
26 | */
27 | constructor(public httpError: boolean, public code: number, public message: string, public body: T) {}
28 | }
29 |
--------------------------------------------------------------------------------
/lib/http-interceptor/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/http-interceptor/logout.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpError, ResponseModel } from './http.model';
3 | import { Subject, Subscription } from 'rxjs';
4 | import { throttleTime } from 'rxjs/operators';
5 | import { NzxUtils } from '@xmagic/nzx-antd/util';
6 | import { DEFAULT_RESPONSE_SETTING, NzxAntdService, ResponseSetting } from '@xmagic/nzx-antd'
7 |
8 | /**
9 | * 退出通知
10 | */
11 | @Injectable({ providedIn: 'root' })
12 | export class LogoutService {
13 | protected readonly timeoutFn: (error: HttpError) => boolean;
14 | private loginNotify$ = new Subject();
15 |
16 | constructor(protected antdService: NzxAntdService) {
17 | this.timeoutFn = NzxUtils.extend({}, DEFAULT_RESPONSE_SETTING, this.antdService.response).timeout!;
18 | }
19 |
20 | notifyLogin(error: HttpError): void {
21 | this.loginNotify$.next({
22 | message: error.message,
23 | url: (error.body as { url?: string })?.url,
24 | timeout: this.timeoutFn(error)
25 | });
26 | }
27 |
28 | /**
29 | * 静默通知退出
30 | * @param message 提示消息
31 | * @param code 错误码 -1 不显示提示信息
32 | */
33 | notifyLogout(message: string = '', code = 0): void {
34 | this.notifyLogin(new HttpError(false, code, message, {}));
35 | }
36 |
37 | /**
38 | * 执行退出登录Observable
39 | * @param logoutType
40 | */
41 | logout(logoutType: LogoutType): void {
42 | this.loginNotify$.next(logoutType);
43 | }
44 |
45 | onLogout(fn: (logoutType: LogoutType) => void): Subscription {
46 | return this.loginNotify$.asObservable().pipe(throttleTime(2000)).subscribe(fn);
47 | }
48 | }
49 |
50 | export interface LogoutType {
51 | /**
52 | * url
53 | */
54 | url?: string;
55 | /**
56 | * 是否超时
57 | */
58 | timeout?: boolean;
59 | /**
60 | * 错误信息
61 | */
62 | message?: string;
63 | }
64 |
--------------------------------------------------------------------------------
/lib/http-interceptor/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/http-interceptor/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './http-custom-server-error.interceptor';
2 | export * from './http-error.interceptor';
3 | export * from './http.model';
4 | export * from './http-loading.interceptor';
5 | export * from './http-loading.service';
6 | export * from './logout.service';
7 | export * from './http-params.interceptor';
8 | export * from './http-response-parse.interceptor';
9 | export * from './http-url.interceptor';
10 | export * from './http-default-encoder';
11 | export * from './http-interceptor.config';
12 | export * from './http-interceptor.module';
13 | export * from './xhr';
14 |
--------------------------------------------------------------------------------
/lib/index.less:
--------------------------------------------------------------------------------
1 | @import 'ng-zorro-antd/style/entry.less';
2 | @import 'ng-zorro-antd/components.less';
3 |
4 | @import './between/between.component.less';
5 | @import './layout-page/layout-page.less';
6 | @import './table/index.less';
7 | @import './button/button.less';
8 |
--------------------------------------------------------------------------------
/lib/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'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, '../../coverage/nzx-antd'),
29 | subdir: '.',
30 | reporters: [
31 | { type: 'html' },
32 | { type: 'text-summary' }
33 | ]
34 | },
35 | reporters: ['progress', 'kjhtml'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/lib/layout-page/content.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, HostBinding, Input, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'nzx-content',
5 | template: '',
6 | host: {
7 | '[class.nzx-page-content]': 'true'
8 | }
9 | })
10 | export class NzxContentComponent {
11 | /**
12 | * 显示验证占位符(是否显示form-item底部的空白)
13 | */
14 | @Input() formItemBottomVisible = true;
15 | /**
16 | * margin
17 | */
18 | @Input() margin?: string;
19 | /**
20 | * margin top
21 | */
22 | @Input() marginTop = '10px';
23 |
24 | @HostBinding('class.hide-form-item-bottom') get hideFormItemBottom() {
25 | return !this.formItemBottomVisible;
26 | }
27 | @HostBinding('style.margin') get contentMargin() {
28 | return this.margin;
29 | }
30 | @HostBinding('style.margin-top') get contentMarginTop() {
31 | return this.marginTop;
32 | }
33 | constructor() {}
34 | }
35 |
--------------------------------------------------------------------------------
/lib/layout-page/header.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, HostBinding, Input } from '@angular/core';
2 | import { isContentEmpty } from './is-content-empty';
3 |
4 | @Component({
5 | selector: 'nzx-header',
6 | template: `
7 |
20 | `,
21 | host: {
22 | '[class.nzx-page-header]': 'true'
23 | }
24 | })
25 | export class NzxHeaderComponent {
26 | hasContent = false;
27 | /**
28 | * 显示验证占位符(是否显示form-item底部的空白)
29 | */
30 | @Input() hasBottom = false;
31 | /**
32 | * 是否显示按钮区域
33 | */
34 | @Input() buttonsVisible = true;
35 | @HostBinding('class.hide-form-item-bottom') get hideFormItemBottom() {
36 | return !this.hasBottom;
37 | }
38 |
39 | constructor() {}
40 |
41 | contentChanged(element: HTMLElement) {
42 | this.hasContent = !isContentEmpty(element);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/layout-page/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/layout-page/is-content-empty.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * 用于校验 `` 是否为空,自定义组件时蛮有用。
4 | */
5 | export function isContentEmpty(element: HTMLElement): boolean {
6 | const nodes = element.childNodes;
7 | for (let i = 0; i < nodes.length; i++) {
8 | const node = nodes.item(i);
9 | if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).outerHTML.trim().length !== 0) {
10 | return false;
11 | } else if (node.nodeType === Node.TEXT_NODE && node.textContent!.trim().length !== 0) {
12 | return false;
13 | }
14 | }
15 | return true;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/layout-page/layout-page.less:
--------------------------------------------------------------------------------
1 | @import '../base.less';
2 | @nzx-page-prefix: ~'@{nzx-prefix}-page';
3 | @nzx-page-header-prefix: ~'@{nzx-prefix}-page-header';
4 | @nzx-page-content-prefix: ~'@{nzx-prefix}-page-content';
5 | @nzx-page-background-color: #f0f2f5;
6 |
7 | .@{nzx-page-prefix}{
8 | flex-direction: column;
9 | display: flex;
10 | height: 100%;
11 | background: @nzx-page-background-color;
12 | }
13 |
14 | .@{nzx-page-content-prefix}{
15 | padding: 6px;
16 | flex: 1;
17 | background-color: #fff;
18 | border-radius: 2px;
19 |
20 | &.hide-form-item-bottom .ant-form-item {
21 | margin-bottom: 3px;
22 | }
23 | }
24 |
25 | .@{nzx-page-header-prefix}{
26 | background-color: #fff;
27 | padding: 12px 10px;
28 | border-radius: 2px;
29 |
30 | &.hide-form-item-bottom .ant-form-item {
31 | margin-bottom: 3px;
32 | }
33 | .page-header_row {
34 | display: flex;
35 | }
36 | .page-header_col {
37 | flex: 1;
38 | }
39 | .header-content-wrapper {
40 | padding-left: 10px;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/layout-page/layout-page.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxContentComponent } from './content.component';
4 | import { NzxPageComponent } from './page.component';
5 | import { NzxHeaderComponent } from './header.component';
6 | import { ObserversModule } from '@angular/cdk/observers';
7 |
8 | const COMPONENTS = [NzxContentComponent, NzxPageComponent, NzxHeaderComponent];
9 |
10 | @NgModule({
11 | declarations: [COMPONENTS],
12 | imports: [CommonModule, ObserversModule],
13 | exports: [COMPONENTS]
14 | })
15 | export class NzxLayoutPageModule {}
16 |
--------------------------------------------------------------------------------
/lib/layout-page/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/layout-page/page.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'nzx-page',
5 | template: '',
6 | host: {
7 | '[class.nzx-page]': 'true'
8 | }
9 | })
10 | export class NzxPageComponent {
11 | constructor() {}
12 | }
13 |
--------------------------------------------------------------------------------
/lib/layout-page/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './content.component';
2 | export * from './page.component';
3 | export * from './header.component';
4 | export * from './layout-page.module';
5 | export * from './is-content-empty';
6 |
--------------------------------------------------------------------------------
/lib/modal/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/modal/modal-drag.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, Host } from '@angular/core';
2 | import { NzModalComponent } from 'ng-zorro-antd/modal';
3 | import { NzxModalDragService } from './modal-drag.service';
4 |
5 | /**
6 | * 可拖动的对话框
7 | * @example
8 | * ``` html
9 | *
10 | ```
11 | */
12 | @Directive({
13 | selector: 'nz-modal[nzxModalDrag]'
14 | })
15 | export class NzxModalDragDirective {
16 | constructor(@Host() protected modal: NzModalComponent, public modalDragService: NzxModalDragService) {
17 | const wrapCls = this.modalDragService.getRandomCls();
18 | modal.afterOpen.subscribe(() => {
19 | const modelElement = modal.getElement()!;
20 | if (!modelElement || modelElement.className.indexOf(NzxModalDragService.DRAG_CLS_PREFIX) !== -1) {
21 | return;
22 | }
23 |
24 | modelElement.classList.add(wrapCls);
25 | const drag = this.modalDragService.createDragHandler(wrapCls, modal.nzMask, modal.nzModalType);
26 | modal.afterClose.subscribe(() => {
27 | if (drag && !drag.dropped) {
28 | drag.dispose();
29 | }
30 | });
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/modal/modal-drag.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { DragDrop, DragRef } from '@angular/cdk/drag-drop';
3 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
4 | import { ModalTypes, NzModalService } from 'ng-zorro-antd/modal';
5 |
6 | /**
7 | * 对话框拖动服务
8 | */
9 | @Injectable()
10 | export class NzxModalDragService {
11 | static readonly DRAG_CLS_PREFIX = 'NZ-MODAL-WRAP-CLS-';
12 | constructor(public modal: NzModalService, public dragDrop: DragDrop) {}
13 |
14 | /**
15 | * 创建拖拽手柄
16 | * @param wrapCls 类名
17 | * @param nzMask 是否有遮罩
18 | * @param nzModalType 对话框类型
19 | */
20 | createDragHandler(wrapCls: string, nzMask?: boolean, nzModalType?: ModalTypes): DragRef {
21 | const wrapElement = document.querySelector(`.${wrapCls}`)!;
22 | const rootElement = wrapElement.querySelector(`.ant-modal-content`)!;
23 | const handle =
24 | nzModalType === 'confirm'
25 | ? rootElement.querySelector('.ant-modal-body')!
26 | : rootElement.querySelector('.ant-modal-header')!;
27 | this.fixedWrapElementStyle(wrapElement);
28 | if (!(nzMask == null || nzMask)) {
29 | this.setMaxZIndex(rootElement, wrapElement);
30 | }
31 | return this.dragDrop.createDrag(handle).withHandles([handle]).withRootElement(rootElement);
32 | }
33 |
34 | /**
35 | * 获取随机类名
36 | */
37 | getRandomCls() {
38 | return NzxModalDragService.DRAG_CLS_PREFIX + Date.now() + Math.random().toString().replace('0.', '');
39 | }
40 |
41 | /**
42 | * 解决wrap的样式, 设置鼠标可以穿透
43 | * @param wrapElement
44 | * @protected
45 | */
46 | protected fixedWrapElementStyle(wrapElement: HTMLElement): void {
47 | wrapElement.style.pointerEvents = 'none';
48 | }
49 |
50 | /**
51 | * 当前对话框点击时,设置当前对话框z-index为最大
52 | * @param rootElement 当前对话框
53 | * @param wrapElement 待修改z-index 容器
54 | * @protected
55 | */
56 | protected setMaxZIndex(rootElement: HTMLElement, wrapElement: HTMLElement): void {
57 | rootElement.addEventListener(
58 | 'mousedown',
59 | () => {
60 | const maxZIndex = this.getModalMaxZIndex(wrapElement);
61 | if (maxZIndex) {
62 | wrapElement.style.zIndex = maxZIndex + 1 + '';
63 | }
64 | },
65 | false
66 | );
67 | }
68 |
69 | /**
70 | * 获取所有对话框最大值,并确定是否需要修改
71 | * @param wrapElement 待修改z-index 容器
72 | */
73 | protected getModalMaxZIndex(wrapElement: HTMLElement): number | null {
74 | const wrapZIndex = this.getZIndex(wrapElement);
75 | const maxZIndex = this.modal.openModals.reduce((prev, modal) => {
76 | // @ts-ignore
77 | const element = (modal.containerInstance.host || modal.containerInstance.elementRef).nativeElement;
78 | if (wrapElement === element) {
79 | return prev;
80 | }
81 | const zIndex = this.getZIndex(element);
82 | return zIndex > prev ? zIndex : prev;
83 | }, 0);
84 | return maxZIndex >= wrapZIndex ? maxZIndex : null;
85 | }
86 |
87 | protected getZIndex(element: HTMLElement): number {
88 | return +getComputedStyle(element, null).zIndex;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/lib/modal/modal.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { NzxModalService } from './nzx-modal.service';
3 | import { NzModalModule } from 'ng-zorro-antd/modal';
4 | import { NzxModalDragDirective } from './modal-drag.directive';
5 | import { NzxModalDragService } from './modal-drag.service';
6 |
7 | @NgModule({
8 | declarations: [NzxModalDragDirective],
9 | imports: [NzModalModule],
10 | exports: [NzxModalDragDirective],
11 | providers: [NzxModalService, NzxModalDragService]
12 | })
13 | export class NzxModalModule {}
14 |
--------------------------------------------------------------------------------
/lib/modal/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/modal/nzx-modal.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 |
3 | import { Subject } from 'rxjs';
4 | import { ConfirmType, ModalOptions, NzModalRef, NzModalService } from 'ng-zorro-antd/modal';
5 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
6 | import { NzxModalDragService } from './modal-drag.service';
7 |
8 | @Injectable()
9 | export class NzxModalService {
10 | constructor(
11 | public modal: NzModalService,
12 | public modalDragService: NzxModalDragService
13 | ) {}
14 |
15 | /**
16 | * 创建对话框, 增加可拖拽功能
17 | * @param config NzxModalOptions
18 | */
19 | create(config: NzxModalOptions): NzModalRef {
20 | return this.createModalWidthDrag(config, c => this.modal.create(c));
21 | }
22 |
23 | get openModals(): NzModalRef[] {
24 | return this.modal.openModals;
25 | }
26 |
27 | get afterAllClosed(): Subject {
28 | return this.modal._afterAllClosed;
29 | }
30 |
31 | closeAll(): void {
32 | this.modal.closeAll();
33 | }
34 |
35 | confirm(options: NzxModalOptions, confirmType?: ConfirmType): NzModalRef {
36 | return this.createModalWidthDrag(options, c => this.modal.confirm(c, confirmType));
37 | }
38 |
39 | info(options: NzxModalOptions): NzModalRef {
40 | return this.createModalWidthDrag(options, c => this.modal.info(c));
41 | }
42 |
43 | success(options: NzxModalOptions): NzModalRef {
44 | return this.createModalWidthDrag(options, c => this.modal.success(c));
45 | }
46 |
47 | error(options: NzxModalOptions): NzModalRef {
48 | return this.createModalWidthDrag(options, c => this.modal.error(c));
49 | }
50 |
51 | warning(options: NzxModalOptions): NzModalRef {
52 | return this.createModalWidthDrag(options, c => this.modal.warning(c));
53 | }
54 |
55 | protected createModalWidthDrag(
56 | config: NzxModalOptions,
57 | create: (newConfig: NzxModalOptions) => NzModalRef
58 | ) {
59 | const wrapCls = this.modalDragService.getRandomCls();
60 | const newConfig = this.createModalConfig(config, wrapCls);
61 | const modalRef = create(newConfig);
62 |
63 | modalRef.afterOpen.subscribe(() => {
64 | if (config.draggable !== false) {
65 | const drag = this.modalDragService.createDragHandler(wrapCls, config.nzMask, newConfig.nzModalType);
66 | modalRef.afterClose.subscribe(() => {
67 | if (drag && !drag.dropped) {
68 | drag.dispose();
69 | }
70 | });
71 | }
72 | });
73 | return modalRef;
74 | }
75 |
76 | protected createModalConfig(config: NzxModalOptions, wrapCls: string): NzxModalOptions {
77 | const defaultConfig: NzxModalOptions = {
78 | nzMaskClosable: false,
79 | nzTitle: '提示'
80 | };
81 | const maskStyle = config.nzMask === false ? { nzMaskStyle: { display: 'none' } } : {};
82 | const newConfig = Object.assign(defaultConfig, config, maskStyle);
83 | newConfig.nzWrapClassName = (newConfig.nzWrapClassName || '') + ' ' + wrapCls;
84 | return newConfig;
85 | }
86 | }
87 |
88 | export interface NzxModalOptions extends ModalOptions {
89 | /**
90 | * 是否允许拖拽
91 | */
92 | draggable?: boolean;
93 | /**
94 | * 允许改变窗口大小
95 | */
96 | resizable?: boolean;
97 | /**
98 | * 允许最大值
99 | */
100 | maximum?: boolean;
101 | /**
102 | * 允许最小值
103 | */
104 | minimum?: boolean;
105 | }
106 |
--------------------------------------------------------------------------------
/lib/modal/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './modal.module';
2 | export * from './nzx-modal.service';
3 | export * from './modal-drag.service';
4 | export * from './modal-drag.directive';
5 |
--------------------------------------------------------------------------------
/lib/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../dist/nzx-antd",
4 | "lib": {
5 | "entryFile": "./public-api.ts",
6 | "styleIncludePaths": ["node_modules"]
7 | },
8 | "assets": [
9 | "./**/*.less"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/lib/nzx-antd.less:
--------------------------------------------------------------------------------
1 | @import 'ng-zorro-antd/style/default.less';
2 | @import './index.less';
3 |
--------------------------------------------------------------------------------
/lib/nzx-antd.module.ts:
--------------------------------------------------------------------------------
1 | // import { NgModule } from '@angular/core';
2 | // import { NzxModalModule } from '@xmagic/nzx-antd/modal';
3 | // import { NzxDirectiveModule } from '@xmagic/nzx-antd/directive';
4 | // import { NzxTableModule } from '@xmagic/nzx-antd/table';
5 | // import { NzxPipeModule } from '@xmagic/nzx-antd/pipe';
6 | // import { NzxSwitchModule } from '@xmagic/nzx-antd/switch';
7 | // import { NzxServiceModule } from '@xmagic/nzx-antd/service';
8 | // import { NzxBetweenModule } from '@xmagic/nzx-antd/between';
9 | // import { NzxBetweenInputModule } from '@xmagic/nzx-antd/between-input';
10 | // import { NzxCheckboxModule } from '@xmagic/nzx-antd/checkbox';
11 | // import { NzxUploadModule } from '@xmagic/nzx-antd/upload';
12 | // import { NzxBetweenDatetimeModule } from '@xmagic/nzx-antd/between-datetime';
13 | // import { NzxBetweenTimeModule } from '@xmagic/nzx-antd/between-time';
14 | // import { NzxHttpInterceptorModule } from '@xmagic/nzx-antd/http-interceptor';
15 | // import { NzxRepeatModule } from '@xmagic/nzx-antd/repeat';
16 | // import { NzxLayoutPageModule } from '@xmagic/nzx-antd/layout-page';
17 | //
18 | // @NgModule({
19 | // imports: [],
20 | // exports: [
21 | // NzxBetweenModule,
22 | // NzxBetweenInputModule,
23 | // NzxCheckboxModule,
24 | // NzxModalModule,
25 | // NzxDirectiveModule,
26 | // NzxTableModule,
27 | // NzxPipeModule,
28 | // NzxSwitchModule,
29 | // NzxServiceModule,
30 | // NzxUploadModule,
31 | // NzxBetweenDatetimeModule,
32 | // NzxBetweenTimeModule,
33 | // NzxHttpInterceptorModule,
34 | // NzxLayoutPageModule,
35 | // NzxRepeatModule
36 | // ],
37 | // declarations: []
38 | // })
39 | // export class NzxAntdModule {}
40 |
--------------------------------------------------------------------------------
/lib/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@xmagic/nzx-antd",
3 | "version": "17.0.13",
4 | "repository": {
5 | "type": "git",
6 | "url": "https://github.com/m310851010/nzx-antd.git"
7 | },
8 | "author": "m310851010",
9 | "publishConfig": {
10 | "access": "public"
11 | },
12 | "license": "MIT"
13 | }
14 |
--------------------------------------------------------------------------------
/lib/pipe/defaultify.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 | import { NzxAntdService } from '@xmagic/nzx-antd';
4 |
5 | @Pipe({
6 | name: 'defaultify',
7 | pure: true
8 | })
9 | export class DefaultifyPipe implements PipeTransform {
10 | constructor(protected antdService: NzxAntdService) {}
11 | transform(value: T | undefined | null, defaultValue?: T | string): T | string {
12 | return value == null ? ((defaultValue == null ? this.antdService.defaultify || '--' : defaultValue) as T) : value;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/pipe/dic.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { DicItem, DicService } from '@xmagic/nzx-antd/service';
3 | import { map, Observable, of } from 'rxjs';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 |
6 | /**
7 | * 字典管道
8 | * @example
9 | *
10 | * ``` html
11 | * {{1 | dic: 'status' | async}} // 'label'
12 | *
13 | * {{'A' | dic: 'status' | async}} // 'label'
14 | *
15 | * {{'A' | dic: statusObservable$ | async}} // 'label'
16 | *
17 | * {{'A' | dic: statusObservable$ : true | async}} // dic item
18 | *
19 | *
20 | * ```
21 | */
22 | @Pipe({
23 | name: 'dic',
24 | pure: true
25 | })
26 | export class DicPipe implements PipeTransform {
27 | constructor(protected dicService: DicService) {}
28 |
29 | /**
30 | * 字典管道, 获取字典项label
31 | * @param key 字典项key
32 | * @param dicItemsOrKey 字典名称
33 | */
34 | transform(
35 | key: string | number | null,
36 | dicItemsOrKey: Observable | string
37 | ): Observable;
38 |
39 | /**
40 | * 字典管道, 获取字典项label
41 | * @param key 字典项key
42 | * @param dicItemsOrKey 字典名称
43 | * @param isGetItem 获取字典项label
44 | */
45 | transform(
46 | key: string | number | null,
47 | dicItemsOrKey: Observable | string,
48 | isGetItem: false
49 | ): Observable;
50 |
51 | /**
52 | * 字典管道, 获取字典项
53 | * @param key 字典项key
54 | * @param dicItemsOrKey 字典名称
55 | * @param isGetItem 获取字典项
56 | */
57 | transform(
58 | key: string | number | null,
59 | dicItemsOrKey: Observable | string,
60 | isGetItem: true
61 | ): Observable;
62 |
63 | /**
64 | * 字典管道
65 | * @param key 字典项key
66 | * @param dicItemsOrKey 字典名称
67 | * @param isGetItem 是否获取字典项
68 | */
69 | transform(
70 | key: string | number | null,
71 | dicItemsOrKey: Observable | string,
72 | isGetItem?: boolean
73 | ): Observable {
74 | if (key == null) {
75 | return of(null);
76 | }
77 | const dic$ = NzxUtils.isString(dicItemsOrKey) ? this.dicService.getDic(dicItemsOrKey) : dicItemsOrKey;
78 | return dic$.pipe(map(list => NzxUtils.listToMap(list, 'value', isGetItem ? (v: DicItem) => v : 'label')[key]));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/lib/pipe/filter.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 | import { NzxUtils } from '@xmagic/nzx-antd/util';
4 |
5 | @Pipe({
6 | name: 'filter',
7 | pure: true
8 | })
9 | export class FilterPipe implements PipeTransform {
10 | transform(array: T[], matcher: string, searchText?: string): T[];
11 | transform(array: T[], matcher: FilterMatcherFn): T[];
12 |
13 | /**
14 | * Filter array
15 | *
16 | * 过滤数组
17 | */
18 | transform(array: T[], matcher: FilterMatcherFn | string, searchText?: string): T[] {
19 | if (typeof matcher === 'string') {
20 | if (NzxUtils.isEmpty(searchText)) {
21 | return array;
22 | }
23 |
24 | // @ts-ignore
25 | const text = searchText.toLowerCase();
26 | return (array || []).filter(v => NzxUtils.get(v, matcher, '').toLowerCase().indexOf(text) !== -1);
27 | }
28 | return (array || []).filter(v => matcher(v));
29 | }
30 | }
31 |
32 | export type FilterMatcherFn = (item: T) => boolean;
33 |
--------------------------------------------------------------------------------
/lib/pipe/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/pipe/math.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 |
3 | /**
4 | * 调用数学函数 如{{ 5.1 | math: 'ceil' }} => 6
5 | */
6 | @Pipe({
7 | name: 'math',
8 | pure: true
9 | })
10 | export class MathPipe implements PipeTransform {
11 | transform(value: string | number, fnName: keyof Math, fixed?: number): string | null {
12 | if (value == null) {
13 | return null;
14 | }
15 | const n: number = typeof value === 'string' ? Number(value) : value;
16 | // @ts-ignore
17 | const result = Math[fnName](n);
18 | return fixed == null ? result : n.toFixed(fixed);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/pipe/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/pipe/path-value.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { NzxUtils } from '@xmagic/nzx-antd/util';
3 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
4 |
5 | /**
6 | * 根据路径获取数据
7 | * @example
8 | * {{ {a: {b: 1}} | pathValue: 'a.b'}} // 1
9 | */
10 | @Pipe({
11 | name: 'pathValue',
12 | pure: true
13 | })
14 | export class PathValuePipe implements PipeTransform {
15 | transform(value: NzSafeAny, path: string, defaultValue?: NzSafeAny): T {
16 | return NzxUtils.get(value, path, defaultValue);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/pipe/pipe.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { MathPipe } from './math.pipe';
4 | import { DefaultifyPipe } from './defaultify.pipe';
5 | import { TrustHtmlPipe, TrustScriptPipe, TrustStylePipe, TrustUrlPipe } from './trust-resource.pipe';
6 | import { TimeUnitPipe } from './time-unit.pipe';
7 | import { ToAsyncPipe } from './to-async.pipe';
8 | import { FilterPipe } from './filter.pipe';
9 | import { DicPipe } from './dic.pipe';
10 | import { PathValuePipe } from './path-value.pipe';
11 |
12 | const PIPE = [
13 | MathPipe,
14 | DefaultifyPipe,
15 | TrustUrlPipe,
16 | TrustHtmlPipe,
17 | TrustScriptPipe,
18 | TrustStylePipe,
19 | TimeUnitPipe,
20 | ToAsyncPipe,
21 | FilterPipe,
22 | DicPipe,
23 | PathValuePipe
24 | ];
25 | @NgModule({
26 | declarations: [PIPE],
27 | imports: [CommonModule],
28 | exports: [PIPE]
29 | })
30 | export class NzxPipeModule {}
31 |
--------------------------------------------------------------------------------
/lib/pipe/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './defaultify.pipe';
2 | export * from './filter.pipe';
3 | export * from './trust-resource.pipe';
4 | export * from './math.pipe';
5 | export * from './time-unit.pipe';
6 | export * from './to-async.pipe';
7 | export * from './dic.pipe';
8 | export * from './path-value.pipe';
9 | export * from './pipe.module';
10 |
--------------------------------------------------------------------------------
/lib/pipe/time-unit.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 |
3 | @Pipe({
4 | name: 'timeUnit',
5 | pure: true
6 | })
7 | export class TimeUnitPipe implements PipeTransform {
8 | transform(value: number | undefined | null, unit: 's' | 'ms'): string | null {
9 | if (value == null) {
10 | return null;
11 | }
12 |
13 | const second = unit === 's' ? value : Math.floor(value / 1000);
14 | const days = Math.floor(second / 86400);
15 | const hours = Math.floor((second % 86400) / 3600);
16 | const minutes = Math.floor(((second % 86400) % 3600) / 60);
17 | const seconds = Math.floor(((second % 86400) % 3600) % 60);
18 |
19 | const units = ['天', '小时', '分', '秒'];
20 | const format = [days, hours, minutes, seconds].reduce((str, v, i) => (v ? str + v + units[i] : str), '');
21 | return format || '0秒';
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/pipe/to-async.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { from, map, Observable, of } from 'rxjs';
3 | import { FetcherService, FetchOptions } from '@xmagic/nzx-antd/service';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
6 |
7 | /**
8 | * 把请求信息转换为异步对象
9 | */
10 | @Pipe({
11 | name: 'toAsync',
12 | pure: true
13 | })
14 | export class ToAsyncPipe implements PipeTransform {
15 | constructor(private fetcher: FetcherService) {}
16 |
17 | /**
18 | * 转换为Observable
19 | * @param value 可以是url或者Observable, Promise
20 | * @param option 配置项
21 | */
22 | transform(
23 | value: string | Observable | Promise | T,
24 | option?: AsyncOption
25 | ): Observable | null {
26 | if (value == null) {
27 | return of(option?.defaultValue as U);
28 | }
29 |
30 | const opt = option || ({} as AsyncOption);
31 | const mapFn = NzxUtils.isFunction(opt.map) ? opt.map : (data: T) => data as unknown as U;
32 | if (typeof value === 'string') {
33 | return this.fetcher.fetch({ ...opt, url: value }).pipe(
34 | map(v => NzxUtils.defaultIfy(v, option?.defaultValue)),
35 | map(mapFn)
36 | );
37 | }
38 |
39 | if (NzxUtils.isPromise(value) || NzxUtils.isObservable(value)) {
40 | return from(value).pipe(
41 | map(v => NzxUtils.defaultIfy(v, option?.defaultValue)),
42 | map(mapFn)
43 | );
44 | }
45 |
46 | return of(value as T).pipe(map(mapFn));
47 | }
48 | }
49 |
50 | /**
51 | * 异步请求信息
52 | */
53 | export type AsyncOption = Omit & {
54 | /**
55 | * 映射数据
56 | * @param data
57 | * @param index
58 | */
59 | map?: (data: NzSafeAny) => NzSafeAny;
60 | /**
61 | * 默认值
62 | */
63 | defaultValue?: NzSafeAny;
64 | };
65 |
--------------------------------------------------------------------------------
/lib/pipe/trust-resource.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle } from '@angular/platform-browser';
3 |
4 | /**
5 | * 非安全加载URL,比如加载iframe url
6 | */
7 | @Pipe({
8 | name: 'trustUrl',
9 | pure: true
10 | })
11 | export class TrustUrlPipe implements PipeTransform {
12 | constructor(private sanitizer: DomSanitizer) {}
13 | transform(url: string): SafeResourceUrl {
14 | return this.sanitizer.bypassSecurityTrustResourceUrl(url);
15 | }
16 | }
17 |
18 | /**
19 | * 非安全加载HTML
20 | */
21 | @Pipe({
22 | name: 'trustHtml',
23 | pure: true
24 | })
25 | export class TrustHtmlPipe implements PipeTransform {
26 | constructor(private sanitizer: DomSanitizer) {}
27 | transform(html: string, enabled = true): SafeHtml {
28 | return enabled ? this.sanitizer.bypassSecurityTrustHtml(html) : html;
29 | }
30 | }
31 |
32 | /**
33 | * 非安全调用Script
34 | */
35 | @Pipe({
36 | name: 'trustScript',
37 | pure: true
38 | })
39 | export class TrustScriptPipe implements PipeTransform {
40 | constructor(private sanitizer: DomSanitizer) {}
41 | transform(script: string, enabled = true): SafeScript {
42 | return enabled ? this.sanitizer.bypassSecurityTrustScript(script) : script;
43 | }
44 | }
45 |
46 | /**
47 | * 非安全调用Style
48 | */
49 | @Pipe({
50 | name: 'trustStyle',
51 | pure: true
52 | })
53 | export class TrustStylePipe implements PipeTransform {
54 | constructor(private sanitizer: DomSanitizer) {}
55 | transform(style: string, enabled = true): SafeStyle {
56 | return enabled ? this.sanitizer.bypassSecurityTrustStyle(style) : style;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of nzx-antd
3 | */
4 |
5 | // export default void 0;
6 | export * from './nzx-antd.service';
7 | // export * from './nzx-antd.module';
8 | //
9 | // export * from './lib/between/public_api';
10 | // export * from './lib/between-input/public_api';
11 | // export * from './lib/checkbox/public_api';
12 | // export * from './lib/switch/public_api';
13 | // export * from './lib/table/public_api';
14 | // export * from './lib/upload/public_api';
15 | // export * from './lib/between-datetime/public_api';
16 | // export * from './lib/between-time/public_api';
17 | // export * from './lib/directive/public_api';
18 | // export * from './lib/modal/public_api';
19 | // export * from './lib/repeat/public_api';
20 | // export * from './lib/layout-page/public_api';
21 | //
22 | // export * from './lib/pipe/public_api';
23 | // export * from './lib/service/public_api';
24 | // export * from './lib/util/public_api';
25 | // export * from './lib/http-interceptor/public_api';
26 |
--------------------------------------------------------------------------------
/lib/repeat/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/repeat/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/repeat/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './repeat.component';
2 | export * from './repeat.module';
3 |
--------------------------------------------------------------------------------
/lib/repeat/repeat.component.html:
--------------------------------------------------------------------------------
1 | repeat works!
2 |
--------------------------------------------------------------------------------
/lib/repeat/repeat.component.less:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/m310851010/nzx-antd/6089df3a3fbe55f3c9b406b8f0b9d4a5d302b1df/lib/repeat/repeat.component.less
--------------------------------------------------------------------------------
/lib/repeat/repeat.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'nzx-repeat',
5 | templateUrl: './repeat.component.html',
6 | styleUrls: ['./repeat.component.less']
7 | })
8 | export class RepeatComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit(): void {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/repeat/repeat.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { RepeatComponent } from './repeat.component';
4 |
5 | @NgModule({
6 | declarations: [RepeatComponent],
7 | imports: [CommonModule],
8 | exports: [RepeatComponent]
9 | })
10 | export class NzxRepeatModule {}
11 |
--------------------------------------------------------------------------------
/lib/service/auth-guard.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Injector } from '@angular/core';
2 | import { ActivatedRouteSnapshot, Data, Route, Router, RouterStateSnapshot } from '@angular/router';
3 | import { Observable, of, tap } from 'rxjs';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
6 | import { NzxAntdService } from '@xmagic/nzx-antd';
7 |
8 | /**
9 | * 权限路由守卫服务, 具体数据格式,由NzxAntdService.hasAuth决定处理
10 | * @example
11 | * const routes: Routes = [
12 | * {
13 | * path: 'xxx',
14 | * canActivate: [ NzxAuthGuardService ],
15 | * data: { guard: 'user1', noAuthUrl: '/no-permisseion' }
16 | * },
17 | * {
18 | * path: 'xxx',
19 | * canActivate: [ NzxAuthGuardService ],
20 | * data: { guard: { auth: ['user1', 'user2'], noAuthUrl: '/no-permisseion'} }}
21 | * },
22 | * {
23 | * path: 'yyy',
24 | * canActivate: [ NzxAuthGuardService ],
25 | * data: { guard: ((router, injector, antdService) => of(true)) as AuthGuardType, noAuthUrl: '/no-permisseion' }
26 | * }
27 | * ];
28 | */
29 | @Injectable({
30 | providedIn: 'root'
31 | })
32 | export class NzxAuthGuardService {
33 | protected hasAuth: Required['hasAuth'] = () => of(true);
34 |
35 | constructor(private antdService: NzxAntdService, private router: Router, private injector: Injector) {
36 | if (this.antdService.hasAuth) {
37 | this.hasAuth = this.antdService.hasAuth;
38 | }
39 | }
40 |
41 | private process(data: Data): Observable {
42 | const guard: AuthGuardType = data.guard;
43 |
44 | if (NzxUtils.isFunction(guard)) {
45 | return guard(this.router, this.injector, this.antdService);
46 | }
47 |
48 | return this.hasAuth(guard.auth).pipe(
49 | tap(auth => {
50 | const url = guard.noAuthUrl || this.antdService.noAuthUrl;
51 | if (!auth && url) {
52 | this.router.navigateByUrl(url);
53 | }
54 | })
55 | );
56 | }
57 |
58 | // lazy loading
59 | canLoad(route: Route): Observable {
60 | return this.process(route.data!);
61 | }
62 |
63 | // all children route
64 | canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
65 | return this.canActivate(childRoute, state);
66 | }
67 |
68 | // route
69 | canActivate(route: ActivatedRouteSnapshot, _state: RouterStateSnapshot | null): Observable {
70 | return this.process(route.data);
71 | }
72 | }
73 |
74 | /**
75 | * 权限路由守卫 使用函数处理
76 | */
77 | export type AuthGuardFnType = (router: Router, injector: Injector, antdService: NzxAntdService) => Observable;
78 | /**
79 | * 权限路由守卫配置
80 | */
81 | export type AuthGuardType = AuthGuardFnType | T;
82 |
--------------------------------------------------------------------------------
/lib/service/download.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpResponse } from '@angular/common/http';
3 | import { FetcherService, FetchOptions } from './fetcher.service';
4 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
5 | import { HttpErrorBean } from '@xmagic/nzx-antd';
6 |
7 | @Injectable()
8 | export class NzxDownloadService {
9 | constructor(protected fetcher: FetcherService) {}
10 |
11 | /**
12 | * 下载文件
13 | * @param options 下载文件配置信息
14 | */
15 | download(options: DownloadOption) {
16 | this.fetcher.fetch>({ ...options, responseType: 'blob', observe: 'response' }).subscribe({
17 | next: resp => {
18 | const fn = options.getFileName || this.getFilename.bind(this);
19 | const filename = fn(resp, options.url);
20 | if (options.afterDownload && options.afterDownload(resp, filename) === false) {
21 | return;
22 | }
23 |
24 | this.saveAs(resp.body!, filename);
25 | if (options.downloadDone) {
26 | options.downloadDone(resp, filename);
27 | }
28 | },
29 | error: error => options.downloadError && options.downloadError(error),
30 | complete: () => options.downloadComplete && options.downloadComplete()
31 | });
32 | }
33 |
34 | /**
35 | * 文件另存为
36 | * @param body 二进制内容
37 | * @param filename 文件名
38 | */
39 | saveAs(body: Blob, filename: string) {
40 | if (typeof (window.navigator as NzSafeAny).msSaveBlob !== 'undefined') {
41 | (window.navigator as NzSafeAny).msSaveBlob(body, filename);
42 | return;
43 | }
44 |
45 | const blobURL = window.URL.createObjectURL(body as Blob);
46 | const tempLink = document.createElement('a');
47 | tempLink.style.display = 'none';
48 | tempLink.href = blobURL;
49 | tempLink.setAttribute('download', filename);
50 | if (typeof tempLink.download === 'undefined') {
51 | tempLink.setAttribute('target', '_blank');
52 | }
53 | document.body.appendChild(tempLink);
54 | tempLink.click();
55 | document.body.removeChild(tempLink);
56 | window.URL.revokeObjectURL(blobURL);
57 | }
58 |
59 | /**
60 | * 获取文件名称
61 | * @param resp
62 | * @param url
63 | * @protected
64 | */
65 | getFilename(resp: HttpResponse, url: string): string {
66 | const headers = resp.headers;
67 | const disposition = headers.get('content-disposition');
68 | const filename = headers.get('filename');
69 | if (filename) {
70 | return decodeURIComponent(filename.trim());
71 | } else if (disposition) {
72 | return disposition
73 | .split(';')
74 | .filter(v => v.indexOf('filename=') >= 0)[0]
75 | .split('=')[1]
76 | .replace(/(^")|("$)/g, '')
77 | .trim();
78 | } else {
79 | const start = url.lastIndexOf('/') + 1;
80 | const endIndex = url.lastIndexOf('?');
81 | const end = endIndex === -1 ? url.length : endIndex;
82 | return url.substring(start, end);
83 | }
84 | }
85 | }
86 |
87 | /**
88 | * 下载文件配置信息
89 | */
90 | export type DownloadOption = Omit & {
91 | /**
92 | * 请求完成后的回调
93 | * @param resp
94 | * @param filename
95 | */
96 | afterDownload?: (resp: HttpResponse, filename: string) => boolean | void;
97 |
98 | /**
99 | * 下载并保存完成的回调
100 | * @param resp
101 | * @param filename
102 | */
103 | downloadDone?: (resp: HttpResponse, filename: string) => void;
104 | /**
105 | * 下载发生错误回调
106 | * @param error
107 | */
108 | downloadError?: (error: HttpErrorBean) => void;
109 | /**
110 | * 下载结束回调, 不管成功还是失败
111 | */
112 | downloadComplete?: () => void;
113 |
114 | /**
115 | * 获取文件名
116 | * @param resp 响应对象
117 | * @param url 请求的url
118 | */
119 | getFileName?: (resp: HttpResponse, url: string) => string;
120 | };
121 |
--------------------------------------------------------------------------------
/lib/service/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/service/loading.service.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 全局loading
3 | */
4 | import { Injectable } from '@angular/core';
5 |
6 | @Injectable({
7 | providedIn: 'root'
8 | })
9 | export class NzxLoadingService {
10 | readonly loadingId = '__MESSAGE_LOADING__';
11 |
12 | /**
13 | * 显示loading
14 | * @param type loading类型
15 | * @param message 消息
16 | */
17 | show(type: 'message' | 'spin' = 'message', message: string = '加载中...') {
18 | this.showx(this.loadingId, type, () => {
19 | if (type === 'spin') {
20 | return `
21 |
22 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
${message}
33 |
`;
34 | }
35 |
36 | return `
37 |
38 |
39 |
40 |
41 |
42 |
47 |
48 |
${message}
49 |
50 |
51 |
`;
52 | });
53 | }
54 |
55 | private showx(id: string, type: 'message' | 'spin', html: () => string) {
56 | const loading = document.getElementById(id);
57 | if (loading) {
58 | if (loading.getAttribute('type') !== type) {
59 | loading.setAttribute('type', type);
60 | loading.innerHTML = html();
61 | }
62 | loading.style.display = 'block';
63 | return;
64 | }
65 | const div = document.createElement('div');
66 | div.setAttribute('type', type);
67 | div.setAttribute('id', id);
68 | div.innerHTML = html();
69 | document.body.append(div);
70 | }
71 |
72 | /**
73 | * 显示或隐藏loading
74 | * @param show 是否显示
75 | */
76 | loading(show: boolean = true): void {
77 | show ? this.show() : this.hide();
78 | }
79 |
80 | /**
81 | * 隐藏loading
82 | */
83 | hide() {
84 | const loading = document.getElementById(this.loadingId);
85 | if (loading) {
86 | loading.style.display = 'none';
87 | }
88 | }
89 | }
90 |
91 | export const loadingService = new NzxLoadingService();
92 |
--------------------------------------------------------------------------------
/lib/service/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/service/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './loading.service';
2 | export * from './download.service';
3 | export * from './fetcher.service';
4 | export * from './storage.service';
5 | export * from './auth-guard.service';
6 | export * from './dic.service';
7 | export * from './service.module';
8 |
--------------------------------------------------------------------------------
/lib/service/service.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { FetcherService } from './fetcher.service';
4 | import { HttpClientModule } from '@angular/common/http';
5 | import { NzxDownloadService } from './download.service';
6 |
7 | @NgModule({
8 | declarations: [],
9 | imports: [CommonModule, HttpClientModule],
10 | providers: [FetcherService, NzxDownloadService]
11 | })
12 | export class NzxServiceModule {}
13 |
--------------------------------------------------------------------------------
/lib/service/storage.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Optional } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 |
4 | @Injectable({
5 | providedIn: 'root'
6 | })
7 | export class NzxStorageService {
8 | /**
9 | * 获取长度
10 | */
11 | get length() {
12 | return this.storage.length;
13 | }
14 |
15 | constructor(@Optional() public storage: Storage) {
16 | if (!storage) {
17 | this.storage = localStorage;
18 | }
19 | }
20 |
21 | /**
22 | * 清除所有数据
23 | */
24 | clear() {
25 | this.storage.clear();
26 | }
27 |
28 | /**
29 | * 获取值
30 | * @param key key
31 | */
32 | getItem(key: string): T | null {
33 | const value = this.storage.getItem(key);
34 | return value == null ? null : (JSON.parse(value) as T);
35 | }
36 |
37 | /**
38 | * 获取key
39 | * @param index 索引
40 | */
41 | key(index: number): string | null {
42 | return this.storage.key(index);
43 | }
44 |
45 | /**
46 | * 移除值
47 | * @param key key
48 | */
49 | removeItem(key: string): void {
50 | this.storage.removeItem(key);
51 | }
52 |
53 | /**
54 | * 设置值
55 | * @param key
56 | * @param value
57 | */
58 | setItem(key: string, value: T): void {
59 | this.storage.setItem(key, JSON.stringify(value));
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/switch/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/switch/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/switch/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './switch.component';
2 | export * from './switch.module';
3 |
--------------------------------------------------------------------------------
/lib/switch/switch.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AfterViewInit,
3 | ChangeDetectionStrategy,
4 | ChangeDetectorRef,
5 | Component,
6 | forwardRef,
7 | Input,
8 | TemplateRef,
9 | ViewChild
10 | } from '@angular/core';
11 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
12 | import { NzSafeAny, NzSizeDSType } from 'ng-zorro-antd/core/types';
13 | import { BaseControl } from '@xmagic/nzx-antd/util';
14 | import { NzSwitchComponent } from 'ng-zorro-antd/switch';
15 |
16 | @Component({
17 | selector: 'nzx-switch',
18 | template: `
19 |
30 | `,
31 | changeDetection: ChangeDetectionStrategy.OnPush,
32 | providers: [
33 | {
34 | provide: NG_VALUE_ACCESSOR,
35 | useExisting: forwardRef(() => NzxSwitchComponent),
36 | multi: true
37 | }
38 | ]
39 | })
40 | export class NzxSwitchComponent extends BaseControl implements ControlValueAccessor, AfterViewInit {
41 | @ViewChild('nzSwitch', { static: true }) nzSwitch!: NzSwitchComponent;
42 | nzxValue!: boolean;
43 | /**
44 | * 选中时的值
45 | */
46 | @Input() nzxCheckedValue: NzSafeAny = true;
47 | /**
48 | * 非选中时的值
49 | */
50 | @Input() nzxUnCheckedValue: NzSafeAny = false;
51 | /**
52 | * disable 状态
53 | */
54 | @Input() nzDisabled?: boolean;
55 | /**
56 | * 加载中的开关
57 | */
58 | @Input() nzLoading?: boolean;
59 | /**
60 | * 是否完全由用户控制状态, Switch 的状态完全由用户接管,不再自动根据点击事件改变数据。
61 | */
62 | @Input() nzControl = false;
63 | /**
64 | * 选中时的内容
65 | */
66 | @Input() nzCheckedChildren?: string | TemplateRef;
67 | /**
68 | * 非选中时的内容
69 | */
70 | @Input() nzUnCheckedChildren?: string | TemplateRef;
71 | /**
72 | * 开关大小
73 | */
74 | @Input() nzSize?: NzSizeDSType;
75 |
76 | constructor(private cdr: ChangeDetectorRef) {
77 | super();
78 | }
79 |
80 | ngAfterViewInit(): void {
81 | const touched = this.nzSwitch.onTouched;
82 | this.nzSwitch.onTouched = () => {
83 | touched.call(this.nzSwitch);
84 | this.onTouched();
85 | };
86 | }
87 |
88 | ngModelChange(val: boolean) {
89 | this.onChange(val ? this.nzxCheckedValue : this.nzxUnCheckedValue);
90 | }
91 |
92 | writeValue(value: NzSafeAny | null): void {
93 | this.nzxValue = value === this.nzxCheckedValue;
94 | this.cdr.markForCheck();
95 | }
96 |
97 | override setDisabledState(isDisabled: boolean): void {
98 | this.nzDisabled = isDisabled;
99 | this.cdr.markForCheck();
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/switch/switch.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxSwitchComponent } from './switch.component';
4 | import { NzSwitchModule } from 'ng-zorro-antd/switch';
5 | import { FormsModule } from '@angular/forms';
6 |
7 | @NgModule({
8 | declarations: [NzxSwitchComponent],
9 | imports: [CommonModule, FormsModule, NzSwitchModule],
10 | exports: [NzxSwitchComponent]
11 | })
12 | export class NzxSwitchModule {}
13 |
--------------------------------------------------------------------------------
/lib/table/const.ts:
--------------------------------------------------------------------------------
1 | import { FetchSetting } from './table.type';
2 |
3 | export const FETCH_SETTING: FetchSetting = {
4 | pageIndexField: 'pageIndex',
5 | pageSizeField: 'pageSize',
6 | listField: 'list',
7 | totalField: 'total',
8 | method: 'post',
9 | responseType: 'json'
10 | };
11 |
--------------------------------------------------------------------------------
/lib/table/header/column-setting/column-setting.component.html:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
28 |
29 |
30 |
31 |
32 |
33 |
39 |
40 | -
49 |
50 |
51 |
59 |
60 |
61 |
62 |
72 |
73 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/lib/table/header/column-setting/column-setting.component.less:
--------------------------------------------------------------------------------
1 | @import '../../../base.less';
2 | @nzx-column-setting-prefix-cls: ~'@{nzx-prefix}-column-setting';
3 |
4 | .@{nzx-column-setting-prefix-cls} {
5 | &__popover-title {
6 | display: flex;
7 | align-items: center;
8 | }
9 |
10 | &__flex {
11 | display: flex;
12 | align-items: center;
13 | }
14 |
15 | &__cloumn-box {
16 | .ant-popover-inner-content {
17 | padding-right: 0;
18 | padding-left: 0;
19 | }
20 |
21 | .cdk-drop-list-dragging .cdk-drag {
22 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
23 | }
24 |
25 | .cdk-drag-placeholder {
26 | opacity: 0;
27 | }
28 | }
29 |
30 | &__drag-preview {
31 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
32 | }
33 |
34 | &__column-list {
35 | padding: 0;
36 | }
37 |
38 | &__check-item {
39 | display: flex;
40 | align-items: center;
41 | padding: 6px 16px 6px 0;
42 | justify-content: space-between;
43 |
44 | .drag-box {
45 | display: flex;
46 | align-items: center;
47 | flex: 1;
48 | }
49 |
50 | .ant-checkbox-wrapper {
51 | flex: 1;
52 | &:hover {
53 | color: @primary-color;
54 | }
55 | }
56 | }
57 |
58 | &__fixed-left,
59 | &__fixed-right {
60 | color: #666;
61 | cursor: pointer;
62 | font-size: 16px;
63 | transform: rotate(-90deg);
64 |
65 | &.active,
66 | &:hover {
67 | color: @primary-color;
68 | }
69 |
70 | &.disabled {
71 | color: @disabled-color;
72 | cursor: not-allowed;
73 | }
74 | }
75 |
76 | &__drag-icon {
77 | display: inline-block;
78 | width: 16px;
79 | height: 16px;
80 | margin: 0 5px;
81 | font-size: 16px;
82 | cursor: move;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/table/header/column-setting/column-setting.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeDetectionStrategy,
3 | Component,
4 | ElementRef,
5 | EventEmitter,
6 | Input,
7 | OnInit,
8 | Output,
9 | Renderer2,
10 | ViewEncapsulation
11 | } from '@angular/core';
12 | import { CdkDragDrop, CdkDragRelease, CdkDragStart, moveItemInArray } from '@angular/cdk/drag-drop';
13 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
14 | import { NzxColumn } from '../../table.type';
15 |
16 | /**
17 | * 列设置
18 | * 注意: 只在表头不分组的情况下有效
19 | */
20 | @Component({
21 | selector: 'nzx-column-setting',
22 | templateUrl: './column-setting.component.html',
23 | preserveWhitespaces: false,
24 | encapsulation: ViewEncapsulation.None,
25 | changeDetection: ChangeDetectionStrategy.OnPush
26 | })
27 | export class NzxColumnSettingComponent implements OnInit /*, OnChanges*/ {
28 | _nzxColumns: NzxColumn[] = [];
29 | _columnNameChecked!: boolean | null;
30 | _indeterminate!: boolean | null;
31 |
32 | /**
33 | * 拖拽预览样式
34 | */
35 | @Input() dragPreviewClass = 'nzx-column-setting__drag-preview';
36 | /**
37 | * 显示列名
38 | */
39 | @Input() columnNameVisible: boolean | null = true;
40 |
41 | @Input() set nzxColumns(value: NzxColumn[]) {
42 | if (value) {
43 | this._nzxColumns = value;
44 | this.refreshNameCheckedStatus();
45 | }
46 | }
47 | get nzxColumns() {
48 | return this._nzxColumns;
49 | }
50 |
51 | /**
52 | * 当个列选中事件
53 | */
54 | @Output() columnCheckedChange = new EventEmitter>();
55 | /**
56 | * 排序列触发
57 | */
58 | @Output() sortedColumn = new EventEmitter, NzSafeAny>>();
59 | /**
60 | * 列名选择Change
61 | */
62 | @Output() columnNameCheckedChange = new EventEmitter();
63 |
64 | /**
65 | * 固定列
66 | */
67 | @Output() fixedClick = new EventEmitter>();
68 |
69 | constructor(protected renderer: Renderer2) {}
70 |
71 | ngOnInit(): void {}
72 |
73 | columnVisible(item: NzxColumn, checked: boolean) {
74 | this.refreshNameCheckedStatus();
75 | this.columnCheckedChange.emit(item);
76 | }
77 |
78 | /**
79 | * 固定列
80 | * @param column
81 | * @param fixed
82 | */
83 | fixedColumn(column: NzxColumn, fixed?: 'left' | 'right') {
84 | if (column.fixed === fixed) {
85 | return;
86 | }
87 | column.fixed = fixed;
88 | this.fixedClick.emit(column);
89 | }
90 |
91 | /**
92 | * 拖动列排序
93 | * @param event
94 | * @param list 排序数组
95 | */
96 | dropColumn(event: CdkDragDrop, NzSafeAny>, list: NzxColumn[]) {
97 | moveItemInArray(list, event.previousIndex, event.currentIndex);
98 | this.sortedColumn.emit(event);
99 | }
100 |
101 | /**
102 | * 开始拖动
103 | * @param event
104 | */
105 | cdkDragStarted(event: CdkDragStart) {
106 | const preview = new ElementRef(document.querySelector('.cdk-drag.cdk-drag-preview')!);
107 | this.renderer.addClass(preview.nativeElement, this.dragPreviewClass);
108 | }
109 |
110 | /**
111 | * 结束拖动
112 | * @param event
113 | */
114 | cdkDragReleased(event: CdkDragRelease) {
115 | const preview = new ElementRef(document.querySelector('.cdk-drag.cdk-drag-preview')!);
116 | this.renderer.removeClass(preview.nativeElement, this.dragPreviewClass);
117 | }
118 |
119 | /**
120 | * 展示列复选框 checked
121 | * @param checked
122 | */
123 | columnNameChange(checked: boolean) {
124 | if (this._nzxColumns && this._nzxColumns.length) {
125 | this._columnNameChecked = checked;
126 | this._indeterminate = false;
127 | this._nzxColumns.filter(v => v.settingVisible != false && v.settingDisabled !== true).forEach(v => (v.visible = checked));
128 | this.columnNameCheckedChange.emit(checked);
129 | }
130 | }
131 |
132 | /**
133 | * 更新展示列状态
134 | */
135 | refreshNameCheckedStatus(): void {
136 | if (this._nzxColumns && this._nzxColumns.length) {
137 | const list = this._nzxColumns.filter(v => v.settingVisible != false && v.settingDisabled !== true);
138 | this._columnNameChecked = list.every(item => item.visible);
139 | this._indeterminate = !this._columnNameChecked && list.some(item => item.visible);
140 | } else {
141 | this._columnNameChecked = false;
142 | this._indeterminate = false;
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/lib/table/header/table-header/table-header.component.html:
--------------------------------------------------------------------------------
1 |
38 |
39 |
40 |
41 | -
47 | {{ item.sizeName }}
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lib/table/header/table-header/table-header.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeDetectionStrategy,
3 | Component,
4 | EventEmitter,
5 | Input,
6 | OnChanges,
7 | OnInit,
8 | Output,
9 | SimpleChange,
10 | SimpleChanges,
11 | ViewEncapsulation
12 | } from '@angular/core';
13 | import { NzTableSize } from 'ng-zorro-antd/table';
14 | import { NzxTableSize } from '../../table.type';
15 |
16 | @Component({
17 | selector: 'nzx-table-header',
18 | templateUrl: './table-header.component.html',
19 | styles: [':host{display: block}'],
20 | preserveWhitespaces: false,
21 | encapsulation: ViewEncapsulation.None,
22 | changeDetection: ChangeDetectionStrategy.OnPush
23 | })
24 | export class NzxTableHeaderComponent implements OnInit, OnChanges {
25 | @Input() tableSize: NzxTableSize = 'small';
26 | /**
27 | * 是否显示操作按钮小图标
28 | */
29 | @Input() actionVisible?: boolean;
30 | @Input() refreshVisible?: boolean;
31 | @Input() resizeVisible?: boolean;
32 |
33 | @Output() tableSizeChange = new EventEmitter();
34 | @Output() refreshClick = new EventEmitter();
35 |
36 | readonly tableSizeOptions = [
37 | { sizeName: '大号', selected: false, value: 'default' },
38 | { sizeName: '中等', selected: false, value: 'middle' },
39 | { sizeName: '紧凑', selected: true, value: 'small' },
40 | { sizeName: '迷你', selected: true, value: 'mini' }
41 | ];
42 |
43 | constructor() {}
44 |
45 | ngOnInit(): void {
46 | this.tableSizeOptions.forEach(v => (v.selected = v.value === this.tableSize));
47 | }
48 |
49 | ngOnChanges(changes: { [K in keyof this]?: SimpleChange } & SimpleChanges): void {
50 | if (changes.tableSize && !changes.tableSize.isFirstChange()) {
51 | this.ngOnInit();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/table/index.less:
--------------------------------------------------------------------------------
1 | @import 'table.component.less';
2 | @import 'header/column-setting/column-setting.component.less';
3 |
--------------------------------------------------------------------------------
/lib/table/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/table/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/table/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './table.component';
2 | export * from './table.type';
3 | export * from './header/table-header/table-header.component';
4 | export * from './header/column-setting/column-setting.component';
5 | export * from './table-widget.service';
6 | export * from './table.module';
7 |
--------------------------------------------------------------------------------
/lib/table/table-widget.directive.ts:
--------------------------------------------------------------------------------
1 | import { ComponentRef, Directive, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core';
2 | import { IndexAttr, NzxColumn, NzxWidget } from './table.type';
3 | import { TableWidgetService } from './table-widget.service';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 | import { of } from 'rxjs';
6 |
7 | @Directive({
8 | selector: '[table-widget]'
9 | })
10 | export class TableWidgetDirective implements OnInit {
11 | @Input() row: T = {} as T;
12 | @Input() indexAttr!: IndexAttr;
13 | @Input() colIndex!: IndexAttr;
14 | @Input() column!: NzxColumn;
15 | @Input() nzData: T[] = [];
16 | @Input() nzPageData: T[] = [];
17 |
18 | @Input() widget!: NzxWidget;
19 |
20 | constructor(
21 | private widgetService: TableWidgetService,
22 | private viewContainerRef: ViewContainerRef,
23 | private renderer: Renderer2
24 | ) {}
25 |
26 | ngOnInit(): void {
27 | this.viewContainerRef.clear();
28 | if (!this.widget) {
29 | return;
30 | }
31 | const componentType = this.widgetService.get(this.widget.type);
32 | if (!componentType) {
33 | console.warn(`组件类型“${this.widget.type}”未注册`);
34 | return;
35 | }
36 |
37 | const params = {
38 | row: this.row,
39 | nzData: this.nzData,
40 | nzPageData: this.nzPageData,
41 | column: this.column,
42 | indexAttr: this.indexAttr,
43 | colIndex: this.colIndex
44 | };
45 |
46 | const componentRef = this.viewContainerRef.createComponent(componentType);
47 | const callbackParams = {
48 | instance: componentRef.instance,
49 | componentRef,
50 | ...params
51 | };
52 |
53 | const result = NzxUtils.isFunction(this.widget.props)
54 | ? resolveType(this.widget.props(this.row, params))
55 | : resolveType(this.widget.props);
56 | result.subscribe((props: Record) => {
57 | console.log(props);
58 | const values = Object.assign(params, { props }, props);
59 | Object.assign(componentRef.instance, values);
60 |
61 | for (const key in values) {
62 | // eslint-disable-next-line
63 | // @ts-ignore
64 | const tNode = componentRef._tNode;
65 | // 检查属性是否有属于inputs, _tNode是私有属性,不应该直接访问,所以做个检查,对实际运行不影响
66 | if (tNode && tNode.inputs && tNode.inputs[key]) {
67 | componentRef.setInput(key, values[key]);
68 | } else {
69 | componentRef.instance[key] = values[key];
70 | }
71 | }
72 | this.widget.onInit?.(callbackParams);
73 | });
74 |
75 | this.mergeElementProperty(componentRef, params);
76 | if (this.widget.onDestroy) {
77 | componentRef.onDestroy(() =>
78 | this.widget.onDestroy!({
79 | ...callbackParams
80 | })
81 | );
82 | }
83 | }
84 |
85 | private mergeElementProperty(
86 | componentRef: ComponentRef,
87 | params: {
88 | indexAttr: IndexAttr;
89 | column: NzxColumn;
90 | colIndex: IndexAttr;
91 | nzData: T[];
92 | row: T;
93 | nzPageData: T[];
94 | }
95 | ) {
96 | const element = componentRef.location.nativeElement;
97 | if (this.widget.style) {
98 | Object.assign(element.style, this.widget.style);
99 | }
100 | if (this.widget.className) {
101 | element.className = this.widget.className;
102 | }
103 | if (this.widget.click) {
104 | this.renderer.listen(element, 'click', (event: MouseEvent) => this.widget.click!(this.row, params, event));
105 | }
106 | }
107 | }
108 |
109 | function resolveType(type: T) {
110 | if (!type) {
111 | return of({});
112 | }
113 | if (NzxUtils.isObservable(type) || NzxUtils.isPromise(type)) {
114 | return type;
115 | }
116 | return of(type);
117 | }
118 |
--------------------------------------------------------------------------------
/lib/table/table-widget.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, InjectionToken, Type } from '@angular/core';
2 |
3 | export const TABLE_WIDGET = new InjectionToken('TABLE_WIDGET');
4 |
5 | export interface TableWidget {
6 | name: string;
7 | component: Type;
8 | }
9 |
10 | export type TableWidgetMap = Record>;
11 |
12 | @Injectable({
13 | providedIn: 'root'
14 | })
15 | export class TableWidgetService {
16 | private widgetMap: TableWidgetMap = {};
17 |
18 | get widgets(): TableWidgetMap {
19 | return this.widgetMap;
20 | }
21 |
22 | register(widgets?: TableWidget[]): void {
23 | if (!widgets?.length) {
24 | return;
25 | }
26 |
27 | for (const widget of widgets) {
28 | this.widgetMap[widget.name] = widget.component;
29 | }
30 | }
31 |
32 | has(type: string): boolean {
33 | return Object.hasOwn(this.widgetMap, type);
34 | }
35 |
36 | get(type: string): Type {
37 | return this.widgetMap[type];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/table/table-widget/table-button/table-button.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 | import { IndexAttr, NzxColumn } from '../../table.type';
3 |
4 | @Component({
5 | selector: 'nzx-table-button',
6 | template: `
7 |
27 | `
28 | })
29 | export class TableButtonComponent {
30 | @Input() props: Record = {};
31 | @Input() row: T = {} as T;
32 | @Input() indexAttr!: IndexAttr;
33 | @Input() colIndex!: IndexAttr;
34 | @Input() column!: NzxColumn;
35 | @Input() nzData: T[] = [];
36 | @Input() nzPageData: T[] = [];
37 | }
38 |
--------------------------------------------------------------------------------
/lib/table/table-widget/table-input/table-input.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 | import { IndexAttr, NzxColumn } from '../../table.type';
3 |
4 | @Component({
5 | selector: 'nzx-table-input',
6 | template: `
7 |
24 | `
25 | })
26 | export class TableInputComponent {
27 | @Input() props: Record = {};
28 | @Input() row: T = {} as T;
29 | @Input() indexAttr!: IndexAttr;
30 | @Input() colIndex!: IndexAttr;
31 | @Input() column!: NzxColumn;
32 | @Input() nzData: T[] = [];
33 | @Input() nzPageData: T[] = [];
34 |
35 | get params() {
36 | return {
37 | row: this.row,
38 | nzData: this.nzData,
39 | nzPageData: this.nzPageData,
40 | colIndex: this.colIndex,
41 | column: this.column,
42 | indexAttr: this.indexAttr
43 | };
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/table/table-widget/table-link/table-link.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 | import { IndexAttr, NzxColumn, NzxColumnButton } from '../../table.type';
3 |
4 | @Component({
5 | selector: 'nzx-table-link',
6 | template: `
7 |
14 | {{ props.text }}
15 |
16 | `
17 | })
18 | export class TableLinkComponent {
19 | @Input() props!: NzxColumnButton;
20 | @Input() nzData: T[] = [];
21 | @Input() nzPageData: T[] = [];
22 | @Input() row: T = {} as T;
23 | @Input() indexAttr!: IndexAttr;
24 | @Input() colIndex!: IndexAttr;
25 | @Input() column!: NzxColumn;
26 |
27 | get params() {
28 | return {
29 | row: this.row,
30 | nzData: this.nzData,
31 | nzPageData: this.nzPageData,
32 | colIndex: this.colIndex,
33 | column: this.column,
34 | indexAttr: this.indexAttr
35 | };
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/table/table-widget/table-tag/table-tag.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input } from '@angular/core';
2 | import { IndexAttr, NzxColumn } from '../../table.type';
3 |
4 | @Component({
5 | selector: 'nzx-table-tag',
6 | template: `
7 |
18 | {{ props.text }}
19 |
20 | `
21 | })
22 | export class TableTagComponent {
23 | @Input() props: Record = {};
24 | @Input() row: T = {} as T;
25 | @Input() indexAttr!: IndexAttr;
26 | @Input() colIndex!: IndexAttr;
27 | @Input() column!: NzxColumn;
28 | @Input() nzData: T[] = [];
29 | @Input() nzPageData: T[] = [];
30 |
31 | get params() {
32 | return {
33 | row: this.row,
34 | nzData: this.nzData,
35 | nzPageData: this.nzPageData,
36 | colIndex: this.colIndex,
37 | column: this.column,
38 | indexAttr: this.indexAttr
39 | };
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/table/table-widget/table-widget.module.ts:
--------------------------------------------------------------------------------
1 | import { Inject, NgModule, Optional } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { TableInputComponent } from './table-input/table-input.component';
4 | import { FormsModule } from '@angular/forms';
5 | import { NzInputModule } from 'ng-zorro-antd/input';
6 | import { TableButtonComponent } from './table-button/table-button.component';
7 | import { NzButtonModule } from 'ng-zorro-antd/button';
8 | import { NzIconModule } from 'ng-zorro-antd/icon';
9 | import { TableLinkComponent } from './table-link/table-link.component';
10 | import { LinkHrefPipe } from '../transform/link-href.pipe';
11 | import { TableTagComponent } from './table-tag/table-tag.component';
12 | import { NzTagModule } from 'ng-zorro-antd/tag';
13 | import { NzxSwitchComponent, NzxSwitchModule } from '@xmagic/nzx-antd/switch';
14 | import { NzInputNumberComponent, NzInputNumberModule } from 'ng-zorro-antd/input-number';
15 | import { TableWidgetService, TABLE_WIDGET, TableWidget } from '../table-widget.service';
16 |
17 | export function defaultTableWidget(): TableWidget[] {
18 | return [
19 | { name: 'switch', component: NzxSwitchComponent },
20 | { name: 'input', component: TableInputComponent },
21 | { name: 'number', component: NzInputNumberComponent },
22 | { name: 'tag', component: TableTagComponent },
23 | { name: 'button', component: TableButtonComponent },
24 | { name: 'link', component: TableLinkComponent }
25 | ];
26 | }
27 |
28 | @NgModule({
29 | declarations: [TableInputComponent, TableButtonComponent, TableLinkComponent, TableTagComponent, LinkHrefPipe],
30 | imports: [
31 | CommonModule,
32 | FormsModule,
33 | NzInputModule,
34 | NzButtonModule,
35 | NzIconModule,
36 | NzTagModule,
37 | NzInputNumberModule,
38 | NzxSwitchModule
39 | ],
40 | providers: [{ provide: TABLE_WIDGET, useFactory: defaultTableWidget, multi: true }],
41 | exports: [TableInputComponent, TableButtonComponent, TableLinkComponent, TableTagComponent]
42 | })
43 | export class TableWidgetModule {
44 | constructor(
45 | public service: TableWidgetService,
46 | @Optional() @Inject(TABLE_WIDGET) widgets: TableWidget[][] = []
47 | ) {
48 | if (!widgets) {
49 | return;
50 | }
51 | widgets.forEach(c => service.register(c));
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/table/table.component.less:
--------------------------------------------------------------------------------
1 | @import '../base';
2 | @table-padding-vertical-mini: 4px;
3 | @table-padding-horizontal-mini: 4px;
4 | @table-font-size-mini: 14px;
5 | @table-striped-bgcolor: @table-row-hover-bg;
6 |
7 | .table-size(~'mini', @table-padding-vertical-mini, @table-padding-horizontal-mini, @table-font-size-mini);
8 |
9 | .@{table-prefix-cls}-mini {
10 | .@{table-prefix-cls}-thead > tr > th {
11 | background-color: @table-header-bg-sm;
12 | }
13 | .@{table-prefix-cls}-selection-column {
14 | width: 46px;
15 | min-width: 46px;
16 | }
17 | }
18 |
19 | @nzx-table-prefix-cls: ~'@{nzx-prefix}-table';
20 |
21 | .@{nzx-table-prefix-cls} {
22 | &-striped-tbody > tr:nth-of-type(even):not(.ant-table-placeholder) > td {
23 | background: @table-striped-bgcolor;
24 | }
25 |
26 | &-fit {
27 | height: 100%;
28 | position: relative;
29 | display: flex;
30 | flex-direction: column;
31 |
32 | .nzx-inner-table{
33 | width: 100%;
34 | flex: 1;
35 | display: flex;
36 |
37 | .ant-spin-nested-loading{
38 | width: 100%;
39 | }
40 | .ant-spin-container{
41 | display: flex;
42 | flex-direction: column;
43 | height: 100%;
44 |
45 | >.ant-table {
46 | width: 100%;
47 | flex: 1;
48 | position: relative;
49 |
50 | .ant-table-container{
51 | top: 0;
52 | left: 0;
53 | right: 0;
54 | bottom: 0;
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
61 | .ant-table-column-title {
62 | position: initial;
63 | }
64 | .nz-resizable-handle-right {
65 | width: 8px;
66 | right: 0;
67 | }
68 |
69 | .ant-table:not(.ant-table-bordered) .ant-table-thead > tr > th:not(:last-child) .nz-resizable-handle-right:after {
70 | content: ' ';
71 | position: absolute;
72 | width: 1px;
73 | background: #e8e8e8;
74 | right: 0;
75 | height: 18px;
76 | top: 50%;
77 | margin-top: -9px;
78 | }
79 |
80 | .ant-table.ant-table-bordered .ant-table-thead > tr > th:not(:last-child) .nz-resizable-handle-right:after {
81 | content: ' ';
82 | position: absolute;
83 | width: 1px;
84 | right: 0;
85 | height: 18px;
86 | top: 50%;
87 | margin-top: -9px;
88 | }
89 |
90 | &__header {
91 | display: flex;
92 | align-items: center;
93 | padding-bottom: 8px;
94 | }
95 | &__title {
96 | display: flex;
97 | flex: 1;
98 | align-items: center;
99 | > * {
100 | margin-right: 8px;
101 | }
102 | }
103 |
104 | &__toolbar {
105 | display: flex;
106 | align-items: center;
107 | justify-content: flex-end;
108 |
109 | > * {
110 | margin-right: 8px;
111 | }
112 | .anticon[tabindex] {
113 | cursor: pointer;
114 | font-size: 18px;
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/lib/table/table.module.ts:
--------------------------------------------------------------------------------
1 | import { Inject, ModuleWithProviders, NgModule, Optional } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzTableModule } from 'ng-zorro-antd/table';
4 | import { NzxTableComponent } from './table.component';
5 | import { NzxTableHeaderComponent } from './header/table-header/table-header.component';
6 | import { NzxColumnSettingComponent } from './header/column-setting/column-setting.component';
7 | import { NzResizableModule } from 'ng-zorro-antd/resizable';
8 | import { NzIconModule } from 'ng-zorro-antd/icon';
9 | import { NzPopoverModule } from 'ng-zorro-antd/popover';
10 | import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
11 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
12 | import { DragDropModule } from '@angular/cdk/drag-drop';
13 | import { NzDividerModule } from 'ng-zorro-antd/divider';
14 | import { NzDropDownModule } from 'ng-zorro-antd/dropdown';
15 | import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
16 | import { NzxPipeModule } from '@xmagic/nzx-antd/pipe';
17 | import { NzxServiceModule } from '@xmagic/nzx-antd/service';
18 | import { NzOutletModule } from 'ng-zorro-antd/core/outlet';
19 | import { NzButtonModule } from 'ng-zorro-antd/button';
20 | import { ColFormatPipe } from './transform/col-format.pipe';
21 | import { NzxDirectiveModule } from '@xmagic/nzx-antd/directive';
22 | import { ColSpanPipe } from './transform/col-span.pipe';
23 | import { ColButtonVisiblePipe } from './transform/col-button-visible.pipe';
24 | import { HasAuthPipe } from './transform/has-auth.pipe';
25 | import { ColButtonsPipe } from './transform/col-buttons.pipe';
26 | import { TableWidgetService, TABLE_WIDGET, TableWidget } from './table-widget.service';
27 |
28 | import { TableWidgetModule } from './table-widget/table-widget.module';
29 | import { TableWidgetDirective } from './table-widget.directive';
30 |
31 | const COMPONENT = [NzxTableComponent, NzxTableHeaderComponent, NzxColumnSettingComponent];
32 | @NgModule({
33 | declarations: [
34 | COMPONENT,
35 | ColFormatPipe,
36 | ColSpanPipe,
37 | ColButtonVisiblePipe,
38 | HasAuthPipe,
39 | TableWidgetDirective,
40 | ColButtonsPipe
41 | ],
42 | imports: [
43 | CommonModule,
44 | FormsModule,
45 | ReactiveFormsModule,
46 | NzTableModule,
47 | NzResizableModule,
48 | NzIconModule,
49 | NzPopoverModule,
50 | NzCheckboxModule,
51 | DragDropModule,
52 | NzDividerModule,
53 | NzDropDownModule,
54 | NzToolTipModule,
55 | NzxPipeModule,
56 | NzxServiceModule,
57 | NzOutletModule,
58 | NzButtonModule,
59 | NzxDirectiveModule,
60 | TableWidgetModule
61 | ],
62 | exports: [COMPONENT]
63 | })
64 | export class NzxTableModule {
65 | constructor(
66 | public service: TableWidgetService,
67 | @Optional() @Inject(TABLE_WIDGET) widgets: TableWidget[][] = []
68 | ) {
69 | if (!widgets) {
70 | return;
71 | }
72 | widgets.forEach(c => service.register(c));
73 | }
74 |
75 | static forChild(config: TableWidget[] = []): ModuleWithProviders {
76 | return {
77 | ngModule: NzxTableModule,
78 | providers: [{ provide: TABLE_WIDGET, useValue: config, multi: true }]
79 | };
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/table/transform/col-button-visible.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { CellArgType, NzxColumnButton } from '../table.type';
3 | import { NzxUtils } from '@xmagic/nzx-antd/util';
4 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
5 |
6 | @Pipe({
7 | name: 'colButtonVisible'
8 | })
9 | export class ColButtonVisiblePipe implements PipeTransform {
10 | transform(
11 | value?: NzxColumnButton['visible']
12 | ): (row: NzSafeAny, params: CellArgType) => boolean | undefined | null | void {
13 | if (NzxUtils.isFunction(value)) {
14 | return value;
15 | }
16 | return () => value !== false;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/table/transform/col-buttons.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { CellArgType } from '../table.type';
3 | import { of } from 'rxjs';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 |
6 | @Pipe({
7 | name: 'colButtons'
8 | })
9 | export class ColButtonsPipe implements PipeTransform {
10 | transform(
11 | buttons: T[] | ((row: T, params: CellArgType & { parentRow?: T }) => T[]),
12 | row: T,
13 | params: CellArgType,
14 | parentRow?: T
15 | ) {
16 | if (!buttons) {
17 | return of([]);
18 | }
19 |
20 | if (NzxUtils.isFunction(buttons)) {
21 | return resolveButton(buttons(row, { ...params, parentRow }));
22 | }
23 | return resolveButton(buttons);
24 | }
25 | }
26 |
27 | function resolveButton(buttons: T[]) {
28 | if (!buttons) {
29 | return of([]);
30 | }
31 |
32 | if (NzxUtils.isArray(buttons)) {
33 | return of(buttons);
34 | }
35 |
36 | if (NzxUtils.isObservable(buttons) || NzxUtils.isPromise(buttons)) {
37 | return buttons;
38 | }
39 | return of([]);
40 | }
41 |
--------------------------------------------------------------------------------
/lib/table/transform/col-format.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 | import { CellArgType, NzxColumn } from '../table.type';
4 | import { Observable } from 'rxjs';
5 | import { NzxUtils } from '@xmagic/nzx-antd/util';
6 |
7 | @Pipe({
8 | name: 'colFormat'
9 | })
10 | export class ColFormatPipe> implements PipeTransform {
11 | transform(row: T, col: NzxColumn, params: CellArgType): Observable | Promise {
12 | const nameData = col.name ? NzxUtils.get(row, col.name as string) : null;
13 | if (!col.format) {
14 | return Promise.resolve(nameData);
15 | }
16 | const result = col.format(nameData, row, params);
17 | if (NzxUtils.isPromise(result) || NzxUtils.isObservable(result)) {
18 | return result;
19 | }
20 | return Promise.resolve(result);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/table/transform/col-span.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { IndexAttr, NzxColumn, SpanFunc } from '../table.type';
3 |
4 | @Pipe({
5 | name: 'colSpan',
6 | pure: true
7 | })
8 | export class ColSpanPipe implements PipeTransform {
9 | transform(
10 | row: T,
11 | spanFunc: SpanFunc,
12 | nzData: T[],
13 | nzPageData: T[],
14 | column: NzxColumn,
15 | indexAttr: IndexAttr,
16 | colIndex: IndexAttr
17 | ): unknown {
18 | let rowspan: number | null | void = 1;
19 | let colspan: number | null | void = 1;
20 |
21 | if (spanFunc) {
22 | const result = spanFunc(row, {
23 | row,
24 | nzData,
25 | nzPageData,
26 | column,
27 | indexAttr,
28 | colIndex
29 | });
30 | if (Array.isArray(result)) {
31 | rowspan = result[0];
32 | colspan = result[1];
33 | } else if (result != null) {
34 | rowspan = result.rowspan;
35 | colspan = result.colspan;
36 | }
37 | }
38 |
39 | return { rowspan, colspan };
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/table/transform/has-auth.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
3 | import { NzxAntdService } from '@xmagic/nzx-antd';
4 | import { Observable, of } from 'rxjs';
5 |
6 | @Pipe({
7 | name: 'hasAuth'
8 | })
9 | export class HasAuthPipe implements PipeTransform {
10 | protected hasAuth: Required['hasAuth'] = () => of(true);
11 | constructor(public antdService: NzxAntdService) {
12 | if (this.antdService.hasAuth) {
13 | this.hasAuth = this.antdService.hasAuth;
14 | }
15 | }
16 |
17 | transform(value: NzSafeAny): Observable {
18 | return this.hasAuth(value);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/table/transform/link-href.pipe.ts:
--------------------------------------------------------------------------------
1 | import { Pipe, PipeTransform } from '@angular/core';
2 | import { CellArgType, NzxColumnButton } from '../table.type';
3 | import { NzSafeAny } from 'ng-zorro-antd/core/types';
4 | import { NzxUtils } from '@xmagic/nzx-antd/util';
5 |
6 | /**
7 | * 处理链接的href属性
8 | */
9 | @Pipe({
10 | name: 'linkHref'
11 | })
12 | export class LinkHrefPipe implements PipeTransform {
13 | transform(btn: NzxColumnButton, row: NzSafeAny, params: CellArgType): unknown {
14 | if (!btn.href) {
15 | return undefined;
16 | }
17 | if (typeof btn.href === 'string') {
18 | return btn.href;
19 | }
20 |
21 | if (NzxUtils.isFunction(btn.href)) {
22 | return btn.href(row, params);
23 | }
24 |
25 | if (row?.buttons && params.column.name) {
26 | return row.buttons[params.column.name]?.href;
27 | }
28 | return null;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/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';
4 | import 'zone.js/testing';
5 | import { getTestBed } from '@angular/core/testing';
6 | import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
7 |
8 | new Date().toLocaleString('', { dateStyle: 'medium' });
9 |
10 | // First, initialize the Angular testing environment.
11 | getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
12 | teardown: { destroyAfterEach: true }
13 | });
14 |
--------------------------------------------------------------------------------
/lib/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../out-tsc/lib",
6 | "declaration": true,
7 | "declarationMap": true,
8 | "inlineSources": true,
9 | "types": []
10 | },
11 | "exclude": [
12 | "src/test.ts",
13 | "**/*.spec.ts",
14 | "**/*.stories.ts"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/lib/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.lib.json",
4 | "compilerOptions": {
5 | "declarationMap": false
6 | },
7 | "angularCompilerOptions": {
8 | "compilationMode": "partial"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/lib/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../out-tsc/spec",
6 | "types": ["jasmine"]
7 | },
8 | "files": [
9 | "test.ts"
10 | ],
11 | "include": ["**/*.spec.ts", "**/*.d.ts"]
12 | }
13 |
--------------------------------------------------------------------------------
/lib/upload/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/upload/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/upload/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './upload.component';
2 | export * from './upload.module';
3 |
--------------------------------------------------------------------------------
/lib/upload/upload.component.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | {{nzxUploadText}}
48 | {{ nzxHint }}
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lib/upload/upload.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { CommonModule } from '@angular/common';
3 | import { NzxUploadComponent } from './upload.component';
4 | import { NzUploadModule } from 'ng-zorro-antd/upload';
5 | import { HttpClientModule } from '@angular/common/http';
6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms';
7 | import { NzButtonModule } from 'ng-zorro-antd/button';
8 | import { NzIconModule } from 'ng-zorro-antd/icon';
9 | import { NzMessageModule } from 'ng-zorro-antd/message';
10 | import { NzOutletModule } from 'ng-zorro-antd/core/outlet';
11 |
12 | const COMPONENT = [NzxUploadComponent];
13 |
14 | @NgModule({
15 | declarations: [COMPONENT],
16 | imports: [
17 | CommonModule,
18 | HttpClientModule,
19 | FormsModule,
20 | ReactiveFormsModule,
21 | NzUploadModule,
22 | NzMessageModule,
23 | NzButtonModule,
24 | NzIconModule,
25 | NzOutletModule
26 | ],
27 | exports: [COMPONENT]
28 | })
29 | export class NzxUploadModule {}
30 |
--------------------------------------------------------------------------------
/lib/util/base-control.ts:
--------------------------------------------------------------------------------
1 | export abstract class BaseControl {
2 | protected nzxDisabled?: boolean;
3 | onChange: (value: T) => void = () => null;
4 | onTouched: () => void = () => null;
5 |
6 | registerOnChange(fn: (_: T) => void): void {
7 | this.onChange = fn;
8 | }
9 |
10 | registerOnTouched(fn: () => void): void {
11 | this.onTouched = fn;
12 | }
13 |
14 | setDisabledState?(isDisabled: boolean): void {
15 | this.nzxDisabled = isDisabled;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/util/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Use of this source code is governed by an MIT-style license that can be
3 | *
4 | */
5 |
6 | export * from './public-api';
7 |
--------------------------------------------------------------------------------
/lib/util/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "lib": {
3 | "entryFile": "public-api.ts"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/lib/util/public-api.ts:
--------------------------------------------------------------------------------
1 | export * from './utils';
2 | export * from './utils-fn';
3 | export * from './form-utils';
4 | export * from './base-control';
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nzx-antd",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "watch": "ng build --watch --configuration development",
9 | "test": "ng test",
10 | "build:nzx-antd": "ng build nzx-antd && node version path=./dist/nzx-antd/version",
11 | "publish:nzx-antd": "cd dist/nzx-antd && npm publish --access public",
12 | "docs:json": "compodoc -p ./tsconfig.json -e json -d .",
13 | "storybook": "ng run storybook:storybook",
14 | "build-storybook": "ng run storybook:build-storybook"
15 | },
16 | "private": true,
17 | "dependencies": {
18 | "@angular/animations": "^17.0.2",
19 | "@angular/common": "^17.0.2",
20 | "@angular/compiler": "^17.0.2",
21 | "@angular/core": "^17.0.2",
22 | "@angular/forms": "^17.0.2",
23 | "@angular/platform-browser": "^17.0.2",
24 | "@angular/platform-browser-dynamic": "^17.0.2",
25 | "@angular/router": "^17.0.2",
26 | "rxjs": "~7.8.0",
27 | "tslib": "^2.3.0",
28 | "zone.js": "~0.14.2",
29 | "ng-zorro-antd": "^17.0.0"
30 | },
31 | "devDependencies": {
32 | "@angular-devkit/build-angular": "^17.0.0",
33 | "@angular/cli": "^17.0.0",
34 | "@angular/compiler-cli": "^17.0.2",
35 | "@babel/core": "^7.21.8",
36 | "@compodoc/compodoc": "^1.1.19",
37 | "ng-packagr": "^17.0.0",
38 | "@angular-eslint/builder": "^17.0.0",
39 | "@angular-eslint/eslint-plugin": "^17.0.0",
40 | "@angular-eslint/eslint-plugin-template": "^17.0.0",
41 | "@angular-eslint/schematics": "^17.0.0",
42 | "@angular-eslint/template-parser": "^17.0.0",
43 | "@commitlint/cli": "^17.6.3",
44 | "@commitlint/config-conventional": "^17.6.3",
45 | "@storybook/addon-actions": "^7.0.9",
46 | "@storybook/addon-essentials": "^7.0.9",
47 | "@storybook/addon-interactions": "^7.0.9",
48 | "@storybook/addon-links": "^7.0.9",
49 | "@storybook/angular": "^7.0.9",
50 | "@storybook/builder-webpack5": "^7.0.9",
51 | "@storybook/manager-webpack5": "^6.5.16",
52 | "@storybook/testing-library": "0.1.0",
53 | "@types/jasmine": "~4.3.0",
54 | "@types/node": "18.16.9",
55 | "@types/prettier": "^3.0.0",
56 | "@typescript-eslint/eslint-plugin": "5.59.2",
57 | "@typescript-eslint/eslint-plugin-tslint": "5.59.2",
58 | "@typescript-eslint/parser": "5.59.2",
59 | "eslint": "8.43.0",
60 | "eslint-config-prettier": "^8.8.0",
61 | "eslint-plugin-import": "2.27.5",
62 | "eslint-plugin-jsdoc": "46.4.2",
63 | "eslint-plugin-prefer-arrow": "1.2.3",
64 | "eslint-plugin-storybook": "^0.6.12",
65 | "jasmine-core": "~4.6.0",
66 | "karma": "~6.4.0",
67 | "karma-chrome-launcher": "~3.2.0",
68 | "karma-coverage": "~2.2.0",
69 | "karma-jasmine": "~5.1.0",
70 | "karma-jasmine-html-reporter": "~2.0.0",
71 | "prettier": "^3.0.0",
72 | "react-textarea-autosize": "8.5.2",
73 | "typescript": "~5.2.2"
74 | },
75 | "engines": {
76 | "node": ">= 16.14.0 || >= 18.10.0"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/stories/@types/index.ts:
--------------------------------------------------------------------------------
1 | declare module '*.mdx' {
2 | const mdxMeta: {
3 | parameters: {
4 | docs: {
5 | page: () => any;
6 | };
7 | };
8 | [key: string]: any;
9 | };
10 | export default mdxMeta;
11 | }
12 |
--------------------------------------------------------------------------------
/stories/Introduction.stories.mdx:
--------------------------------------------------------------------------------
1 | import { Meta } from '@storybook/addon-docs';
2 |
3 |
4 |
5 | # NzxAntd
6 |
7 | `NzxAntd`是一个`angular`组件库,基于`ng-zorro-antd`进行二次扩展,并加入开发常用功能。全部代码开源并遵循 `MIT` 协议,任何企业、组织及个人均可免费使用。
8 |
9 | [](https://npmjs.com/package/@xmagic/nzx-antd)
10 | 
11 | [](https://www.github.com/angular/angular)
12 | [](https://m310851010.github.io/nzx-antd)
13 |
14 | ## ✨特性
15 |
16 | - 扩展`HttpInterceptor`拦截器,简化通用业务处理
17 | - 封装常用组件 使之支持`FormControl`和`NgModal`
18 | - 封装表格组件, 简单易用, 功能强大
19 | - 常用工具类, 服务, 指令,管道
20 | - 集中化配置,统一配置入口
21 |
22 | ## 🖥使用环境
23 |
24 | - [Angular](https://angular.io) >= v13.0.0
25 | - [ng-zorro-antd](https://ng.ant.design) >= v13.0.0
26 |
27 | ## 📦安装
28 |
29 | ```shell
30 | npm i @xmagic/nzx-antd --save
31 | ```
32 |
33 | ## 🔨使用
34 |
35 |
36 | ## 🍏引入样式
37 |
38 | > 有两种方式引入样式, 在 `angular.json` 中 或者 `style.less`中, 任选其一
39 |
40 | - 在 `angular.json` 中引入
41 |
42 | ```json
43 | {
44 | "styles": [
45 | "node_modules/@xmagic/nzx-antd/nzx-antd.less"
46 | ]
47 | }
48 | ```
49 |
50 | - 在 `style.less` 中引入 `less` 样式文件
51 |
52 | ```css
53 | @import "~@xmagic/nzx-antd/nzx-antd.less";
54 | ```
55 |
56 | ## 🍎引入模块
57 |
58 | 1. 配置`NzxAntdService`
59 |
60 | ```ts
61 | // nzx-antd-config.service.ts
62 |
63 | import { Injectable } from '@angular/core';
64 | import { NzxAntdService } from '@xmagic/nzx-antd';
65 | import { environment } from '../environments/environment';
66 |
67 | @Injectable({
68 | providedIn: 'root'
69 | })
70 | export class NzxAntdConfigService extends NzxAntdService {
71 | override basePath = environment.basePath;
72 | override response = { data: 'data' };
73 | constructor() {
74 | super();
75 | }
76 | }
77 |
78 | ```
79 |
80 | 2. 修改`AppModule`
81 |
82 | ```ts
83 | // app.module.ts
84 |
85 | import { NgModule } from '@angular/core';
86 | import { AppComponent } from './app.component';
87 | import { NzxModalModule } from '@xmagic/nzx-antd/modal';
88 | import { NzxHttpInterceptorModule } from '@xmagic/nzx-antd/http-interceptor';
89 | import { NzxAntdService } from '@xmagic/nzx-antd';
90 | import { NzxAntdConfigService } from './nzx-antd-config.service';
91 |
92 | @NgModule({
93 | imports: [
94 | NzxModalModule,
95 | NzxHttpInterceptorModule
96 | ],
97 | providers: [
98 | { provide: NzxAntdService, useExisting: NzxAntdConfigService }
99 | ],
100 | bootstrap: [AppComponent]
101 | })
102 | export class AppComponent {}
103 | ```
104 |
105 | 3. 修改`AppComponent`
106 |
107 | ```ts
108 | //app.component.ts
109 |
110 | import { Component, OnInit } from '@angular/core';
111 | import { HttpLoadingService, LogoutService } from '@xmagic/nzx-antd/http-interceptor';
112 | import { NzMessageService } from 'ng-zorro-antd/message';
113 | import { NzxModalWrapService } from '@xmagic/nzx-antd/modal';
114 | import { loadingService } from '@xmagic/nzx-antd/service';
115 |
116 | @Component({
117 | selector: 'app-root',
118 | template: '',
119 | })
120 | export class AppComponent implements OnInit {
121 | constructor(
122 | protected loading: HttpLoadingService,
123 | protected notifyService: LogoutService,
124 | protected modalService: NzxModalWrapService,
125 | protected message: NzMessageService,
126 | ) {}
127 |
128 | ngOnInit(): void {
129 | this.loading.subscribe(status => loadingService.loading(status));
130 |
131 | this.notifyService.onLogout(error => {
132 | this.modalService.closeAll();
133 | if (error.timeout) {
134 | this.message.info(error.message || '登录超时,请重新登录');
135 | }
136 | window.top!.location.href = error?.url || '#/login';
137 | });
138 | }
139 | }
140 | ```
141 |
142 | ## 🏴授权协议
143 |
144 | [MIT](https://raw.githubusercontent.com/m310851010/nzx-antd/main/LICENSE)
145 |
146 | ## 👍支持
147 |
148 |
149 | 提示 为该项目点个免费的星⭐
150 |
151 |
--------------------------------------------------------------------------------
/stories/index.ts:
--------------------------------------------------------------------------------
1 | import { InputType } from '@storybook/csf';
2 | import { Story } from '@storybook/angular';
3 | // 控件类型
4 | // https://storybook.js.org/docs/angular/essentials/controls
5 | export const EXCLUDE_PARAMS = [
6 | 'setDisabledState',
7 | 'registerOnChange',
8 | 'registerOnTouched',
9 | 'onChange',
10 | 'onTouched',
11 | 'writeValue',
12 | 'ngModelChange'
13 | ];
14 |
15 | export const SIZE_ARG_TYPE = {
16 | control: 'inline-radio',
17 | options: ['large', 'default', 'small'],
18 | defaultValue: 'default'
19 | };
20 |
21 | export const HIDE_CONTROL = {
22 | table: { defaultValue: { summary: null } },
23 | control: false
24 | };
25 |
26 | /**
27 | * storybook 模板工程
28 | * @param props 传递的参数
29 | * @param template 模板
30 | */
31 | export function storyFactory(props?: Partial, template?: string): Story {
32 | // @ts-ignore
33 | const fn: Story = args => {
34 | return {
35 | props: args,
36 | template
37 | };
38 | };
39 | if (props) {
40 | fn.args = props;
41 | }
42 | return fn;
43 | }
44 |
45 | /**
46 | * 隐藏指定属性的control, 属性不隐藏
47 | * @param props 属性名称列表
48 | */
49 | export function hideControlArgType(...props: (keyof T)[]): Record {
50 | return props.reduce((prev, curr) => {
51 | prev[curr] = { ...HIDE_CONTROL };
52 | return prev;
53 | }, {} as Record);
54 | }
55 |
56 | /**
57 | * 隐藏属性
58 | */
59 | export const HIDE_CONTROL_COMMONS = hideControlArgType('nzxValue');
60 |
--------------------------------------------------------------------------------
/stories/styles.less:
--------------------------------------------------------------------------------
1 | @import '../lib/nzx-antd.less';
2 | @ant-btn-primary: #451;
3 |
4 | .doc-tip {
5 | display: inline-block;
6 | border-radius: 1em;
7 | font-size: 11px !important;
8 | line-height: 12px;
9 | font-weight: 700;
10 | background: #e7fdd8;
11 | color: #66bf3c;
12 | padding: 4px 12px;
13 | margin-right: 10px !important;
14 | vertical-align: top;
15 | }
16 |
17 | .doc-tip-wrapper {
18 | font-size: 13px !important;
19 | line-height: 20px;
20 | margin-top: 40px !important;
21 | margin-bottom: 40px !important;
22 | }
23 |
24 | .doc-tip-wrapper code {
25 | font-size: 12px !important;
26 | display: inline-block;
27 | }
28 |
29 | .doc-label{
30 | width: 120px;
31 | display: inline-block;
32 | text-align: right;
33 | padding-right: 10px;
34 | }
35 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "forceConsistentCasingInFileNames": true,
8 | "strict": true,
9 | "noImplicitReturns": true,
10 | "noFallthroughCasesInSwitch": true,
11 | "sourceMap": true,
12 | "declaration": false,
13 | "downlevelIteration": true,
14 | "experimentalDecorators": true,
15 | "moduleResolution": "node",
16 | "importHelpers": true,
17 | "skipLibCheck": true,
18 | "noImplicitAny": true,
19 | "strictNullChecks": true,
20 | "noImplicitOverride": true,
21 | "noImplicitThis": true,
22 | "target": "ES2022",
23 | "module": "es2020",
24 | "lib": ["ESNext", "dom"],
25 | "resolveJsonModule": true,
26 | "allowJs": true,
27 | "jsx": "react-jsx",
28 | "allowSyntheticDefaultImports": true,
29 | "paths": {
30 | "@xmagic/nzx-antd": ["lib/public-api"],
31 | "@xmagic/nzx-antd/*": ["lib/*"],
32 | "@stories": ["stories"],
33 | "@stories/*": ["stories/*"]
34 | },
35 | "typeRoots": ["./stories/@types", "./node_modules/@types"]
36 | },
37 | "angularCompilerOptions": {
38 | "enableI18nLegacyMessageIdFormat": false,
39 | "strictInjectionParameters": true,
40 | "strictInputAccessModifiers": true,
41 | "strictTemplates": false
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/version.js:
--------------------------------------------------------------------------------
1 | const exec = require('child_process').execSync;
2 | const process = require('process');
3 | const fs = require('fs');
4 | const path = require('path');
5 |
6 | function getCommand() {
7 | const [, , ...argv] = process.argv;
8 | return argv.reduce((prev, v) => {
9 | const kv = v.split('=');
10 | prev[kv[0]] = kv[1];
11 | return prev;
12 | }, {});
13 | }
14 |
15 | function getDateStr(date) {
16 | const prefixZero = v => (v < 10 ? '0' + v : v);
17 | return (
18 | date.getFullYear() +
19 | '-' +
20 | prefixZero(date.getMonth() + 1) +
21 | '-' +
22 | prefixZero(date.getDate()) +
23 | ' ' +
24 | prefixZero(date.getHours()) +
25 | ':' +
26 | prefixZero(date.getMinutes()) +
27 | ':' +
28 | prefixZero(date.getSeconds())
29 | );
30 | }
31 |
32 | const cmd = getCommand();
33 | const versionPath = path.resolve(cmd.path || './dist/version');
34 | const commitId = exec('git log -1 --format="COMMIT ID: %HDATE: %cd" --date=format:"%Y-%m-%d %H:%M:%S"\n')
35 | .toString()
36 | .replace('DATE:', '\nCOMMIT TIME:');
37 | const branch = exec('git name-rev --name-only HEAD');
38 |
39 | const dir = path.dirname(versionPath);
40 | if (!fs.existsSync(dir)) {
41 | fs.mkdirSync(dir, { recursive: true });
42 | }
43 |
44 | const buildTime = 'BUILD TIME: ' + getDateStr(new Date()) + '\n';
45 | fs.writeFileSync(versionPath, `BRANCH: ${branch}${commitId}${buildTime}`);
46 |
--------------------------------------------------------------------------------