ops-console v1.0.2 (versionCode 8) 源码入库
This commit is contained in:
212
lib/services/app_service.dart
Normal file
212
lib/services/app_service.dart
Normal file
@@ -0,0 +1,212 @@
|
||||
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>[];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user