diff --git a/src/app/elements/replay/asciicast/asciicast.component.html b/src/app/elements/replay/asciicast/asciicast.component.html
index e2b49aa96..a6e6347ea 100644
--- a/src/app/elements/replay/asciicast/asciicast.component.html
+++ b/src/app/elements/replay/asciicast/asciicast.component.html
@@ -48,24 +48,26 @@
-
0">
-
- {{ "Commands" | translate }} ({{ commands.length }})
-
-
-
-
{{ item.input }}
-
{{ item.atime }}
+ @if (commands && commands.length > 0) {
+
+
+ {{ "Commands" | translate }} ({{ commands.length }})
+
+
+
+
{{ item.input }}
+
{{ item.atime }}
+
-
+ }
diff --git a/src/app/elements/replay/asciicast/asciicast.component.ts b/src/app/elements/replay/asciicast/asciicast.component.ts
index fd3ace477..2505b3fa1 100644
--- a/src/app/elements/replay/asciicast/asciicast.component.ts
+++ b/src/app/elements/replay/asciicast/asciicast.component.ts
@@ -1,9 +1,9 @@
-import { AfterViewInit, Component, HostListener, Input, OnInit } from '@angular/core';
-import { ActivatedRoute } from '@angular/router';
+import { filter } from 'rxjs';
+import { HttpService } from '@app/services';
import { Command, Replay } from '@app/model';
import { formatTime } from '@app/utils/common';
-import { HttpService } from '@app/services';
-import { filter } from 'rxjs';
+import { ActivatedRoute } from '@angular/router';
+import { AfterViewInit, Component, HostListener, Input, OnInit } from '@angular/core';
@Component({
standalone: false,
@@ -22,12 +22,13 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
rows: number;
duration: string;
position: string;
- timer: any; // 多长时间播放下一个
+ timer: any;
startTime = null;
startTimeStamp = null;
commands: Command[];
page = 0;
private AsciinemaPlayer: any;
+ private playerCreated = false;
constructor(
private route: ActivatedRoute,
@@ -37,10 +38,10 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
}
async ngOnInit() {
- // 动态加载 asciinema-player
await this.loadAsciinemaPlayer();
this.commands = new Array();
+
const start = new Date(this.replay.date_start);
const end = new Date(this.replay.date_end);
const duration = end.getTime() - start.getTime();
@@ -56,32 +57,49 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
if (this.startAt >= duration) {
this.startAt = duration;
}
- /* */
});
this.rows = Math.min(25, Math.floor((window.innerHeight - 120) / 16)); // 限制最大25行,调整计算方式
this.position = '00:00';
this.duration = formatTime(duration);
this.getCommands(this.page);
+
+ this.createPlayerWhenReady();
}
private async loadAsciinemaPlayer() {
try {
- // 动态导入 asciinema-player
const module = await import('asciinema-player');
+
this.AsciinemaPlayer = module.default || module;
} catch (error) {
console.error('Failed to load asciinema-player:', error);
- // 如果动态导入失败,尝试从全局变量获取(兼容性)
+
this.AsciinemaPlayer = (window as any).AsciinemaPlayer;
}
}
ngAfterViewInit() {
+ this.createPlayerWhenReady();
+ }
+
+ private createPlayerWhenReady() {
+ if (this.playerCreated) {
+ return;
+ }
+
if (this.AsciinemaPlayer) {
this.player = this.createPlayer();
- this.player.play();
- this.isPlaying = true;
- this.createTimer();
+
+ if (this.player) {
+ this.player.play();
+ this.isPlaying = true;
+ this.createTimer();
+ this.playerCreated = true;
+ } else {
+ console.error('Player creation failed');
+ }
+ } else {
+ setTimeout(() => this.createPlayerWhenReady(), 100);
}
}
@@ -176,9 +194,28 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
console.error('AsciinemaPlayer not loaded');
return null;
}
+
const el = document.getElementById('screen');
+
+ if (!el) {
+ console.error('Screen element not found');
+ return null;
+ }
+
+ if (!this.replay?.src) {
+ console.error('Replay src not available');
+ return null;
+ }
+
const opt = this.getPlayerOptions();
- return this.AsciinemaPlayer.create(this.replay.src, el, opt);
+
+ try {
+ const player = this.AsciinemaPlayer.create(this.replay.src, el, opt);
+ return player;
+ } catch (error) {
+ console.error('Error creating player:', error);
+ return null;
+ }
}
getUserLang() {
@@ -199,6 +236,7 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
if (!this.startTimeStamp) {
return;
}
+
this._http.getCommandsData(this.replay.id, page).subscribe(
data => {
const results = data.results;
@@ -209,6 +247,7 @@ export class ElementReplayAsciicastComponent implements OnInit, AfterViewInit {
this.commands = this.commands.concat(results);
},
err => {
+ console.error('getCommandsData error:', err);
alert('没找到命令记录');
}
);
diff --git a/src/app/pages/replay/replay.component.ts b/src/app/pages/replay/replay.component.ts
index 4c45857e4..708154c12 100644
--- a/src/app/pages/replay/replay.component.ts
+++ b/src/app/pages/replay/replay.component.ts
@@ -1,8 +1,8 @@
-import {Component, OnInit} from '@angular/core';
-import {ActivatedRoute} from '@angular/router';
-import {HttpService, I18nService, LogService, SettingService} from '@app/services';
-import {Asset, Replay, Session, User} from '@app/model';
-import {getWaterMarkContent} from '@app/utils/common';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+import { HttpService, I18nService, LogService, SettingService } from '@app/services';
+import { Asset, Replay, Session, User } from '@app/model';
+import { getWaterMarkContent } from '@app/utils/common';
@Component({
standalone: false,
@@ -18,11 +18,13 @@ export class PagesReplayComponent implements OnInit {
sessionUser: User;
loading: boolean = true;
- constructor(private route: ActivatedRoute,
- private _http: HttpService,
- private _settingSvc: SettingService,
- private _i18n: I18nService,
- private _logger: LogService) {
+ constructor(
+ private route: ActivatedRoute,
+ private _http: HttpService,
+ private _settingSvc: SettingService,
+ private _i18n: I18nService,
+ private _logger: LogService
+ ) {
this.getCurrentUser();
}
@@ -34,12 +36,21 @@ export class PagesReplayComponent implements OnInit {
async ngOnInit() {
let sid = '';
+
this.route.params.subscribe(params => {
sid = params['sid'];
});
+
this.session = await this._http.getSessionDetail(sid);
- this.asset = await this._http.getAssetDetail(this.session.asset_id).toPromise();
+
+ try {
+ this.asset = await this._http.getAssetDetail(this.session.asset_id).toPromise();
+ } catch (error) {
+ this.asset = new Asset();
+ }
+
this.sessionUser = await this._http.getUserDetail(this.session.user_id);
+
const interval = setInterval(() => {
this._http.getReplay(sid).subscribe(
data => {
@@ -55,11 +66,13 @@ export class PagesReplayComponent implements OnInit {
clearInterval(interval);
this.loading = false;
const auditorUser = `${this._i18n.instant('Viewer')}: ${this.user.name}(${this.user.username})`;
- const sessionContent = getWaterMarkContent(this.sessionUser, this.asset, this._settingSvc);
- const content = `${auditorUser}\n${sessionContent}`;
- this._settingSvc.createWaterMarkIfNeed(
- document.body, `${content}`
+ const sessionContent = getWaterMarkContent(
+ this.sessionUser,
+ this.asset,
+ this._settingSvc
);
+ const content = `${auditorUser}\n${sessionContent}`;
+ this._settingSvc.createWaterMarkIfNeed(document.body, `${content}`);
}
},
err => {
@@ -78,11 +91,11 @@ export class PagesReplayComponent implements OnInit {
const tp = this.replay.type;
const supportedType = {
- 'json': true,
- 'guacamole': true,
- 'asciicast': true,
- 'mp4': true,
- 'parts': true
+ json: true,
+ guacamole: true,
+ asciicast: true,
+ mp4: true,
+ parts: true
};
return !supportedType[tp];
}