Files
CloudHome-Ops/lib/services/app_service.dart

213 lines
6.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:dio/dio.dart';
import '../models/app_version.dart';
import '../models/tv_app.dart';
import 'api_client.dart';
import '../utils/session_org_scope.dart';
/// 应用管理服务:APP 版本管理与 TV 应用管理。
///
/// 对接真实「爱视后台」:
/// - APP 版本:/api/device/orgGroupAppVersion/*
/// - TV 应用:/api/theme/tvapp/*
class AppService {
AppService({Dio? dio}) : _dio = dio ?? ApiClient.instance.dio;
final Dio _dio;
// ================ APP 版本管理 ================
/// 获取 APP 版本列表(分页,可按组织/分组筛选)。
///
/// GET /device/orgGroupAppVersion/list?page=&limit=&orgId=&groupId=
Future<List<AppVersion>> getAppVersionList({
int page = 1,
int limit = 20,
String? orgId,
String? groupId,
}) async {
final effectiveOrgId = orgId ??
(SessionOrgScope.instance.enabled
? SessionOrgScope.instance.currentOrgId
: null);
final response = await _dio.get<dynamic>(
'/device/orgGroupAppVersion/list',
queryParameters: {
'page': page,
'limit': limit,
if (effectiveOrgId != null) 'orgId': effectiveOrgId,
if (groupId != null) 'groupId': groupId,
},
);
final list = _extractList(response.data);
return list
.whereType<Map<String, dynamic>>()
.map(AppVersion.fromJson)
.toList();
}
/// 按 orgId 查询该组织直接配置的版本(单体)。
///
/// 对齐 Web 端 `searchAppVersion`:每个 scope=ORG 的组织至多一条版本配置,
/// 有则返回当前版本(进入编辑流程)、无则返回 null(走新增流程)。
///
/// GET /device/orgGroupAppVersion/search?orgId=
///
/// 注意:拦截器已解包 `{code,msg,data}` 信封,`response.data` 即内层 data;
/// 兼容 data 为 `{appVersion: {...}}`、版本对象直接返回、或 null(无配置)三种形态。
Future<Map<String, dynamic>?> searchAppVersion({
required String orgId,
String? groupId,
}) async {
if (orgId.isEmpty && groupId == null) {
throw const ApiException(400, 'orgId 与 groupId 需二选一');
}
final response = await _dio.get<dynamic>(
'/device/orgGroupAppVersion/search',
queryParameters: {
if (orgId.isNotEmpty) 'orgId': orgId,
if (groupId != null) 'groupId': groupId,
},
);
final data = response.data;
if (data == null) return null;
if (data is Map<String, dynamic>) {
final appVersion = data['appVersion'];
if (appVersion is Map) {
return Map<String, dynamic>.from(appVersion);
}
// 直接是版本对象(含 id 或 versionName)。
if (data.containsKey('id') || data.containsKey('versionName')) {
return data;
}
}
return null;
}
/// 获取 APP 版本详情。
///
/// GET /device/orgGroupAppVersion/info/{id}
Future<AppVersion> getAppVersionInfo(String id) async {
final response =
await _dio.get<dynamic>('/device/orgGroupAppVersion/info/$id');
final data = response.data;
if (data is! Map<String, dynamic>) {
throw ApiException(500, 'APP 版本信息加载失败:$id');
}
return AppVersion.fromJson(data);
}
/// 新增 APP 版本。
///
/// POST /device/orgGroupAppVersion/save,body 为版本数据。
Future<void> saveAppVersion(Map<String, dynamic> data) async {
await _dio.post<dynamic>(
'/device/orgGroupAppVersion/save',
data: data,
);
}
/// 修改 APP 版本。
///
/// POST /device/orgGroupAppVersion/update,body 为版本数据(含 id)。
Future<void> updateAppVersion(Map<String, dynamic> data) async {
await _dio.post<dynamic>(
'/device/orgGroupAppVersion/update',
data: data,
);
}
/// 批量删除 APP 版本。
///
/// POST /device/orgGroupAppVersion/delete,body 为 `{ids: [...]}`。
Future<void> deleteAppVersion(List<int> ids) async {
await _dio.post<dynamic>(
'/device/orgGroupAppVersion/delete',
data: {'ids': ids},
);
}
// ================ TV 应用管理 ================
/// 获取 TV 应用列表(分页,可按名称/组织/分组筛选)。
///
/// GET /theme/tvapp/list?page=&limit=&appName=&orgId=&groupId=
Future<List<TvApp>> getTvAppList({
int page = 1,
int limit = 20,
String? appName,
String? orgId,
String? groupId,
}) async {
final effectiveOrgId = orgId ??
(SessionOrgScope.instance.enabled
? SessionOrgScope.instance.currentOrgId
: null);
final response = await _dio.get<dynamic>(
'/theme/tvapp/list',
queryParameters: {
'page': page,
'limit': limit,
if (appName != null) 'appName': appName,
if (effectiveOrgId != null) 'orgId': effectiveOrgId,
if (groupId != null) 'groupId': groupId,
},
);
final list = _extractList(response.data);
return list
.whereType<Map<String, dynamic>>()
.map(TvApp.fromJson)
.toList();
}
/// 获取 TV 应用详情。
///
/// GET /theme/tvapp/info/{id}
Future<TvApp> getTvAppInfo(String id) async {
final response = await _dio.get<dynamic>('/theme/tvapp/info/$id');
final data = response.data;
if (data is! Map<String, dynamic>) {
throw ApiException(500, 'TV 应用信息加载失败:$id');
}
return TvApp.fromJson(data);
}
/// 新增或修改 TV 应用。
///
/// POST /theme/tvapp/save,body 为应用数据。
Future<void> saveTvApp(Map<String, dynamic> data) async {
await _dio.post<dynamic>('/theme/tvapp/save', data: data);
}
/// 批量删除 TV 应用。
///
/// POST /theme/tvapp/delete,body 为 `{ids: [...]}`。
Future<void> deleteTvApp(List<int> ids) async {
await _dio.post<dynamic>(
'/theme/tvapp/delete',
data: {'ids': ids},
);
}
// ================ 工具方法 ================
/// 兼容列表响应的三种形态:
/// `{list: [...], totalCount}` / `{page: {list, totalCount}}` / 直接数组。
static List<dynamic> _extractList(dynamic data) {
if (data is List) {
return data;
}
if (data is Map<String, dynamic>) {
final list = data['list'];
if (list is List) {
return list;
}
final page = data['page'];
if (page is Map<String, dynamic> && page['list'] is List) {
return page['list'] as List;
}
}
return const <dynamic>[];
}
}