4 changed files with 364 additions and 247 deletions
@ -0,0 +1,169 @@ |
|||||||
|
import 'package:excel/excel.dart'; |
||||||
|
|
||||||
|
class RelationshipCalculatorService { |
||||||
|
final Map<String, bool> _columnRedStates = {}; |
||||||
|
final List<List<String>> _aspects = []; // Stores [conjunction, opposition, square] for each row |
||||||
|
|
||||||
|
static const List<String> zodiacColumns = [ |
||||||
|
'日', |
||||||
|
'月', |
||||||
|
'水', |
||||||
|
'金', |
||||||
|
'火', |
||||||
|
'木', |
||||||
|
'土', |
||||||
|
'天', |
||||||
|
'海', |
||||||
|
'冥', |
||||||
|
'南', |
||||||
|
'北', |
||||||
|
'孛', |
||||||
|
'凯', |
||||||
|
]; |
||||||
|
|
||||||
|
void processEntireSheet(Sheet sheet) { |
||||||
|
_columnRedStates.clear(); |
||||||
|
_aspects.clear(); |
||||||
|
|
||||||
|
for (var rowIndex = 0; rowIndex < sheet.maxRows; rowIndex++) { |
||||||
|
final row = sheet.rows[rowIndex]; |
||||||
|
if (row.isEmpty) continue; |
||||||
|
|
||||||
|
// 跳过所有第一个单元格值为"Date"的行 |
||||||
|
if (row.first?.value?.toString().startsWith('Date') == true) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
_processZodiacColumns(rowIndex, row); |
||||||
|
_calculateCoordinateRelationships(row); |
||||||
|
} |
||||||
|
|
||||||
|
// Add aspect markers to the last three rows |
||||||
|
_addAspectMarkers(sheet); |
||||||
|
} |
||||||
|
|
||||||
|
void _processZodiacColumns(int rowIndex, List<Data?> row) { |
||||||
|
for (int i = 0; i < zodiacColumns.length; i++) { |
||||||
|
final columnTitle = zodiacColumns[i]; |
||||||
|
final dataColumnIndex = 4 + (i * 2) + 1; |
||||||
|
|
||||||
|
if (dataColumnIndex >= row.length) continue; |
||||||
|
|
||||||
|
final cell = row[dataColumnIndex]; |
||||||
|
if (cell == null) continue; |
||||||
|
|
||||||
|
final cellValue = cell.value?.toString() ?? ''; |
||||||
|
|
||||||
|
if (cellValue.contains('R')) { |
||||||
|
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.red); |
||||||
|
_columnRedStates[columnTitle] = true; |
||||||
|
} else if (cellValue.contains('D')) { |
||||||
|
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.black); |
||||||
|
_columnRedStates[columnTitle] = false; |
||||||
|
} else if (_columnRedStates[columnTitle] == true) { |
||||||
|
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.red); |
||||||
|
} else { |
||||||
|
cell.cellStyle = CellStyle(fontColorHex: ExcelColor.black); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void _calculateCoordinateRelationships(List<Data?> row) { |
||||||
|
List<int> positionsInMinutes = []; |
||||||
|
List<String> planets = []; |
||||||
|
|
||||||
|
// Extract positions for all planets in minutes |
||||||
|
for (int i = 0; i < zodiacColumns.length; i++) { |
||||||
|
final dataColumnIndex = 4 + (i * 2) + 1; |
||||||
|
if (dataColumnIndex >= row.length) continue; |
||||||
|
|
||||||
|
final cell = row[dataColumnIndex]; |
||||||
|
if (cell == null) continue; |
||||||
|
|
||||||
|
final cellValue = cell.value?.toString() ?? ''; |
||||||
|
final cleanedValue = cellValue.replaceAll(RegExp(r'[RD]'), ''); |
||||||
|
if (cleanedValue.isEmpty) continue; |
||||||
|
|
||||||
|
try { |
||||||
|
final parts = cleanedValue.split('°'); |
||||||
|
if (parts.length != 2) continue; |
||||||
|
|
||||||
|
final degrees = int.parse(parts[0]); |
||||||
|
final minutesPart = parts[1].split('\''); |
||||||
|
final minutes = minutesPart.isNotEmpty ? int.parse(minutesPart[0]) : 0; |
||||||
|
|
||||||
|
positionsInMinutes.add(degrees * 60 + minutes); |
||||||
|
planets.add(zodiacColumns[i]); |
||||||
|
} catch (e) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Calculate aspects |
||||||
|
List<String> conjunctions = []; |
||||||
|
List<String> oppositions = []; |
||||||
|
List<String> squares = []; |
||||||
|
|
||||||
|
for (int i = 0; i < positionsInMinutes.length; i++) { |
||||||
|
for (int j = i + 1; j < positionsInMinutes.length; j++) { |
||||||
|
final diff = (positionsInMinutes[i] - positionsInMinutes[j]).abs(); |
||||||
|
final circularDiff = diff > 10800 ? 21600 - diff : diff; // 360° = 21600 minutes |
||||||
|
|
||||||
|
// Check for conjunction (<60 minutes or 120°±30 minutes) |
||||||
|
if (circularDiff < 60 || (circularDiff >= 7170 && circularDiff <= 7290)) { |
||||||
|
// 119°30' to 120°29' |
||||||
|
|
||||||
|
if (planets[i] == '南' && planets[j] == '北') { |
||||||
|
// 南北合不用显示 |
||||||
|
} else { |
||||||
|
conjunctions.add('${planets[i]}${planets[j]}合'); |
||||||
|
} |
||||||
|
} |
||||||
|
// Check for square (90°±30 minutes) |
||||||
|
else if (circularDiff >= 5370 && circularDiff <= 5490) { |
||||||
|
// 89°30' to 90°29' |
||||||
|
squares.add('${planets[i]}${planets[j]}刑'); |
||||||
|
} |
||||||
|
// Check for opposition (180°±30 minutes) |
||||||
|
else if (circularDiff >= 10770 && circularDiff <= 10890) { |
||||||
|
// 179°30' to 180°29' |
||||||
|
oppositions.add('${planets[i]}${planets[j]}冲'); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
_aspects.add([conjunctions.join(', '), oppositions.join(', '), squares.join(', ')]); |
||||||
|
} |
||||||
|
|
||||||
|
void _addAspectMarkers(Sheet sheet) { |
||||||
|
if (_aspects.isEmpty) return; |
||||||
|
|
||||||
|
// 确定要在哪三列添加数据(最后三列) |
||||||
|
final firstAspectCol = sheet.maxColumns - 3; |
||||||
|
final secondAspectCol = sheet.maxColumns - 2; |
||||||
|
final thirdAspectCol = sheet.maxColumns - 1; |
||||||
|
|
||||||
|
for (int rowIndex = 0; rowIndex < sheet.maxRows; rowIndex++) { |
||||||
|
final row = sheet.rows[rowIndex]; |
||||||
|
if (row.isEmpty || row.first?.value?.toString().startsWith('Date') == true) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// 获取当前行对应的aspect数据 |
||||||
|
int dataIndex = rowIndex - 1; // 假设第一行是标题行 |
||||||
|
if (dataIndex >= 0 && dataIndex < _aspects.length) { |
||||||
|
final aspects = _aspects[dataIndex]; |
||||||
|
|
||||||
|
_setCellValue(sheet, firstAspectCol, rowIndex, aspects[0]); |
||||||
|
_setCellValue(sheet, secondAspectCol, rowIndex, aspects[1]); |
||||||
|
_setCellValue(sheet, thirdAspectCol, rowIndex, aspects[2]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 辅助方法:正确设置单元格值 |
||||||
|
void _setCellValue(Sheet sheet, int col, int row, String value) { |
||||||
|
final cell = sheet.cell(CellIndex.indexByColumnRow(columnIndex: col, rowIndex: row)); |
||||||
|
cell.value = TextCellValue(value); // 使用TextCellValue包装字符串 |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue