完善游客模式登录 并且新增设备管理
This commit is contained in:
@@ -3,21 +3,17 @@ abstract class Api {
|
||||
/// 游客登录查看是否已经注册
|
||||
static const String kr_isRegister = "/v1/app/auth/check";
|
||||
|
||||
/// 注册1024
|
||||
static const String kr_register = "/v1/app/auth/register";
|
||||
/// 注册
|
||||
static const String kr_register = "/v1/auth/register";
|
||||
|
||||
/// 验证验证码
|
||||
static const String kr_checkVerificationCode =
|
||||
"/v1/common/check_verification_code";
|
||||
static const String kr_checkVerificationCode = "/v1/auth/check-code";
|
||||
|
||||
/// 发送手机验证码
|
||||
static const String kr_sendPhoneCode = "/v1/common/send_sms_code";
|
||||
|
||||
/// 发送邮箱验证码
|
||||
static const String kr_sendEmailCode = "/v1/common/send_code";
|
||||
/// 发送验证码(统一接口,支持邮箱和手机)
|
||||
static const String kr_sendCode = "/v1/auth/send-code";
|
||||
|
||||
/// 登录接口
|
||||
static const String kr_login = "/v1/app/auth/login";
|
||||
static const String kr_login = "/v1/auth/login";
|
||||
|
||||
/// 设备登录(游客登录)
|
||||
/// 参考 OmnOem 项目 ppanel.json 配置
|
||||
@@ -29,8 +25,8 @@ abstract class Api {
|
||||
/// 忘记密码-设置新密码
|
||||
static const String kr_setNewPsdByForgetPsd = "/v1/app/auth/reset_password";
|
||||
|
||||
/// 节点信息
|
||||
static const String kr_nodeList = "/v1/app/node/list";
|
||||
/// 节点信息(包含试用/付费标志)
|
||||
static const String kr_nodeList = "/v1/public/subscribe/node/list";
|
||||
|
||||
/// 获取用户订阅流量日志
|
||||
static const String kr_nodeGroupList = "/v1/app/node/rule_group_list";
|
||||
@@ -48,15 +44,15 @@ abstract class Api {
|
||||
static const String kr_checkout = "/v1/app/order/checkout";
|
||||
|
||||
/// 获取可购买套餐
|
||||
static const String kr_getPackageList = "/v1/app/subscribe/list";
|
||||
static const String kr_getPackageList = "/v1/public/subscribe/list";
|
||||
|
||||
/// 获取用户已订阅套餐
|
||||
/// 获取用户已订阅套餐(用于判断是否购买过)
|
||||
static const String kr_getAlreadySubscribe =
|
||||
"/v1/app/subscribe/user/already_subscribe";
|
||||
"/v1/public/user/subscribe";
|
||||
|
||||
/// 获取用户可用订阅
|
||||
/// 获取用户可用订阅(与已订阅接口相同,OmnOem 项目中没有区分)
|
||||
static const String kr_userAvailableSubscribe =
|
||||
"/v1/app/subscribe/user/available_subscribe";
|
||||
"/v1/public/user/subscribe";
|
||||
|
||||
/// 续费
|
||||
static const String kr_renewal = "/v1/app/order/renewal";
|
||||
@@ -66,7 +62,7 @@ abstract class Api {
|
||||
static const String kr_orderDetail = "/v1/app/order/detail";
|
||||
|
||||
/// 获取消息列表
|
||||
static const String kr_getMessageList = "/v1/app/announcement/list";
|
||||
static const String kr_getMessageList = "/v1/public/announcement/list";
|
||||
|
||||
/// 获取邀请数据
|
||||
// static const String kr_getInviteData = "/v1/public/invite/code";
|
||||
@@ -74,9 +70,6 @@ abstract class Api {
|
||||
/// 配置信息
|
||||
static const String kr_config = "/v1/app/auth/config";
|
||||
|
||||
/// 获取用户信息
|
||||
static const String kr_getUserInfo = "/v1/app/user/info";
|
||||
|
||||
/// 获取用户在线时长统计
|
||||
static const String kr_getUserOnlineTimeStatistics =
|
||||
"/v1/app/user/online_time/statistics";
|
||||
@@ -96,4 +89,10 @@ abstract class Api {
|
||||
/// 重置订阅周期
|
||||
static const String kr_resetSubscribePeriod =
|
||||
"/v1/app/subscribe/reset/period";
|
||||
|
||||
/// 获取用户设备列表
|
||||
static const String kr_getUserDevices = "/v1/public/user/devices";
|
||||
|
||||
/// 解绑用户设备
|
||||
static const String kr_unbindUserDevice = "/v1/public/user/unbind_device";
|
||||
}
|
||||
|
||||
@@ -83,21 +83,22 @@ class KRUserApi {
|
||||
return right(baseResponse.model);
|
||||
}
|
||||
|
||||
Future<Either<HttpError, KRUserInfo>> kr_getUserInfo() async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
BaseResponse<KRUserInfo> baseResponse =
|
||||
await HttpUtil.getInstance().request<KRUserInfo>(
|
||||
Api.kr_getUserInfo,
|
||||
data,
|
||||
method: HttpMethod.GET,
|
||||
isShowLoading: false,
|
||||
);
|
||||
if (!baseResponse.isSuccess) {
|
||||
return left(
|
||||
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
}
|
||||
return right(baseResponse.model);
|
||||
}
|
||||
// ⚠️ 已废弃:新版本后端不再提供此接口
|
||||
// Future<Either<HttpError, KRUserInfo>> kr_getUserInfo() async {
|
||||
// final Map<String, dynamic> data = <String, dynamic>{};
|
||||
// BaseResponse<KRUserInfo> baseResponse =
|
||||
// await HttpUtil.getInstance().request<KRUserInfo>(
|
||||
// Api.kr_getUserInfo,
|
||||
// data,
|
||||
// method: HttpMethod.GET,
|
||||
// isShowLoading: false,
|
||||
// );
|
||||
// if (!baseResponse.isSuccess) {
|
||||
// return left(
|
||||
// HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
// }
|
||||
// return right(baseResponse.model);
|
||||
// }
|
||||
|
||||
Future<Either<HttpError, KRAffiliateCount>> kr_getAffiliateCount() async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
@@ -132,4 +133,64 @@ class KRUserApi {
|
||||
return right(baseResponse.model);
|
||||
}
|
||||
|
||||
/// 获取用户设备列表
|
||||
Future<Either<HttpError, List<Map<String, dynamic>>>> kr_getUserDevices() async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
|
||||
BaseResponse<dynamic> baseResponse =
|
||||
await HttpUtil.getInstance().request<dynamic>(
|
||||
Api.kr_getUserDevices,
|
||||
data,
|
||||
method: HttpMethod.GET,
|
||||
isShowLoading: false,
|
||||
);
|
||||
|
||||
if (!baseResponse.isSuccess) {
|
||||
return left(
|
||||
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
}
|
||||
|
||||
// 返回设备列表数据
|
||||
try {
|
||||
// 响应格式: { data: { list: [...], total: N } }
|
||||
final responseData = baseResponse.model;
|
||||
final List<Map<String, dynamic>> devices =
|
||||
(responseData['list'] as List)
|
||||
.map((item) => item as Map<String, dynamic>)
|
||||
.toList();
|
||||
return right(devices);
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('解析设备列表失败: $e', tag: 'KRUserApi');
|
||||
return left(HttpError(msg: '数据解析失败', code: -1));
|
||||
}
|
||||
}
|
||||
|
||||
/// 解绑用户设备
|
||||
Future<Either<HttpError, void>> kr_unbindUserDevice(String deviceId) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
|
||||
// 将字符串 ID 转换为整数
|
||||
try {
|
||||
data['id'] = int.parse(deviceId);
|
||||
} catch (e) {
|
||||
KRLogUtil.kr_e('设备ID格式错误: $deviceId', tag: 'KRUserApi');
|
||||
return left(HttpError(msg: '设备ID格式错误', code: -1));
|
||||
}
|
||||
|
||||
BaseResponse<dynamic> baseResponse =
|
||||
await HttpUtil.getInstance().request<dynamic>(
|
||||
Api.kr_unbindUserDevice,
|
||||
data,
|
||||
method: HttpMethod.PUT,
|
||||
isShowLoading: true,
|
||||
);
|
||||
|
||||
if (!baseResponse.isSuccess) {
|
||||
return left(
|
||||
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
}
|
||||
|
||||
return right(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,22 +23,14 @@ import '../../common/app_config.dart';
|
||||
import 'package:dio/dio.dart' as dio;
|
||||
|
||||
class KRAuthApi {
|
||||
/// 是否开启了审核开关
|
||||
Future<Either<HttpError, bool>> kr_isRegister(
|
||||
KRLoginType tpye, String account, String? areaCode) async {
|
||||
/// 检查账号是否已注册(仅支持邮箱)
|
||||
Future<Either<HttpError, bool>> kr_isRegister(String email) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
data['account'] = account;
|
||||
|
||||
final deviceId = await KRDeviceUtil().kr_getDeviceId();
|
||||
KRLogUtil.kr_i('设备ID: $deviceId', tag: 'KRAuthApi');
|
||||
data["identifier"] = deviceId;
|
||||
data['email'] = email;
|
||||
|
||||
data["user_agent"] = _kr_getUserAgent();
|
||||
data["os"] = _kr_getUserAgent();
|
||||
if (areaCode != null) {
|
||||
data['area_code'] = areaCode.toString();
|
||||
}
|
||||
final deviceId = await KRDeviceUtil().kr_getDeviceId();
|
||||
KRLogUtil.kr_i('设备ID: $deviceId', tag: 'KRAuthApi');
|
||||
data["identifier"] = deviceId;
|
||||
|
||||
BaseResponse<KRIsRegister> baseResponse = await HttpUtil.getInstance()
|
||||
.request<KRIsRegister>(Api.kr_isRegister, data,
|
||||
@@ -52,29 +44,26 @@ class KRAuthApi {
|
||||
return right(baseResponse.model.kr_isRegister);
|
||||
}
|
||||
|
||||
/// 注册
|
||||
/// 注册(仅支持邮箱+密码,验证码和邀请码可选)
|
||||
Future<Either<HttpError, String>> kr_register(
|
||||
KRLoginType tpye,
|
||||
String account,
|
||||
String? areaCode,
|
||||
String? code,
|
||||
String? password,
|
||||
{String? inviteCode}) async {
|
||||
String email,
|
||||
String password,
|
||||
{String? code,
|
||||
String? inviteCode}) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
data['account'] = account;
|
||||
data['email'] = email;
|
||||
data['password'] = password;
|
||||
data["code"] = code;
|
||||
data["identifier"] = await KRDeviceUtil().kr_getDeviceId();
|
||||
data["os"] = _kr_getUserAgent();
|
||||
|
||||
// 验证码是可选的,只有在提供时才发送
|
||||
if (code != null && code.isNotEmpty) {
|
||||
data["code"] = code;
|
||||
}
|
||||
|
||||
// 邀请码是可选的
|
||||
if (inviteCode != null && inviteCode.isNotEmpty) {
|
||||
data["invite"] = inviteCode;
|
||||
}
|
||||
data["user_agent"] = _kr_getUserAgent();
|
||||
if (tpye == KRLoginType.kr_telephone) {
|
||||
data['area_code'] = areaCode;
|
||||
}
|
||||
|
||||
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
|
||||
.request<KRLoginData>(Api.kr_register, data,
|
||||
@@ -87,20 +76,14 @@ class KRAuthApi {
|
||||
return right(baseResponse.model.kr_token.toString());
|
||||
}
|
||||
|
||||
/// 验证验证码
|
||||
Future<Either<HttpError, bool>> kr_checkVerificationCode( KRLoginType tpye,
|
||||
String account, String? areaCode, String code, int type) async {
|
||||
|
||||
/// 验证验证码(仅支持邮箱)
|
||||
Future<Either<HttpError, bool>> kr_checkVerificationCode(
|
||||
String email, String code, int type) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
if(tpye == KRLoginType.kr_telephone){
|
||||
data['account'] = areaCode.toString() + account;
|
||||
|
||||
}else{
|
||||
data['account'] = account;
|
||||
}
|
||||
data['email'] = email;
|
||||
data['code'] = code;
|
||||
data['type'] = type;
|
||||
|
||||
BaseResponse<KRIsRegister> baseResponse = await HttpUtil.getInstance()
|
||||
.request<KRIsRegister>(Api.kr_checkVerificationCode, data,
|
||||
method: HttpMethod.POST, isShowLoading: true);
|
||||
@@ -108,37 +91,23 @@ class KRAuthApi {
|
||||
return left(
|
||||
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
}
|
||||
if(baseResponse.model.kr_isRegister){
|
||||
if (baseResponse.model.kr_isRegister) {
|
||||
return right(true);
|
||||
}else{
|
||||
} else {
|
||||
return left(HttpError(msg: "error.70001".tr, code: 70001));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// 登陆
|
||||
Future<Either<HttpError, String>> kr_login(KRLoginType tpye, bool isPsd,
|
||||
String account, String? areaCode, String? code, String? password) async {
|
||||
/// 登录(仅支持邮箱+密码)
|
||||
Future<Either<HttpError, String>> kr_login(
|
||||
String email, String password) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
data['account'] = account;
|
||||
data['email'] = email;
|
||||
data['password'] = password;
|
||||
|
||||
|
||||
final deviceId = await KRDeviceUtil().kr_getDeviceId();
|
||||
final deviceId = await KRDeviceUtil().kr_getDeviceId();
|
||||
KRLogUtil.kr_i('设备ID: $deviceId', tag: 'KRAuthApi');
|
||||
data["identifier"] = deviceId;
|
||||
data["user_agent"] = _kr_getUserAgent();
|
||||
data["os"] = _kr_getUserAgent();
|
||||
if (tpye == KRLoginType.kr_telephone) {
|
||||
data['area_code'] = areaCode;
|
||||
}
|
||||
|
||||
if (isPsd) {
|
||||
data['password'] = password;
|
||||
} else {
|
||||
data["code"] = code;
|
||||
}
|
||||
data["identifier"] = deviceId;
|
||||
|
||||
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
|
||||
.request<KRLoginData>(Api.kr_login, data,
|
||||
@@ -151,45 +120,30 @@ class KRAuthApi {
|
||||
return right(baseResponse.model.kr_token.toString());
|
||||
}
|
||||
|
||||
/// 发送验证码 type 1 注册 其他 2
|
||||
Future<Either<HttpError, bool>> kr_sendCode(
|
||||
KRLoginType tpye, String account, String? areaCode, int type) async {
|
||||
/// 发送验证码(仅支持邮箱)
|
||||
/// type: 1=登录, 2=注册, 3=重置密码
|
||||
Future<Either<HttpError, bool>> kr_sendCode(String email, int type) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
|
||||
if (tpye == KRLoginType.kr_email) {
|
||||
data['email'] = account;
|
||||
} else {
|
||||
data['telephone'] = account;
|
||||
data['telephone_area_code'] = areaCode.toString();
|
||||
}
|
||||
data['email'] = email;
|
||||
data['type'] = type;
|
||||
|
||||
BaseResponse<dynamic> baseResponse = await HttpUtil.getInstance()
|
||||
.request<dynamic>(
|
||||
tpye == KRLoginType.kr_email
|
||||
? Api.kr_sendEmailCode
|
||||
: Api.kr_sendPhoneCode,
|
||||
data,
|
||||
method: HttpMethod.POST,
|
||||
isShowLoading: true);
|
||||
.request<dynamic>(Api.kr_sendCode, data,
|
||||
method: HttpMethod.POST, isShowLoading: true);
|
||||
if (!baseResponse.isSuccess) {
|
||||
return left(
|
||||
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
|
||||
}
|
||||
|
||||
// KRCommonUtil.kr_showToast(baseResponse.model.toString());
|
||||
// KRIsRegister model = (baseResponse..model) as KRIsRegister;
|
||||
return right(true);
|
||||
}
|
||||
|
||||
/// 删除账号
|
||||
Future<Either<HttpError, String>> kr_deleteAccount(KRLoginType tpye,
|
||||
String code) async {
|
||||
Future<Either<HttpError, String>> kr_deleteAccount(String code) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
|
||||
data['code'] = code;
|
||||
|
||||
BaseResponse<dynamic> baseResponse = await HttpUtil.getInstance()
|
||||
|
||||
BaseResponse<dynamic> baseResponse = await HttpUtil.getInstance()
|
||||
.request<dynamic>(Api.kr_deleteAccount, data,
|
||||
method: HttpMethod.DELETE, isShowLoading: true);
|
||||
if (!baseResponse.isSuccess) {
|
||||
@@ -198,23 +152,16 @@ class KRAuthApi {
|
||||
}
|
||||
|
||||
return right("");
|
||||
|
||||
}
|
||||
|
||||
/// 忘记密码-设置新密码
|
||||
Future<Either<HttpError, String>> kr_setNewPsdByForgetPsd(KRLoginType tpye,
|
||||
String account, String? areaCode, String? code, String? password) async {
|
||||
/// 忘记密码-设置新密码(仅支持邮箱)
|
||||
Future<Either<HttpError, String>> kr_setNewPsdByForgetPsd(
|
||||
String email, String code, String password) async {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['method'] = tpye.value;
|
||||
data['account'] = account;
|
||||
data['email'] = email;
|
||||
data['password'] = password;
|
||||
data["code"] = code;
|
||||
data["identifier"] = await KRDeviceUtil().kr_getDeviceId();
|
||||
data["user_agent"] = _kr_getUserAgent();
|
||||
data["os"] = _kr_getUserAgent();
|
||||
if (tpye == KRLoginType.kr_telephone) {
|
||||
data['area_code'] = areaCode;
|
||||
}
|
||||
data["identifier"] = await KRDeviceUtil().kr_getDeviceId();
|
||||
|
||||
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
|
||||
.request<KRLoginData>(Api.kr_setNewPsdByForgetPsd, data,
|
||||
|
||||
@@ -21,6 +21,11 @@ class KRAnnouncementService {
|
||||
|
||||
KRAnnouncementService._internal();
|
||||
|
||||
// 重置公告显示状态(用于退出登录时)
|
||||
void kr_reset() {
|
||||
_kr_hasShownAnnouncement = false;
|
||||
}
|
||||
|
||||
// 检查是否需要显示公告弹窗
|
||||
Future<void> kr_checkAnnouncement() async {
|
||||
if (_kr_hasShownAnnouncement) {
|
||||
|
||||
@@ -72,6 +72,9 @@ class KRSubscribeService {
|
||||
/// 是否处于试用状态
|
||||
final RxBool kr_isTrial = false.obs;
|
||||
|
||||
/// 当前节点列表是否包含试用节点
|
||||
final RxBool kr_hasTrialNodes = false.obs;
|
||||
|
||||
/// 订阅记录
|
||||
final RxList<KRAlreadySubscribe> kr_alreadySubscribe =
|
||||
<KRAlreadySubscribe>[].obs;
|
||||
@@ -247,9 +250,13 @@ class KRSubscribeService {
|
||||
result.fold((error) {
|
||||
kr_currentStatus.value = KRSubscribeServiceStatus.kr_error;
|
||||
}, (nodes) {
|
||||
// 处理节点列表
|
||||
// 记录当前节点列表是否包含试用节点
|
||||
kr_hasTrialNodes.value = nodes.isTryOut;
|
||||
KRLogUtil.kr_i('切换订阅 - 节点列表包含试用节点: ${kr_hasTrialNodes.value}', tag: 'SubscribeService');
|
||||
|
||||
// 处理节点列表(不使用分组)
|
||||
final listModel = KrOutboundsList();
|
||||
listModel.processOutboundItems(nodes.list, kr_nodeGroups);
|
||||
listModel.processOutboundItems(nodes.list, []);
|
||||
|
||||
// 更新UI数据
|
||||
groupOutboundList.value = listModel.groupOutboundList;
|
||||
@@ -277,24 +284,45 @@ class KRSubscribeService {
|
||||
_kr_trialTimer?.cancel();
|
||||
_kr_subscriptionTimer?.cancel();
|
||||
|
||||
// 检查试用状态
|
||||
final bool kr_isSubscribed = kr_currentSubscribe.value != null &&
|
||||
kr_alreadySubscribe.any((subscribe) =>
|
||||
kr_currentSubscribe.value?.id == subscribe.userSubscribeId);
|
||||
if (kr_currentSubscribe.value == null) {
|
||||
kr_isTrial.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('当前订阅状态: ${kr_isSubscribed ? "已订阅" : "未订阅"}',
|
||||
tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('当前订阅ID: ${kr_currentSubscribe.value?.id}',
|
||||
tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i(
|
||||
'已订阅记录: ${kr_alreadySubscribe.map((s) => s.userSubscribeId).join(', ')}',
|
||||
tag: 'SubscribeService');
|
||||
// 优先使用 API 返回的 isTryOut 字段判断试用状态
|
||||
final currentSubscribe = kr_currentSubscribe.value!;
|
||||
|
||||
// 设置试用状态
|
||||
kr_isTrial.value = kr_currentSubscribe.value != null && !kr_isSubscribed;
|
||||
// 1. 优先使用 API 返回的 isTryOut 字段
|
||||
kr_isTrial.value = currentSubscribe.isTryOut;
|
||||
KRLogUtil.kr_i('步骤1 - API isTryOut 字段: ${currentSubscribe.isTryOut}', tag: 'SubscribeService');
|
||||
|
||||
KRLogUtil.kr_i('试用状态: ${kr_isTrial.value ? "是" : "否"}',
|
||||
tag: 'SubscribeService');
|
||||
// 2. 如果 API 说不是试用,检查是否有购买记录
|
||||
if (!kr_isTrial.value) {
|
||||
final bool kr_isSubscribed = kr_alreadySubscribe.any(
|
||||
(subscribe) => currentSubscribe.id == subscribe.userSubscribeId
|
||||
);
|
||||
KRLogUtil.kr_i('步骤2 - 检查购买记录: $kr_isSubscribed', tag: 'SubscribeService');
|
||||
|
||||
// 如果没有购买记录,判断为试用
|
||||
if (!kr_isSubscribed) {
|
||||
kr_isTrial.value = true;
|
||||
KRLogUtil.kr_i('步骤2 - 没有购买记录,判定为试用', tag: 'SubscribeService');
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 最后检查订阅名称是否包含"试用"关键字(最后的备用方案)
|
||||
if (!kr_isTrial.value && currentSubscribe.name.contains('试用')) {
|
||||
kr_isTrial.value = true;
|
||||
KRLogUtil.kr_i('步骤3 - 订阅名称包含"试用"关键字,判定为试用', tag: 'SubscribeService');
|
||||
}
|
||||
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('当前订阅: ${currentSubscribe.name}(${currentSubscribe.id})', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('API isTryOut: ${currentSubscribe.isTryOut}', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('已订阅记录数: ${kr_alreadySubscribe.length}', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('已订阅ID列表: ${kr_alreadySubscribe.map((s) => s.userSubscribeId).join(', ')}', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('✅ 最终试用状态: ${kr_isTrial.value ? "试用" : "付费"}', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SubscribeService');
|
||||
|
||||
if (kr_isTrial.value) {
|
||||
// 启动试用倒计时
|
||||
@@ -445,15 +473,10 @@ class KRSubscribeService {
|
||||
},
|
||||
);
|
||||
|
||||
final result = await kr_subscribeApi.kr_nodeGroupList();
|
||||
result.fold(
|
||||
(error) {
|
||||
throw Exception('获取节点分组失败: ${error.msg}');
|
||||
},
|
||||
(groups) {
|
||||
kr_nodeGroups.value = groups;
|
||||
},
|
||||
);
|
||||
// 🔧 取消节点分组的概念,不再调用 kr_nodeGroupList
|
||||
// 直接使用节点列表,通过 is_try_out 字段区分免费/付费节点
|
||||
kr_nodeGroups.clear();
|
||||
KRLogUtil.kr_i('已取消节点分组,将直接使用节点列表', tag: 'SubscribeService');
|
||||
|
||||
// 保存当前选中的订阅名称
|
||||
final currentSubscribeID = kr_currentSubscribe.value?.id;
|
||||
@@ -502,9 +525,26 @@ class KRSubscribeService {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 如果没有找到之前的订阅,优先选择已购买的套餐(非试用)
|
||||
// 2. 如果没有找到之前的订阅,优先选择试用套餐
|
||||
if (selectedSubscribe == null) {
|
||||
KRLogUtil.kr_i('开始查找已购买的套餐...', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('开始查找试用套餐...', tag: 'SubscribeService');
|
||||
|
||||
for (var subscribe in subscribes) {
|
||||
KRLogUtil.kr_i('检查订阅: ${subscribe.name}(${subscribe.id}), 是否试用: ${subscribe.isTryOut}',
|
||||
tag: 'SubscribeService');
|
||||
|
||||
if (subscribe.isTryOut) {
|
||||
selectedSubscribe = subscribe;
|
||||
KRLogUtil.kr_i('✅ 找到试用套餐,默认选择: ${selectedSubscribe.name}',
|
||||
tag: 'SubscribeService');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 如果没有试用套餐,选择已购买的套餐(非试用)
|
||||
if (selectedSubscribe == null) {
|
||||
KRLogUtil.kr_i('没有试用套餐,查找已购买的套餐...', tag: 'SubscribeService');
|
||||
KRLogUtil.kr_i('已订阅记录: ${kr_alreadySubscribe.map((s) => s.userSubscribeId).join(', ')}',
|
||||
tag: 'SubscribeService');
|
||||
|
||||
@@ -524,10 +564,10 @@ class KRSubscribeService {
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 如果没有已购买的套餐,选择第一个(可能是试用套餐)
|
||||
// 4. 如果都没有找到,选择第一个
|
||||
if (selectedSubscribe == null) {
|
||||
selectedSubscribe = subscribes.first;
|
||||
KRLogUtil.kr_i('没有已购买的套餐,选择第一个: ${selectedSubscribe.name}',
|
||||
KRLogUtil.kr_i('没有找到匹配的套餐,选择第一个: ${selectedSubscribe.name}',
|
||||
tag: 'SubscribeService');
|
||||
}
|
||||
|
||||
@@ -545,9 +585,13 @@ class KRSubscribeService {
|
||||
(nodes) => nodes,
|
||||
);
|
||||
|
||||
// 处理节点列表
|
||||
// 记录当前节点列表是否包含试用节点
|
||||
kr_hasTrialNodes.value = nodes.isTryOut;
|
||||
KRLogUtil.kr_i('节点列表包含试用节点: ${kr_hasTrialNodes.value}', tag: 'SubscribeService');
|
||||
|
||||
// 处理节点列表(不使用分组)
|
||||
final listModel = KrOutboundsList();
|
||||
listModel.processOutboundItems(nodes.list, kr_nodeGroups);
|
||||
listModel.processOutboundItems(nodes.list, []);
|
||||
|
||||
// 更新UI数据
|
||||
groupOutboundList.value = listModel.groupOutboundList;
|
||||
@@ -596,6 +640,7 @@ class KRSubscribeService {
|
||||
Future<void> kr_clearCutNodeData() async {
|
||||
kr_isLastDayOfSubscription.value = false;
|
||||
kr_isTrial.value = false;
|
||||
kr_hasTrialNodes.value = false;
|
||||
|
||||
kr_subscriptionRemainingTime.value = '';
|
||||
kr_trialRemainingTime.value = '';
|
||||
@@ -618,4 +663,45 @@ class KRSubscribeService {
|
||||
/// 获取当前订阅
|
||||
KRUserAvailableSubscribeItem? get kr_getCurrentSubscribe =>
|
||||
kr_currentSubscribe.value;
|
||||
|
||||
/// 获取免费节点列表(试用节点)
|
||||
/// 当试用结束时,返回空列表
|
||||
List<KROutboundItem> get kr_freeNodes {
|
||||
if (!kr_hasTrialNodes.value) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 如果当前是试用状态或有试用节点,返回所有节点作为免费节点
|
||||
// 如果试用已结束(kr_isTrial=false 且 kr_hasTrialNodes=true),返回空列表
|
||||
if (kr_isTrial.value) {
|
||||
KRLogUtil.kr_i('返回免费节点: ${allList.length} 个', tag: 'SubscribeService');
|
||||
return allList.toList();
|
||||
} else {
|
||||
KRLogUtil.kr_i('试用已结束,不显示免费节点', tag: 'SubscribeService');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取付费节点列表
|
||||
/// 如果当前不是试用,返回所有节点
|
||||
/// 如果当前是试用,返回空列表
|
||||
List<KROutboundItem> get kr_paidNodes {
|
||||
if (kr_isTrial.value) {
|
||||
KRLogUtil.kr_i('当前是试用状态,不显示付费节点', tag: 'SubscribeService');
|
||||
return [];
|
||||
} else {
|
||||
KRLogUtil.kr_i('返回付费节点: ${allList.length} 个', tag: 'SubscribeService');
|
||||
return allList.toList();
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否应该显示免费标签页
|
||||
bool get kr_shouldShowFreeTab {
|
||||
return kr_hasTrialNodes.value && kr_isTrial.value;
|
||||
}
|
||||
|
||||
/// 是否应该显示付费标签页
|
||||
bool get kr_shouldShowPaidTab {
|
||||
return !kr_isTrial.value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user