109 lines
3.7 KiB
Dart
109 lines
3.7 KiB
Dart
import 'package:didvan/models/content/content_item.dart';
|
|
|
|
class SwotItem {
|
|
final int id;
|
|
final String title;
|
|
final String description;
|
|
final String category;
|
|
final String type;
|
|
final String imageUrl;
|
|
final double x1;
|
|
final double y1;
|
|
final String createdAt;
|
|
|
|
/// uuid اصلی content-service (در محتوای جدید). در دادهی قدیمی null است.
|
|
final String? keycloakId;
|
|
|
|
SwotItem({
|
|
required this.id,
|
|
required this.title,
|
|
required this.description,
|
|
required this.category,
|
|
required this.type,
|
|
required this.imageUrl,
|
|
required this.x1,
|
|
required this.y1,
|
|
required this.createdAt,
|
|
this.keycloakId,
|
|
});
|
|
|
|
factory SwotItem.fromJson(Map<String, dynamic> json) {
|
|
return SwotItem(
|
|
id: json['id'],
|
|
title: json['title'],
|
|
description: json['description'],
|
|
category: json['category'],
|
|
type: json['type'],
|
|
imageUrl: json["url"],
|
|
x1: json["scoreX1"],
|
|
y1: json["scoreY1"],
|
|
createdAt: json["createdAt"]
|
|
);
|
|
}
|
|
|
|
/// ساختن SwotItem از ContentItem (دستهی «فرصت و تهدید» در content-service).
|
|
/// نوع (opportunity/threat) از `metadata.type` میآید.
|
|
/// عدد (x1, y1) از جدولِ امتیازات در body محاسبه میشود:
|
|
/// - میانگین ستونِ «۷ سال» برای سطرهای محور X → x1
|
|
/// - میانگین ستونِ «۷ سال» برای سطرهای محور Y → y1
|
|
factory SwotItem.fromContentItem(ContentItem item) {
|
|
// widget قدیمی با type == "THREAT" (uppercase) چک میکند.
|
|
final isThreat = (item.metaType ?? '').toLowerCase() == 'threat';
|
|
final type = isThreat ? 'THREAT' : 'OPPORTUNITY';
|
|
|
|
final (x1, y1) = _extractScores(item.body);
|
|
|
|
return SwotItem(
|
|
id: item.id.hashCode,
|
|
keycloakId: item.id,
|
|
title: item.title,
|
|
description: item.summary ?? '',
|
|
category: item.category?.name ?? 'فرصت و تهدید',
|
|
type: type,
|
|
imageUrl: item.coverImage ?? '',
|
|
x1: x1,
|
|
y1: y1,
|
|
createdAt: item.publishedAt?.toIso8601String() ?? '',
|
|
);
|
|
}
|
|
|
|
/// در body یک بلوک table پیدا میکند و میانگینِ ستونِ آخر را برای محورهای
|
|
/// X و Y برمیگرداند. اگر چیزی پیدا نشد، 0 برمیگرداند.
|
|
static (double, double) _extractScores(dynamic body) {
|
|
try {
|
|
if (body is! Map) return (0.0, 0.0);
|
|
final blocks = body['blocks'];
|
|
if (blocks is! List) return (0.0, 0.0);
|
|
for (final block in blocks) {
|
|
if (block is! Map) continue;
|
|
if (block['type'] != 'table') continue;
|
|
final data = block['data'];
|
|
if (data is! Map) continue;
|
|
final content = data['content'];
|
|
if (content is! List || content.isEmpty) continue;
|
|
// ستونِ آخر = آخرین مقدار در آرایهی هر سطر.
|
|
double xSum = 0, ySum = 0;
|
|
int xCount = 0, yCount = 0;
|
|
for (var i = 1; i < content.length; i++) {
|
|
final row = content[i];
|
|
if (row is! List || row.length < 3) continue;
|
|
final axis = row[1]?.toString().toUpperCase().trim();
|
|
final last = row.last?.toString().trim();
|
|
final val = double.tryParse(last ?? '');
|
|
if (val == null) continue;
|
|
if (axis == 'X') {
|
|
xSum += val;
|
|
xCount++;
|
|
} else if (axis == 'Y') {
|
|
ySum += val;
|
|
yCount++;
|
|
}
|
|
}
|
|
final x1 = xCount > 0 ? xSum / xCount : 0.0;
|
|
final y1 = yCount > 0 ? ySum / yCount : 0.0;
|
|
return (x1, y1);
|
|
}
|
|
} catch (_) {}
|
|
return (0.0, 0.0);
|
|
}
|
|
} |