App启动 → 设备登录 → 保存Token → 进入主页
后续打开:
App启动 → 检测本地Token → Token有效 → 自动登录 → 进入主页
↓
Token失效/无效 → 自动设备登录 → 更新Token → 进入主页
333 lines
9.5 KiB
Dart
Executable File
333 lines
9.5 KiB
Dart
Executable File
import 'dart:convert';
|
||
|
||
import 'package:get/get_connect/http/src/utils/utils.dart';
|
||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||
|
||
import '../../utils/kr_common_util.dart';
|
||
|
||
class KRDescription {
|
||
final List<KRFeature> kr_features;
|
||
|
||
KRDescription({
|
||
required this.kr_features,
|
||
});
|
||
|
||
factory KRDescription.fromJson(Map<String, dynamic> json) {
|
||
return KRDescription(
|
||
kr_features: (json['features'] as List?)
|
||
?.map((e) => KRFeature.fromJson(e as Map<String, dynamic>))
|
||
.toList() ?? [],
|
||
);
|
||
}
|
||
}
|
||
|
||
class KRFeature {
|
||
final String kr_label;
|
||
final String kr_type;
|
||
final List<KRFeatureDetail> kr_details;
|
||
|
||
KRFeature({
|
||
required this.kr_label,
|
||
required this.kr_type,
|
||
required this.kr_details,
|
||
});
|
||
|
||
factory KRFeature.fromJson(Map<String, dynamic> json) {
|
||
return KRFeature(
|
||
kr_label: json['label'] as String,
|
||
kr_type: json['type'] as String,
|
||
kr_details: (json['details'] as List)
|
||
.map((e) => KRFeatureDetail.fromJson(e as Map<String, dynamic>))
|
||
.toList(),
|
||
);
|
||
}
|
||
}
|
||
|
||
class KRFeatureDetail {
|
||
final String kr_label;
|
||
final String kr_description;
|
||
|
||
KRFeatureDetail({
|
||
required this.kr_label,
|
||
required this.kr_description,
|
||
});
|
||
|
||
factory KRFeatureDetail.fromJson(Map<String, dynamic> json) {
|
||
return KRFeatureDetail(
|
||
kr_label: json['label'] as String,
|
||
kr_description: json['description'] as String,
|
||
);
|
||
}
|
||
}
|
||
|
||
class KRPackageList {
|
||
final List<KRPackageListItem> kr_list;
|
||
final int kr_total;
|
||
|
||
KRPackageList({required this.kr_list, required this.kr_total});
|
||
|
||
// 获取所有不同的时间单位
|
||
List<String> kr_getUniqueUnitTimes() {
|
||
return kr_list.map((item) => item.kr_unitTime).toSet().toList();
|
||
}
|
||
|
||
// 根据时间单位获取套餐列表
|
||
List<KRPackageListItem> kr_getPackagesByUnitTime(String unitTime) {
|
||
return kr_list.where((item) => item.kr_unitTime == unitTime).toList();
|
||
}
|
||
|
||
// 检查是否有多个时间单位
|
||
bool kr_hasMultipleUnitTimes() {
|
||
return kr_getUniqueUnitTimes().length > 1;
|
||
}
|
||
|
||
factory KRPackageList.fromJson(Map<String, dynamic> json) {
|
||
return KRPackageList(
|
||
kr_list: (json['list'] as List? ?? [])
|
||
.map((item) => KRPackageListItem.fromJson(item))
|
||
.toList(),
|
||
kr_total: json['total']);
|
||
}
|
||
}
|
||
|
||
class KRPackageListItem {
|
||
// 包的唯一标识符
|
||
final int kr_id;
|
||
// 包的名称
|
||
final String kr_name;
|
||
// 包的描述信息
|
||
final KRDescription kr_description;
|
||
// 单位价格
|
||
final int kr_unitPrice;
|
||
// 单位时间(例如:月、年)
|
||
final String kr_unitTime;
|
||
// 折扣信息列表
|
||
final List<KRDiscount> kr_discount;
|
||
// 替换费用
|
||
final int kr_replacement;
|
||
// 库存数量
|
||
final int kr_inventory;
|
||
// 流量限制
|
||
final int kr_traffic;
|
||
// 速度限制
|
||
final int kr_speedLimit;
|
||
// 设备限制数量
|
||
final int kr_deviceLimit;
|
||
// 配额
|
||
final int kr_quota;
|
||
// 组ID
|
||
final int kr_groupId;
|
||
// 服务器组(可能为空)
|
||
final dynamic kr_serverGroup;
|
||
// 服务器(可能为空)
|
||
final dynamic kr_server;
|
||
// 是否显示
|
||
final bool kr_show;
|
||
// 是否出售
|
||
final bool kr_sell;
|
||
// 排序顺序
|
||
final int kr_sort;
|
||
// 扣除比例
|
||
final int kr_deductionRatio;
|
||
// 是否允许扣除
|
||
final bool kr_allowDeduction;
|
||
// 重置周期
|
||
final int kr_resetCycle;
|
||
// 是否在续订时重置
|
||
final bool kr_renewalReset;
|
||
// 创建时间戳
|
||
final int kr_createdAt;
|
||
// 更新时间戳
|
||
final int kr_updatedAt;
|
||
|
||
KRPackageListItem({
|
||
required this.kr_id,
|
||
required this.kr_name,
|
||
required this.kr_description,
|
||
required this.kr_unitPrice,
|
||
required this.kr_unitTime,
|
||
required this.kr_discount,
|
||
required this.kr_replacement,
|
||
required this.kr_inventory,
|
||
required this.kr_traffic,
|
||
required this.kr_speedLimit,
|
||
required this.kr_deviceLimit,
|
||
required this.kr_quota,
|
||
required this.kr_groupId,
|
||
this.kr_serverGroup,
|
||
this.kr_server,
|
||
required this.kr_show,
|
||
required this.kr_sell,
|
||
required this.kr_sort,
|
||
required this.kr_deductionRatio,
|
||
required this.kr_allowDeduction,
|
||
required this.kr_resetCycle,
|
||
required this.kr_renewalReset,
|
||
required this.kr_createdAt,
|
||
required this.kr_updatedAt,
|
||
});
|
||
|
||
// 从JSON数据创建KRPackageList实例
|
||
factory KRPackageListItem.fromJson(Map<String, dynamic> json) {
|
||
KRLogUtil.kr_i('json: ${json['traffic'] ?? 0}');
|
||
|
||
|
||
// 获取原始折扣列表
|
||
final List<KRDiscount> originalDiscounts = (json['discount'] as List<dynamic>?)
|
||
?.map((e) => KRDiscount.fromJson(e as Map<String, dynamic>))
|
||
.toList() ?? [];
|
||
|
||
// 创建基础选项(数量为1,折扣为100%)
|
||
final KRDiscount baseDiscount = KRDiscount(
|
||
kr_quantity: 1,
|
||
kr_discount: 100, // 折扣为100%,表示原价
|
||
);
|
||
|
||
// 创建完整的折扣列表,确保基础选项在最后
|
||
final List<KRDiscount> discounts = List.from(originalDiscounts);
|
||
if (!discounts.any((discount) => discount.kr_quantity == 1)) {
|
||
discounts.add(baseDiscount);
|
||
}
|
||
|
||
// 解析描述信息
|
||
final descriptionJson = json['description'];
|
||
KRDescription description;
|
||
if (descriptionJson is String) {
|
||
// 如果是空字符串,直接返回空描述
|
||
if (descriptionJson.isEmpty) {
|
||
description = KRDescription(kr_features: []);
|
||
} else {
|
||
try {
|
||
description = KRDescription.fromJson(jsonDecode(descriptionJson));
|
||
} catch (e) {
|
||
KRLogUtil.kr_e('解析描述信息失败: $e');
|
||
description = KRDescription(kr_features: []);
|
||
}
|
||
}
|
||
} else if (descriptionJson is Map<String, dynamic>) {
|
||
description = KRDescription.fromJson(descriptionJson);
|
||
} else {
|
||
description = KRDescription(kr_features: []);
|
||
}
|
||
|
||
return KRPackageListItem(
|
||
kr_id: json['id'] as int,
|
||
kr_name: json['name'] as String,
|
||
kr_description: description,
|
||
kr_unitPrice: json['unit_price'] ?? 0,
|
||
kr_unitTime: json['unit_time'] as String,
|
||
kr_discount: discounts,
|
||
kr_replacement: json['replacement'] ?? 0,
|
||
kr_inventory: json['inventory'] ?? 0,
|
||
kr_traffic: json['traffic'] ?? 0,
|
||
kr_speedLimit: json['speed_limit'] ?? 0,
|
||
kr_deviceLimit: json['device_limit'] ?? 0,
|
||
kr_quota: json['quota'] ?? 0,
|
||
kr_groupId: json['group_id'] ?? 0,
|
||
kr_serverGroup: json['server_group'],
|
||
kr_server: json['server'],
|
||
kr_show: json['show'] ?? false,
|
||
kr_sell: json['sell'] ?? false,
|
||
kr_sort: json['sort'] ?? 0,
|
||
kr_deductionRatio: json['deduction_ratio'] ?? 0,
|
||
kr_allowDeduction: json['allow_deduction'] ?? false,
|
||
kr_resetCycle: json['reset_cycle'] ?? 0,
|
||
kr_renewalReset: json['renewal_reset'] ?? false,
|
||
kr_createdAt: json['created_at'] ?? 0,
|
||
kr_updatedAt: json['updated_at'] ?? 0,
|
||
);
|
||
}
|
||
|
||
// 获取包含基础选项的完整折扣列表
|
||
List<KRDiscount> kr_getCompleteDiscountList() {
|
||
// 创建基础选项(数量为1,折扣为100%)
|
||
final KRDiscount baseDiscount = KRDiscount(
|
||
kr_quantity: 1,
|
||
kr_discount: 100, // 折扣为100%,表示原价
|
||
);
|
||
|
||
// 如果原始折扣列表为空,返回只包含基础选项的列表
|
||
if (kr_discount.isEmpty) {
|
||
return [baseDiscount];
|
||
}
|
||
|
||
// 检查是否已存在数量为1的折扣
|
||
final bool hasBaseDiscount = kr_discount.any((discount) => discount.kr_quantity == 1);
|
||
|
||
// 创建新的列表,包含所有原始折扣
|
||
final List<KRDiscount> completeList = List.from(kr_discount);
|
||
|
||
// 如果没有数量为1的折扣,添加基础选项到列表末尾
|
||
if (!hasBaseDiscount) {
|
||
completeList.add(baseDiscount);
|
||
}
|
||
|
||
// 按数量排序
|
||
completeList.sort((a, b) => a.kr_quantity.compareTo(b.kr_quantity));
|
||
|
||
return completeList;
|
||
}
|
||
|
||
// 获取折扣后的价格
|
||
double kr_getDiscountedPrice() {
|
||
if (kr_discount.isEmpty) return kr_unitPrice / 100.0;
|
||
final maxDiscount = kr_discount.reduce((a, b) => a.kr_discount > b.kr_discount ? a : b);
|
||
return (kr_unitPrice / 100.0) * (maxDiscount.kr_discount / 100.0);
|
||
}
|
||
|
||
// 获取折扣显示文本
|
||
String kr_getDiscountDisplay() {
|
||
if (kr_discount.isEmpty) return '';
|
||
final maxDiscount = kr_discount.reduce((a, b) => a.kr_discount > b.kr_discount ? a : b);
|
||
return '${(maxDiscount.kr_discount / 10).toStringAsFixed(1)}折';
|
||
}
|
||
|
||
// 获取最大折扣
|
||
KRDiscount? kr_getMaxDiscount() {
|
||
if (kr_discount.isEmpty) return null;
|
||
return kr_discount.reduce((a, b) =>
|
||
a.kr_discount > b.kr_discount ? a : b);
|
||
}
|
||
|
||
|
||
|
||
// 格式化价格显示(保留两位小数)
|
||
String kr_formatPrice(double price) {
|
||
return price.toStringAsFixed(2);
|
||
}
|
||
|
||
// 获取套餐描述
|
||
String kr_getPackageDescription() {
|
||
if (kr_discount.isEmpty) {
|
||
return '${kr_name} - ${kr_unitPrice / 100.0}元/${kr_unitTime}';
|
||
}
|
||
final maxDiscount = kr_discount.reduce((a, b) => a.kr_discount > b.kr_discount ? a : b);
|
||
return '${kr_name} - ${kr_getDiscountedPrice()}元/${kr_unitTime}';
|
||
}
|
||
}
|
||
|
||
class KRDiscount {
|
||
// 折扣数量
|
||
final int kr_quantity;
|
||
// 折扣百分比
|
||
final int kr_discount;
|
||
|
||
KRDiscount({
|
||
required this.kr_quantity,
|
||
required this.kr_discount,
|
||
});
|
||
|
||
// 从JSON数据创建KRDiscount实例
|
||
factory KRDiscount.fromJson(Map<String, dynamic> json) {
|
||
// 确保折扣值在 0-100 之间
|
||
int discount = json['discount'] ?? 100;
|
||
if (discount < 0) discount = 0;
|
||
if (discount > 100) discount = 100;
|
||
|
||
return KRDiscount(
|
||
kr_quantity: json['quantity'] ?? 1,
|
||
kr_discount: discount,
|
||
);
|
||
}
|
||
}
|