* 渲染进度条
()
| 300 | * 渲染进度条 |
| 301 | */ |
| 302 | private render(): void { |
| 303 | const percentage = Math.round((this.current / this.total) * 100); |
| 304 | const elapsed = Date.now() - this.startTime; |
| 305 | const rate = this.current / (elapsed / 1000); |
| 306 | const eta = rate > 0 ? Math.round((this.total - this.current) / rate) : 0; |
| 307 | |
| 308 | // 创建进度条 |
| 309 | const filledWidth = Math.round((this.current / this.total) * this.options.width!); |
| 310 | const emptyWidth = this.options.width! - filledWidth; |
| 311 | |
| 312 | const filledBar = UIStyles.status.success(this.options.complete!.repeat(filledWidth)); |
| 313 | const emptyBar = UIStyles.status.muted(this.options.incomplete!.repeat(emptyWidth)); |
| 314 | const bar = `[${filledBar}${emptyBar}]`; |
| 315 | |
| 316 | // 替换格式字符串 |
| 317 | const output = this.options |
| 318 | .format!.replace('{bar}', bar) |
| 319 | .replace('{percentage}', percentage.toString()) |
| 320 | .replace('{current}', this.current.toString()) |
| 321 | .replace('{total}', this.total.toString()) |
| 322 | .replace('{eta}', this.formatTime(eta * 1000)); |
| 323 | |
| 324 | process.stdout.write(`\r${output}`); |
| 325 | |
| 326 | if (this.current >= this.total) { |
| 327 | process.stdout.write('\n'); |
| 328 | } |
| 329 | } |
| 330 | |
| 331 | /** |
| 332 | * 完成进度条 |
no test coverage detected