• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

atinc / ngx-tethys / 68ef226c-f83e-44c1-b8ed-e420a83c5d84

28 May 2025 10:31AM UTC coverage: 10.352% (-80.0%) from 90.316%
68ef226c-f83e-44c1-b8ed-e420a83c5d84

Pull #3460

circleci

pubuzhixing8
chore: xxx
Pull Request #3460: refactor(icon): migrate signal input #TINFR-1476

132 of 6823 branches covered (1.93%)

Branch coverage included in aggregate %.

10 of 14 new or added lines in 1 file covered. (71.43%)

11648 existing lines in 344 files now uncovered.

2078 of 14525 relevant lines covered (14.31%)

6.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.0
/src/empty/empty.component.ts
1
import {
2
    AfterViewInit,
3
    Component,
4
    computed,
5
    contentChild,
6
    effect,
7
    ElementRef,
8
    inject,
9
    input,
10
    NgZone,
11
    Signal,
12
    TemplateRef
13
} from '@angular/core';
14
import { useHostRenderer } from '@tethys/cdk/dom';
1✔
15
import { ThyTranslate } from 'ngx-tethys/core';
16

17
import { NgClass, NgTemplateOutlet } from '@angular/common';
18
import { DomSanitizer } from '@angular/platform-browser';
19
import { injectLocale, ThyEmptyLocale } from 'ngx-tethys/i18n';
1✔
20
import { ThyIcon } from 'ngx-tethys/icon';
21
import { SafeAny } from 'ngx-tethys/types';
22
import { coerceBooleanProperty } from 'ngx-tethys/util';
23
import { ThyEmptyConfig } from './empty.config';
24
import { PRESET_SVG } from './svgs';
25

26
const sizeClassMap = {
27
    lg: ['thy-empty-state', 'thy-empty-state--lg'],
28
    md: ['thy-empty-state'],
29
    sm: ['thy-empty-state', 'thy-empty-state--sm']
30
};
31

32
const sizeMap = {
33
    lg: {
34
        height: 168, // 空提示的高度
35
        offsetTop: 30, // 空提示图标和大小之间的空白距离,需要除去,否则会不居中
36
        defaultMarginTop: 120 // 不自动计算默认的 top 距离
37
    },
38
    md: {
39
        height: 118,
40
        offsetTop: 20,
41
        defaultMarginTop: 10
1✔
42
    },
UNCOV
43
    sm: {
×
UNCOV
44
        height: 78,
×
UNCOV
45
        offsetTop: 10,
×
UNCOV
46
        defaultMarginTop: 10
×
UNCOV
47
    }
×
UNCOV
48
};
×
UNCOV
49

×
UNCOV
50
/** https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-loading */
×
UNCOV
51
export type ThyEmptyImageLoading = 'eager' | 'lazy';
×
UNCOV
52

×
UNCOV
53
/** https://wicg.github.io/priority-hints/#idl-index */
×
UNCOV
54
export type ThyEmptyImageFetchPriority = 'high' | 'low' | 'auto';
×
UNCOV
55

×
UNCOV
56
/**
×
UNCOV
57
 * 空页面组件
×
UNCOV
58
 * @name thy-empty
×
UNCOV
59
 * @order 10
×
UNCOV
60
 */
×
UNCOV
61
@Component({
×
UNCOV
62
    selector: 'thy-empty',
×
UNCOV
63
    templateUrl: './empty.component.html',
×
UNCOV
64
    imports: [ThyIcon, NgClass, NgTemplateOutlet]
×
UNCOV
65
})
×
UNCOV
66
export class ThyEmpty implements AfterViewInit {
×
UNCOV
67
    private thyTranslate = inject(ThyTranslate);
×
68
    private thyEmptyConfig = inject(ThyEmptyConfig);
UNCOV
69
    private elementRef = inject(ElementRef);
×
UNCOV
70
    private ngZone = inject(NgZone);
×
UNCOV
71
    private sanitizer = inject(DomSanitizer);
×
72
    private locale: Signal<ThyEmptyLocale> = injectLocale('empty');
UNCOV
73

×
UNCOV
74
    /**
×
75
     * 显示文本提示信息。同时传入 thyMessage,thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
UNCOV
76
     * @default 暂无数据
×
UNCOV
77
     */
×
78
    readonly thyMessage = input<string>();
79

80
    /**
UNCOV
81
     * 已废弃。显示文本提示信息多语言 Key。同时传入 thyTranslationKey,thyEntityName,thyEntityNameTranslateKey 时优先级最高
×
UNCOV
82
     * @deprecated
×
83
     */
84
    readonly thyTranslationKey = input<string>();
85

UNCOV
86
    /**
×
87
     * 已废弃。显示文本提示信息多语言 Key 的 Values。传入 thyTranslationKey 后,传入这个才会生效
×
88
     * @deprecated
89
     */
UNCOV
90
    readonly thyTranslationValues = input<any>();
×
91

92
    /**
UNCOV
93
     * 已废弃。显示默认提示信息,替换默认提示信息的目标对象,比如:没有 {thyEntityName}。同时传入 thyEntityName,thyEntityNameTranslateKey 时优先级较高
×
UNCOV
94
     * @deprecated
×
95
     */
96
    readonly thyEntityName = input<string>();
97

UNCOV
98
    /**
×
UNCOV
99
     * 已废弃。thyEntityName 的多语言 Key。thyMessage,thyTranslationKey,thyEntityName 均未传入时才会生效
×
UNCOV
100
     * @deprecated
×
101
     */
UNCOV
102
    readonly thyEntityNameTranslateKey = input<string>();
×
UNCOV
103

×
104
    /**
UNCOV
105
     * 提示图标名
×
106
     */
UNCOV
107
    readonly thyIconName = input<string>();
×
108

×
109
    /**
UNCOV
110
     * 大小
×
111
     * @type sm | md | lg
UNCOV
112
     * @default md
×
UNCOV
113
     */
×
114
    readonly thySize = input<string>('md');
115

116
    /**
UNCOV
117
     * 距上距离
×
UNCOV
118
     */
×
119
    readonly thyMarginTop = input<number | string>();
×
120

121
    /**
UNCOV
122
     * 是否自动根据父容器计算高度,垂直居中
×
123
     * @default false
124
     */
UNCOV
125
    readonly thyTopAuto = input(false, { transform: coerceBooleanProperty });
×
126

×
127
    /**
128
     * 自动计算高度垂直居中(即 thyTopAuto 为 true)时,支持传入自定义父容器
129
     */
UNCOV
130
    readonly thyContainer = input<ElementRef>();
×
UNCOV
131

×
UNCOV
132
    /**
×
133
     * 提示图片链接
134
     */
135
    readonly thyImageUrl = input<string>();
UNCOV
136

×
UNCOV
137
    readonly thyImageLoading = input<ThyEmptyImageLoading>();
×
UNCOV
138

×
139
    readonly thyImageFetchPriority = input<ThyEmptyImageFetchPriority>();
140

141
    /**
142
     * 显示文本描述
1✔
143
     */
1✔
144
    readonly thyDescription = input<string>();
145

146
    private hostRenderer = useHostRenderer();
147

148
    /**
149
     * 除提示图片,文本外的其他信息传入模板
150
     * @type TemplateRef
151
     */
152
    readonly extraTemplateRef = contentChild<TemplateRef<SafeAny>>('extra');
153

154
    protected readonly presetSvg = computed(() => {
155
        let presetSvg = this.thyIconName() ? PRESET_SVG[this.thyIconName() as keyof typeof PRESET_SVG] : PRESET_SVG.default;
156

157
        return presetSvg ? this.sanitizer.bypassSecurityTrustHtml(presetSvg) : '';
158
    });
159

160
    protected readonly displayText = computed(() => {
161
        if (this.thyMessage()) {
1✔
162
            return this.thyMessage();
163
        } else if (this.thyTranslationKey()) {
164
            return this.thyTranslate.instant(this.thyTranslationKey(), this.thyTranslationValues());
165
        } else if (this.thyEntityName()) {
166
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
167
                target: this.thyEntityName()
168
            });
169
        } else if (this.thyEntityNameTranslateKey()) {
170
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultWithTargetTranslateKey, {
171
                target: this.thyTranslate.instant(this.thyEntityNameTranslateKey())
172
            });
173
        } else if (this.thyTranslate.instant(this.thyEmptyConfig.noResultTranslateKey) !== 'common.tips.NO_RESULT') {
174
            return this.thyTranslate.instant(this.thyEmptyConfig.noResultTranslateKey);
175
        } else {
176
            return this.locale().noDataText;
177
        }
178
    });
179

180
    constructor() {
181
        effect(() => {
182
            this.updateClass();
183
        });
184
    }
185

186
    private _calculatePosition() {
187
        const sizeOptions = sizeMap[(this.thySize() as keyof typeof sizeMap) || 'md'];
188
        let marginTop = null;
189
        if (this.thyTopAuto()) {
190
            // 选择参考父容器居中
191
            const thyContainer = this.thyContainer();
192
            const containerElement = thyContainer ? thyContainer.nativeElement : this.elementRef.nativeElement.parentElement;
193
            // containerElement.height;
194
            let emptyStateHeight = this.elementRef.nativeElement.offsetHeight;
195
            // 高度没有自动计算出来使用默认值
196
            if (emptyStateHeight <= 10) {
197
                emptyStateHeight = sizeOptions.height;
198
            }
199
            marginTop = (containerElement.offsetHeight - emptyStateHeight) / 2 - sizeOptions.offsetTop;
200
            // marginTop = (containerElement.offsetHeight - emptyStateHeight) / 2;
201
            if (marginTop < 0) {
202
                marginTop = 0; // sizeOptions.defaultMarginTop;
203
            }
204
        } else {
205
            const thyMarginTop = this.thyMarginTop();
206
            if (thyMarginTop) {
207
                marginTop = thyMarginTop;
208
            } else {
209
                marginTop = 0; // sizeOptions.defaultMarginTop;
210
            }
211
        }
212
        if (marginTop) {
213
            this.hostRenderer.setStyle('marginTop', marginTop + 'px');
214
        }
215
    }
216

217
    updateClass() {
218
        const classList = sizeClassMap[(this.thySize() as keyof typeof sizeClassMap) || 'md'];
219
        if (classList) {
220
            this.hostRenderer.updateClass(classList);
221
        }
222
    }
223

224
    ngAfterViewInit() {
225
        this.ngZone.runOutsideAngular(() => {
226
            setTimeout(() => {
227
                this._calculatePosition();
228
            }, 50);
229
        });
230
    }
231
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc