chore(hmos): 导入生产环境鸿蒙工程
- 以 D:\SmartSenior 生产工程为源,纳入 AppScope、entry、cjagent、hvigor 及根配置 - 移除 build-profile.json5 的 signingConfigs(p12/p7b/cer 路径与加密口令)及 products.signingConfig 引用 - 不纳入本地与开发产物:local.properties、.idea、.hvigor、.codegenie、demo、backup_a2a_native、SESSION_LOG.md、build_err.txt、build/、oh_modules - .gitignore 追加 .codegenie 与密钥文件通配(*.p12/*.p7b/*.cer/*.jks/*.keystore/*.pem)
This commit is contained in:
@@ -0,0 +1,875 @@
|
||||
// entry/src/main/ets/utils/LiveViewUtil.ets
|
||||
import { liveViewManager } from '@kit.LiveViewKit';
|
||||
import { Want, wantAgent, WantAgent } from '@kit.AbilityKit';
|
||||
import { FlightData, LiveDataService, PilotData, ApiResponse } from './LiveDataService';
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import deviceInfo from '@ohos.deviceInfo';
|
||||
import { http } from '@kit.NetworkKit';
|
||||
|
||||
// Push Kit相关类型定义
|
||||
interface ClickAction {
|
||||
actionType: number;
|
||||
action: string;
|
||||
}
|
||||
|
||||
interface RichProgress {
|
||||
type: number;
|
||||
nodeIcons: string[];
|
||||
indicatorIcon: string;
|
||||
progress: number;
|
||||
indicatorType: number;
|
||||
color: string;
|
||||
bgColor: string;
|
||||
}
|
||||
|
||||
interface CapsuleData {
|
||||
type: number;
|
||||
status: number;
|
||||
icon: string;
|
||||
bgColor: string; // Push Kit格式
|
||||
backgroundColor: string; // 本地API格式
|
||||
title: string;
|
||||
content: string; // 显式声明必填
|
||||
}
|
||||
|
||||
// Push Kit专用的胶囊数据接口
|
||||
interface PushKitCapsuleData {
|
||||
type: number;
|
||||
status: number;
|
||||
icon: string;
|
||||
bgColor: string; // Push Kit要求的字段名
|
||||
title: string;
|
||||
content?: string; // 可选字段
|
||||
}
|
||||
|
||||
// JWT令牌响应接口
|
||||
interface JwtTokenResponse {
|
||||
token?: string;
|
||||
}
|
||||
|
||||
interface ContentTextItem {
|
||||
text: string;
|
||||
foregroundColor?: string;
|
||||
}
|
||||
|
||||
interface NotificationData {
|
||||
type: number;
|
||||
contentTitle: string;
|
||||
contentText: Array<ContentTextItem>;
|
||||
clickAction: ClickAction;
|
||||
richProgress: RichProgress;
|
||||
largeIcon: string; // 添加largeIcon字段
|
||||
keywords?: Record<string, string>; // 修改为可选的对象类型
|
||||
}
|
||||
|
||||
interface ActivityData {
|
||||
notificationData: NotificationData;
|
||||
capsuleData: PushKitCapsuleData; // 使用Push Kit专用接口
|
||||
}
|
||||
|
||||
// PHP接口响应接口
|
||||
interface PhpApiResponse {
|
||||
success?: boolean;
|
||||
error?: string;
|
||||
code?: string | number;
|
||||
msg?: string;
|
||||
}
|
||||
|
||||
// PHP接口请求数据接口
|
||||
interface StartLiveViewRequestData {
|
||||
token: string;
|
||||
flight_data: FlightData;
|
||||
activity_id: number;
|
||||
authorization: string;
|
||||
}
|
||||
|
||||
interface UpdateLiveViewRequestData {
|
||||
token: string;
|
||||
flight_data: FlightData;
|
||||
activity_id: number;
|
||||
authorization: string;
|
||||
}
|
||||
|
||||
interface EndLiveViewRequestData {
|
||||
token: string;
|
||||
activity_id: number;
|
||||
authorization: string;
|
||||
}
|
||||
|
||||
const DOMAIN = 0x0000;
|
||||
|
||||
/**
|
||||
* 实况窗控制器类,负责管理实况窗的整个生命周期
|
||||
*/
|
||||
export class LiveViewController {
|
||||
private static selectedPilot: PilotData | null = null;
|
||||
private static deviceId: string = '';
|
||||
private static wantAgentInstance: WantAgent | null = null;
|
||||
private static readonly TEMPLATE_ID = 'flight_live_view_template'; // 模板ID
|
||||
private static activityId: number = 0; // 实况活动ID
|
||||
|
||||
// 添加PHP接口URL
|
||||
private static readonly START_LIVE_VIEW_PUSH_API = 'https://system.ldpfly.cn/hmos/startLiveViewPush.php';
|
||||
private static readonly UPDATE_LIVE_VIEW_PUSH_API = 'https://system.ldpfly.cn/hmos/updateLiveViewPush.php';
|
||||
private static readonly END_LIVE_VIEW_PUSH_API = 'https://system.ldpfly.cn/hmos/endLiveViewPush.php';
|
||||
private static readonly ONLINE_PILOTS_API = 'https://system.ldpfly.cn/hmos/OnlinePilots.php'; // 使用OnlinePilots.php
|
||||
|
||||
/**
|
||||
* 设置选中的飞行员
|
||||
* @param pilot 选中的飞行员数据
|
||||
*/
|
||||
public static setSelectedPilot(pilot: PilotData): void {
|
||||
LiveViewController.selectedPilot = pilot;
|
||||
// 获取设备ID
|
||||
LiveViewController.deviceId = deviceInfo.productModel || 'unknown_device';
|
||||
hilog.info(DOMAIN, 'LiveViewController',
|
||||
`Selected pilot: ${pilot.callsign}, Device ID: ${LiveViewController.deviceId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置实况活动ID
|
||||
* @param id 实况活动ID
|
||||
*/
|
||||
public static setActivityId(id: number): void {
|
||||
LiveViewController.activityId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备ID
|
||||
* @returns string 设备ID
|
||||
*/
|
||||
public static getDeviceId(): string {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Getting device ID: ${LiveViewController.deviceId}`);
|
||||
return LiveViewController.deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动实况窗
|
||||
* @returns Promise<ApiResponse> - 启动结果
|
||||
*/
|
||||
public static async startLiveView(): Promise<ApiResponse> {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Starting live view');
|
||||
|
||||
if (!LiveViewController.selectedPilot) {
|
||||
const errorMsg = "请先选择一个飞行员";
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 校验实况窗开关是否打开
|
||||
if (!await LiveViewController.isLiveViewEnabled()) {
|
||||
const errorMsg = "Live view is disabled.";
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 构建WantAgent
|
||||
await LiveViewController.buildWantAgent();
|
||||
|
||||
// 转换选中的飞行员数据为航班数据格式
|
||||
const flightData = LiveViewController.convertPilotToFlightData(LiveViewController.selectedPilot);
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Converted flight data: ${JSON.stringify(flightData)}`);
|
||||
|
||||
// 获取设备ID
|
||||
const deviceId = LiveViewController.getDeviceId();
|
||||
if (!deviceId) {
|
||||
throw new Error("设备ID获取失败");
|
||||
}
|
||||
|
||||
// 获取Push Token
|
||||
let pushToken: string;
|
||||
try {
|
||||
pushToken = await LiveDataService.fetchPushToken(deviceId);
|
||||
if (!pushToken) {
|
||||
throw new Error("未能获取到推送令牌");
|
||||
}
|
||||
} catch (tokenError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取Push Token失败: ${tokenError.message}`);
|
||||
throw new Error("获取推送令牌失败: " + tokenError.message);
|
||||
}
|
||||
|
||||
// 获取JWT令牌
|
||||
let authorization: string;
|
||||
try {
|
||||
authorization = await LiveViewController.getAuthorizationToken();
|
||||
if (!authorization) {
|
||||
throw new Error("未能获取到授权令牌");
|
||||
}
|
||||
} catch (authError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取JWT令牌失败: ${authError.message}`);
|
||||
throw new Error("获取授权令牌失败: " + authError.message);
|
||||
}
|
||||
|
||||
// 生成activityId
|
||||
LiveViewController.activityId = parseInt(Date.now().toString().slice(-9));
|
||||
|
||||
// 通过Push Kit启动实况窗
|
||||
await LiveViewController.startRemoteLiveViewViaPushKit(
|
||||
pushToken,
|
||||
flightData,
|
||||
LiveViewController.activityId,
|
||||
authorization
|
||||
);
|
||||
|
||||
// 创建本地实况窗
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Creating local live view');
|
||||
return await LiveDataService.createRemoteLiveView(LiveViewController.deviceId, flightData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新实况窗
|
||||
* @returns Promise<ApiResponse> - 更新结果
|
||||
*/
|
||||
public static async updateLiveView(): Promise<ApiResponse> {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Updating live view');
|
||||
|
||||
if (!LiveViewController.selectedPilot) {
|
||||
const errorMsg = "没有选中的飞行员";
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 从OnlinePilots.php重新获取最新的航班数据
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Fetching latest flight data from OnlinePilots.php');
|
||||
const flightData = await LiveViewController.fetchFlightDataFromOnlinePilots();
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Fetched flight data: ${JSON.stringify(flightData)}`);
|
||||
|
||||
// 获取设备ID
|
||||
const deviceId = LiveViewController.getDeviceId();
|
||||
if (!deviceId) {
|
||||
throw new Error("设备ID获取失败");
|
||||
}
|
||||
|
||||
// 获取Push Token
|
||||
let pushToken: string;
|
||||
try {
|
||||
pushToken = await LiveDataService.fetchPushToken(deviceId);
|
||||
if (!pushToken) {
|
||||
throw new Error("未能获取到推送令牌");
|
||||
}
|
||||
} catch (tokenError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取Push Token失败: ${tokenError.message}`);
|
||||
throw new Error("获取推送令牌失败: " + tokenError.message);
|
||||
}
|
||||
|
||||
// 获取JWT令牌
|
||||
let authorization: string;
|
||||
try {
|
||||
authorization = await LiveViewController.getAuthorizationToken();
|
||||
if (!authorization) {
|
||||
throw new Error("未能获取到授权令牌");
|
||||
}
|
||||
} catch (authError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取JWT令牌失败: ${authError.message}`);
|
||||
throw new Error("获取授权令牌失败: " + authError.message);
|
||||
}
|
||||
|
||||
// 通过Push Kit更新实况窗
|
||||
await LiveViewController.updateRemoteLiveViewViaPushKit(
|
||||
pushToken,
|
||||
flightData,
|
||||
LiveViewController.activityId,
|
||||
authorization
|
||||
);
|
||||
|
||||
return await LiveDataService.updateRemoteLiveView(LiveViewController.deviceId, flightData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束实况窗
|
||||
* @returns Promise<ApiResponse> - 结束结果
|
||||
*/
|
||||
public static async endLiveView(): Promise<ApiResponse> {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Ending live view');
|
||||
|
||||
if (!LiveViewController.deviceId) {
|
||||
const errorMsg = "设备ID未获取";
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 获取设备ID
|
||||
const deviceId = LiveViewController.getDeviceId();
|
||||
if (!deviceId) {
|
||||
throw new Error("设备ID获取失败");
|
||||
}
|
||||
|
||||
// 获取Push Token
|
||||
let pushToken: string;
|
||||
try {
|
||||
pushToken = await LiveDataService.fetchPushToken(deviceId);
|
||||
if (!pushToken) {
|
||||
throw new Error("未能获取到推送令牌");
|
||||
}
|
||||
} catch (tokenError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取Push Token失败: ${tokenError.message}`);
|
||||
throw new Error("获取推送令牌失败: " + tokenError.message);
|
||||
}
|
||||
|
||||
// 获取JWT令牌
|
||||
let authorization: string;
|
||||
try {
|
||||
authorization = await LiveViewController.getAuthorizationToken();
|
||||
if (!authorization) {
|
||||
throw new Error("未能获取到授权令牌");
|
||||
}
|
||||
} catch (authError) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取JWT令牌失败: ${authError.message}`);
|
||||
throw new Error("获取授权令牌失败: " + authError.message);
|
||||
}
|
||||
|
||||
// 通过Push Kit结束实况窗
|
||||
await LiveViewController.endRemoteLiveViewViaPushKit(
|
||||
pushToken,
|
||||
LiveViewController.activityId,
|
||||
authorization
|
||||
);
|
||||
|
||||
// 清理WantAgent
|
||||
if (LiveViewController.wantAgentInstance) {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Cancelling wantAgent');
|
||||
await wantAgent.cancel(LiveViewController.wantAgentInstance);
|
||||
LiveViewController.wantAgentInstance = null;
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'WantAgent cancelled successfully');
|
||||
} catch (error) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to cancel wantAgent: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 结束本地实况窗
|
||||
try {
|
||||
await LiveViewController.stopLiveView();
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Local live view stopped successfully');
|
||||
} catch (error) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to stop local live view: ${error.message}`);
|
||||
}
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Ending remote live view');
|
||||
return await LiveDataService.endRemoteLiveView(LiveViewController.deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将飞行员数据转换为航班数据格式
|
||||
* @param pilot 飞行员数据
|
||||
* @returns FlightData 航班数据
|
||||
*/
|
||||
public static convertPilotToFlightData(pilot: PilotData): FlightData {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Converting pilot to flight data: ${pilot.callsign}`);
|
||||
|
||||
const flightData: FlightData = {
|
||||
flightNumber: pilot.callsign,
|
||||
altitude: pilot.altitude,
|
||||
speed: pilot.groundSpeed,
|
||||
origin: pilot.departureAirport || "未知", // 防止空字符串
|
||||
destination: pilot.destinationAirport || "未知", // 防止空字符串
|
||||
originName: "出发机场", // 固定显示
|
||||
destinationName: "到达机场", // 固定显示
|
||||
statusCode: 1,
|
||||
statusText: "飞行中"
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Converted flight data: ${JSON.stringify(flightData)}`);
|
||||
return flightData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验实况窗功能是否启用
|
||||
* @returns boolean - 是否启用
|
||||
*/
|
||||
private static async isLiveViewEnabled(): Promise<boolean> {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Checking if live view is enabled');
|
||||
const enabled = await liveViewManager.isLiveViewEnabled();
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Live view enabled status: ${enabled}`);
|
||||
return enabled;
|
||||
} catch (error) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to check live view status: ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建点击动作WantAgent
|
||||
* @returns Want - 点击后的跳转意图
|
||||
*/
|
||||
public static async buildWantAgent(): Promise<void> {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Building WantAgent');
|
||||
|
||||
const wantAgentInfo: wantAgent.WantAgentInfo = {
|
||||
wants: [
|
||||
{
|
||||
bundleName: 'com.example.ldpflyefb', // 应用实际bundleName
|
||||
abilityName: 'EntryAbility',
|
||||
moduleName: 'entry',
|
||||
parameters: {
|
||||
targetPage: 'map',
|
||||
flightNo: LiveViewController.selectedPilot?.callsign || '',
|
||||
departure: LiveViewController.selectedPilot?.departureAirport || '',
|
||||
destination: LiveViewController.selectedPilot?.destinationAirport || ''
|
||||
}
|
||||
} as Want
|
||||
],
|
||||
operationType: wantAgent.OperationType.START_ABILITY,
|
||||
requestCode: 0,
|
||||
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `WantAgent info: ${JSON.stringify(wantAgentInfo)}`);
|
||||
LiveViewController.wantAgentInstance = await wantAgent.getWantAgent(wantAgentInfo);
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'WantAgent created successfully');
|
||||
} catch (error) {
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to create WantAgent: ${error.message}`);
|
||||
throw new Error(`WantAgent创建失败: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取WantAgent实例
|
||||
* @returns WantAgent实例
|
||||
*/
|
||||
public static getWantAgent(): WantAgent | null {
|
||||
hilog.info(DOMAIN, 'LiveViewController',
|
||||
`Getting WantAgent instance: ${LiveViewController.wantAgentInstance !== null}`);
|
||||
return LiveViewController.wantAgentInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建实况胶囊数据(本地API格式)
|
||||
* @param flightData 航班数据
|
||||
* @returns capsuleData 实况胶囊数据
|
||||
*/
|
||||
public static buildCapsuleData(flightData: FlightData): CapsuleData {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Building capsule data for flight: ${flightData.flightNumber}`);
|
||||
|
||||
// 提供默认值而不是抛出错误
|
||||
const speed = flightData.speed || 0;
|
||||
const altitude = flightData.altitude || 0;
|
||||
|
||||
const capsuleData: CapsuleData = {
|
||||
//实况胶囊数据显示
|
||||
type: 1,
|
||||
status: 1,
|
||||
icon: "icon.png", //实况胶囊左侧图标定义,你爹地默认使用LDP FLY的图标
|
||||
bgColor: "#FF0A59F7", // Push Kit格式
|
||||
backgroundColor: "#FF0A59F7", // 本地API格式
|
||||
title: "飞行中", // 固定显示"飞行中"
|
||||
content: flightData.flightNumber // 显示航班号
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Built capsule data: ${JSON.stringify(capsuleData)}`);
|
||||
return capsuleData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换胶囊数据为Push Kit格式
|
||||
* @param capsule 本地胶囊数据
|
||||
* @returns PushKitCapsuleData Push Kit格式的胶囊数据
|
||||
*/
|
||||
private static convertCapsuleForPushKit(capsule: CapsuleData): PushKitCapsuleData {
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Converting capsule data for Push Kit');
|
||||
|
||||
// 验证数据完整性
|
||||
if (!capsule || !capsule.type || !capsule.status || capsule.icon === undefined || !capsule.bgColor ||
|
||||
!capsule.title) {
|
||||
const errorMsg = "胶囊数据不完整";
|
||||
hilog.error(DOMAIN, 'LiveViewController', `${errorMsg}. Capsule data: ${JSON.stringify(capsule)}`);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 验证胶囊类型
|
||||
if (capsule.type !== 1 && capsule.type !== 2) {
|
||||
const errorMsg = "胶囊类型必须为1或2";
|
||||
hilog.error(DOMAIN, 'LiveViewController', `${errorMsg}. Type: ${capsule.type}`);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
// 验证背景颜色格式
|
||||
if (!/^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/.test(capsule.bgColor)) {
|
||||
const errorMsg = "背景颜色格式必须为#RRGGBB或#AARRGGBB";
|
||||
hilog.error(DOMAIN, 'LiveViewController', `${errorMsg}. Color: ${capsule.bgColor}`);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
const pushKitCapsuleData: PushKitCapsuleData = {
|
||||
type: capsule.type,
|
||||
status: capsule.status,
|
||||
icon: capsule.icon || "flight_icon.png", // 提供默认图标
|
||||
bgColor: capsule.bgColor, // 字段名转换
|
||||
title: capsule.title,
|
||||
content: capsule.content // 可选字段
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Converted PushKit capsule data: ${JSON.stringify(pushKitCapsuleData)}`);
|
||||
return pushKitCapsuleData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过PHP接口启动实况窗
|
||||
* @param token Push Token
|
||||
* @param flightData 航班数据
|
||||
* @param activityId 实况活动ID
|
||||
* @param authorization JWT授权令牌
|
||||
*/
|
||||
public static async startRemoteLiveViewViaPushKit(token: string, flightData: FlightData, activityId: number,
|
||||
authorization: string): Promise<void> {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Starting remote live view via PHP API. Activity ID: ${activityId}`);
|
||||
|
||||
const httpRequest = http.createHttp();
|
||||
const requestData: StartLiveViewRequestData = {
|
||||
token: token,
|
||||
flight_data: flightData,
|
||||
activity_id: activityId,
|
||||
authorization: authorization
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Request data: ${JSON.stringify(requestData)}`);
|
||||
|
||||
const response = await httpRequest.request(
|
||||
LiveViewController.START_LIVE_VIEW_PUSH_API,
|
||||
{
|
||||
method: http.RequestMethod.POST,
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
extraData: JSON.stringify(requestData)
|
||||
}
|
||||
);
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController',
|
||||
`Start remote live view via PHP API response code: ${response.responseCode}`);
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Start remote live view via PHP API response: ${response.result}`);
|
||||
|
||||
const responseText = response.result as string;
|
||||
const responseJson = JSON.parse(responseText) as PhpApiResponse;
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Parsed response: ${JSON.stringify(responseJson)}`);
|
||||
|
||||
// 修复错误判断逻辑:将"80000000"视为成功响应
|
||||
if ((responseJson.success === false) ||
|
||||
(responseJson.code && responseJson.code !== "80000000" && responseJson.code !== "200" &&
|
||||
responseJson.code !== 200)) {
|
||||
const errorMsg = `PHP API Error: ${responseJson.msg || responseJson.error || responseJson.code}`;
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Remote live view started successfully via PHP API');
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to start remote live view via PHP API: ${err.message}`);
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Stack trace: ${err.stack}`);
|
||||
throw new Error(`通过PHP接口启动实况窗失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过PHP接口更新实况窗
|
||||
* @param token Push Token
|
||||
* @param flightData 航班数据
|
||||
* @param activityId 实况活动ID
|
||||
* @param authorization JWT授权令牌
|
||||
*/
|
||||
public static async updateRemoteLiveViewViaPushKit(token: string, flightData: FlightData, activityId: number,
|
||||
authorization: string): Promise<void> {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Updating remote live view via PHP API. Activity ID: ${activityId}`);
|
||||
|
||||
const httpRequest = http.createHttp();
|
||||
const requestData: UpdateLiveViewRequestData = {
|
||||
token: token,
|
||||
flight_data: flightData,
|
||||
activity_id: activityId,
|
||||
authorization: authorization
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Request data: ${JSON.stringify(requestData)}`);
|
||||
|
||||
const response = await httpRequest.request(
|
||||
LiveViewController.UPDATE_LIVE_VIEW_PUSH_API,
|
||||
{
|
||||
method: http.RequestMethod.POST,
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
extraData: JSON.stringify(requestData)
|
||||
}
|
||||
);
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController',
|
||||
`Update remote live view via PHP API response code: ${response.responseCode}`);
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Update remote live view via PHP API response: ${response.result}`);
|
||||
|
||||
const responseText = response.result as string;
|
||||
const responseJson = JSON.parse(responseText) as PhpApiResponse;
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Parsed response: ${JSON.stringify(responseJson)}`);
|
||||
|
||||
// 修复错误判断逻辑:将"80000000"视为成功响应
|
||||
if ((responseJson.success === false) ||
|
||||
(responseJson.code && responseJson.code !== "80000000" && responseJson.code !== "200" &&
|
||||
responseJson.code !== 200)) {
|
||||
const errorMsg = `PHP API Error: ${responseJson.msg || responseJson.error || responseJson.code}`;
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Remote live view updated successfully via PHP API');
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to update remote live view via PHP API: ${err.message}`);
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Stack trace: ${err.stack}`);
|
||||
throw new Error(`通过PHP接口更新实况窗失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过PHP接口结束实况窗
|
||||
* @param token Push Token
|
||||
* @param activityId 实况活动ID
|
||||
* @param authorization JWT授权令牌
|
||||
*/
|
||||
public static async endRemoteLiveViewViaPushKit(token: string, activityId: number,
|
||||
authorization: string): Promise<void> {
|
||||
try {
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Ending remote live view via PHP API. Activity ID: ${activityId}`);
|
||||
|
||||
const httpRequest = http.createHttp();
|
||||
const requestData: EndLiveViewRequestData = {
|
||||
token: token,
|
||||
activity_id: activityId,
|
||||
authorization: authorization
|
||||
};
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Request data: ${JSON.stringify(requestData)}`);
|
||||
|
||||
const response = await httpRequest.request(
|
||||
LiveViewController.END_LIVE_VIEW_PUSH_API,
|
||||
{
|
||||
method: http.RequestMethod.POST,
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
extraData: JSON.stringify(requestData)
|
||||
}
|
||||
);
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController',
|
||||
`End remote live view via PHP API response code: ${response.responseCode}`);
|
||||
hilog.info(DOMAIN, 'LiveViewController', `End remote live view via PHP API response: ${response.result}`);
|
||||
|
||||
const responseText = response.result as string;
|
||||
const responseJson = JSON.parse(responseText) as PhpApiResponse;
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', `Parsed response: ${JSON.stringify(responseJson)}`);
|
||||
|
||||
// 修复错误判断逻辑:将"80000000"视为成功响应
|
||||
if ((responseJson.success === false) ||
|
||||
(responseJson.code && responseJson.code !== "80000000" && responseJson.code !== "200" &&
|
||||
responseJson.code !== 200)) {
|
||||
const errorMsg = `PHP API Error: ${responseJson.msg || responseJson.error || responseJson.code}`;
|
||||
hilog.error(DOMAIN, 'LiveViewController', errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
||||
hilog.info(DOMAIN, 'LiveViewController', 'Remote live view ended successfully via PHP API');
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Failed to end remote live view via PHP API: ${err.message}`);
|
||||
hilog.error(DOMAIN, 'LiveViewController', `Stack trace: ${err.stack}`);
|
||||
throw new Error(`通过PHP接口结束实况窗失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建本地实况窗视图
|
||||
* @returns Promise<liveViewManager.LiveView> 实况窗对象
|
||||
*/
|
||||
private static async buildLocalLiveView(flightData: FlightData): Promise<liveViewManager.LiveView> {
|
||||
// 获取WantAgent实例
|
||||
const wantAgent: WantAgent | null = LiveViewController.getWantAgent();
|
||||
if (!wantAgent) {
|
||||
throw new Error("WantAgent未初始化");
|
||||
}
|
||||
|
||||
return {
|
||||
id: 0,
|
||||
event: "FLIGHT",
|
||||
liveViewData: {
|
||||
primary: {
|
||||
title: flightData.flightNumber, // 只显示航班号
|
||||
content: [
|
||||
{ text: "高度 " },
|
||||
{ text: `${flightData.altitude}`, textColor: "#FF0A59F7" },
|
||||
{ text: " ft" },
|
||||
{ text: " | " },
|
||||
{ text: "速度 " },
|
||||
{ text: `${flightData.speed}`, textColor: "#FF0A59F7" },
|
||||
{ text: " kts" },
|
||||
],
|
||||
keepTime: 15,
|
||||
backgroundType: liveViewManager.BackgroundType.SYS_BACKGROUND_FLIGHT_SUNSET,
|
||||
clickAction: wantAgent,
|
||||
layoutData: {
|
||||
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_FLIGHT,
|
||||
spaceIcon: "flight_icon1.png",
|
||||
firstTitle: flightData.origin || "未知", // 防止空字符串导致参数错误
|
||||
firstContent: flightData.originName || "出发机场",
|
||||
lastTitle: flightData.destination || "未知", // 防止空字符串导致参数错误
|
||||
lastContent: flightData.destinationName || "到达机场",
|
||||
additionalText: "数据来源于FSD服务器,仅供参考 | LDP FLY空天模拟飞行平台",
|
||||
}
|
||||
},
|
||||
// 添加实况胶囊数据 - 修改为新的显示格式
|
||||
capsule: {
|
||||
type: 1,
|
||||
status: 1,
|
||||
icon: "icon.png",
|
||||
backgroundColor: "#FF0A59F7",
|
||||
title: "飞行中", // 固定显示"飞行中"
|
||||
content: flightData.flightNumber // 显示航班号
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新本地实况窗
|
||||
* @returns Promise<liveViewManager.LiveViewResult> 更新结果
|
||||
*/
|
||||
public static async updateLocalLiveView(): Promise<liveViewManager.LiveViewResult> {
|
||||
// 校验实况窗开关是否打开
|
||||
if (!await LiveViewController.isLiveViewEnabled()) {
|
||||
throw new Error("Live view is disabled.");
|
||||
}
|
||||
|
||||
if (!LiveViewController.selectedPilot) {
|
||||
throw new Error("没有选中的飞行员");
|
||||
}
|
||||
|
||||
// 转换选中的飞行员数据为航班数据格式
|
||||
const flightData = LiveViewController.convertPilotToFlightData(LiveViewController.selectedPilot);
|
||||
|
||||
// 构建实况窗视图
|
||||
const liveView = await LiveViewController.buildLocalLiveView(flightData);
|
||||
|
||||
// 更新实况窗
|
||||
return await liveViewManager.updateLiveView(liveView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束本地实况窗
|
||||
* @returns Promise<liveViewManager.LiveViewResult> 结束结果
|
||||
*/
|
||||
public static async stopLiveView(): Promise<liveViewManager.LiveViewResult> {
|
||||
// 校验实况窗开关是否打开
|
||||
if (!await LiveViewController.isLiveViewEnabled()) {
|
||||
throw new Error("Live view is disabled.");
|
||||
}
|
||||
|
||||
if (!LiveViewController.selectedPilot) {
|
||||
throw new Error("没有选中的飞行员");
|
||||
}
|
||||
|
||||
// 转换选中的飞行员数据为航班数据格式
|
||||
const flightData = LiveViewController.convertPilotToFlightData(LiveViewController.selectedPilot);
|
||||
|
||||
// 修改实况窗内容为结束状态
|
||||
const liveView = await LiveViewController.buildLocalLiveView(flightData);
|
||||
liveView.liveViewData.primary.title = `${flightData.flightNumber} 已到达`;
|
||||
liveView.liveViewData.primary.content = [
|
||||
{ text: '航班已安全降落,' },
|
||||
{ text: '感谢您的飞行' }
|
||||
];
|
||||
liveView.liveViewData.primary.layoutData = {
|
||||
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_FLIGHT,
|
||||
spaceIcon: "flight_icon1.png",
|
||||
firstTitle: flightData.origin || "未知", // 防止空字符串导致参数错误
|
||||
firstContent: flightData.originName || "出发机场",
|
||||
lastTitle: flightData.destination || "未知", // 防止空字符串导致参数错误
|
||||
lastContent: flightData.destinationName || "到达机场",
|
||||
additionalText: "数据来源于FSD服务器,仅供参考 | LDP FLY空天模拟飞行平台",
|
||||
};
|
||||
liveView.liveViewData.capsule = {
|
||||
type: 1,
|
||||
status: 1,
|
||||
icon: "icon.png",
|
||||
backgroundColor: "#FF0A59F7",
|
||||
title: `${flightData.flightNumber} 已到达`
|
||||
};
|
||||
|
||||
// 结束实况窗
|
||||
return await liveViewManager.stopLiveView(liveView);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取JWT授权令牌
|
||||
* @returns Promise<string> JWT令牌
|
||||
*/
|
||||
private static async getAuthorizationToken(): Promise<string> {
|
||||
try {
|
||||
const httpRequest = http.createHttp();
|
||||
const response = await httpRequest.request(
|
||||
'https://system.ldpfly.cn/hmos/getJwtToken.php',
|
||||
{
|
||||
method: http.RequestMethod.GET,
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 检查HTTP状态码
|
||||
if (response.responseCode !== 200) {
|
||||
throw new Error(`HTTP Error: ${response.responseCode}`);
|
||||
}
|
||||
|
||||
const resultText = response.result as string;
|
||||
|
||||
// 检查返回内容是否为HTML(错误页面)
|
||||
if (resultText.trim().startsWith('<html') || resultText.trim().startsWith('<!DOCTYPE')) {
|
||||
throw new Error('Server returned HTML error page instead of JSON');
|
||||
}
|
||||
const result: JwtTokenResponse = JSON.parse(resultText);
|
||||
if (result.token) {
|
||||
return result.token;
|
||||
} else {
|
||||
throw new Error('服务器返回的JWT令牌无效');
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取JWT令牌失败: ${err.message}`);
|
||||
throw new Error('获取授权令牌失败: ' + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从OnlinePilots.php获取最新的航班数据
|
||||
* @returns Promise<FlightData> 航班数据
|
||||
*/
|
||||
private static async fetchFlightDataFromOnlinePilots(): Promise<FlightData> {
|
||||
try {
|
||||
// 获取所有在线飞行员数据
|
||||
const onlinePilots = await LiveDataService.fetchOnlinePilots();
|
||||
|
||||
// 查找与当前选中飞行员匹配的数据
|
||||
const selectedPilotCallsign = LiveViewController.selectedPilot?.callsign;
|
||||
const matchingPilot = onlinePilots.find(pilot => pilot.callsign === selectedPilotCallsign);
|
||||
|
||||
if (matchingPilot) {
|
||||
// 将PilotData转换为FlightData
|
||||
return LiveViewController.convertPilotToFlightData(matchingPilot);
|
||||
} else {
|
||||
// 如果未找到匹配的飞行员,抛出错误
|
||||
throw new Error(`未找到呼号为 ${selectedPilotCallsign} 的飞行员数据`);
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
hilog.error(DOMAIN, 'LiveViewController', `获取航班数据失败: ${err.message}`);
|
||||
throw new Error('获取航班数据失败: ' + err.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user