didvan-app/lib/models/home_page_content/swot.dart

115 lines
3.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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` می‌آید.
/// امتیازهای محور X و Y مستقیما از `metadata.x1`/`metadata.y1` خوانده
/// می‌شوند (افق ۱ ساله — وزن‌دار شده در swot-service). اگر متادیتا خالی بود
/// (محتوای legacy)، به parse جدول قدیمی fallback می‌شود.
factory SwotItem.fromContentItem(ContentItem item) {
// widget قدیمی با type == "THREAT" (uppercase) چک می‌کند.
final isThreat = (item.metaType ?? '').toLowerCase() == 'threat';
final type = isThreat ? 'THREAT' : 'OPPORTUNITY';
double x1 = item.metaScoreX1;
double y1 = item.metaScoreY1;
if (x1 == 0 && y1 == 0) {
final fallback = _extractScores(item.body);
x1 = fallback.$1;
y1 = fallback.$2;
}
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);
}
}