213 lines
6.4 KiB
Dart
213 lines
6.4 KiB
Dart
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>[];
|
||
}
|
||
}
|