ops-console v1.0.2 (versionCode 8) 源码入库

This commit is contained in:
txh
2026-09-03 18:01:05 +08:00
commit 685fff27c8
170 changed files with 53049 additions and 0 deletions

View 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>[];
}
}