|
7 | 7 | @using System.Globalization |
8 | 8 |
|
9 | 9 | <!-- |
10 | | - 1. spendings by category |
11 | | - 2. chart |
| 10 | +1. spendings by category |
| 11 | +2. chart |
12 | 12 | --> |
13 | | -<div class="gtid-table" style="grid-template-columns: auto"> |
| 13 | +<div class="gtid-table" style="grid-template-columns: auto; min-width: 350px;"> |
14 | 14 | <div class="grid-cell"> |
15 | | - <SimplePieChart Data="summary" |
| 15 | + <input type="checkbox" @bind="@chartDataByCat" id="chart_data" /> <label for="chart_data">@(chartDataByCat ? "By Category" : "By Person")</label> |
| 16 | + @if (chartDataByCat) |
| 17 | + { |
| 18 | + <SimplePieChart Data="summary" |
16 | 19 | ColorSequenceGenerator="csg" |
17 | 20 | ShowSubcategories=@true |
18 | 21 | ShowAbsoluteNumbers=@true |
19 | 22 | RenderExtraControls="settings.Show_Debug_UI"> |
20 | | - <ExtraControls> |
21 | | - Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span> |
22 | | - @{ |
23 | | - if (Magic == -1) Magic = (int)(csg.Magic * 1000); |
24 | | - if (Seed == null) Seed = csg.Seed.ToString("#"); |
25 | | - } |
26 | | - <input type="color" @bind-value="@SeedBind"/> |
27 | | - <AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind"/> |
28 | | - </ExtraControls> |
29 | | - </SimplePieChart> |
| 23 | + <ExtraControls> |
| 24 | + Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span> |
| 25 | + @{ |
| 26 | + if (Magic == -1) Magic = (int)(csg.Magic * 1000); |
| 27 | + if (Seed == null) Seed = csg.Seed.ToString("#"); |
| 28 | + } |
| 29 | + <input type="color" @bind-value="@SeedBind"/> |
| 30 | + <AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind"/> |
| 31 | + </ExtraControls> |
| 32 | + </SimplePieChart> |
| 33 | + } else { |
| 34 | + <SimplePieChart Data="summaryByPersons" |
| 35 | + ColorSequenceGenerator="csg" |
| 36 | + ShowSubcategories=@true |
| 37 | + ShowAbsoluteNumbers=@true |
| 38 | + RenderExtraControls="settings.Show_Debug_UI"> |
| 39 | + <ExtraControls> |
| 40 | + Current Seed color: <span style="color: @csg.Seed">@csg.Seed</span> |
| 41 | + @{ |
| 42 | + if (Magic == -1) Magic = (int)(csg.Magic * 1000); |
| 43 | + if (Seed == null) Seed = csg.Seed.ToString("#"); |
| 44 | + } |
| 45 | + <input type="color" @bind-value="@SeedBind" /> |
| 46 | + <AntDesign.InputNumber Size="@InputSize.Small" @bind-Value="MagicBind" /> |
| 47 | + </ExtraControls> |
| 48 | + </SimplePieChart> |
| 49 | + } |
30 | 50 | </div> |
31 | | -<div class="grid-cell"> |
| 51 | + <div class="grid-cell"> |
32 | 52 | @{ |
33 | 53 | var currencies = (Tour?.Currencies?.OrderByDescending(c => c.CurrencyRate) ?? Enumerable.Empty<Currency>()).Select((x, i) => (x, i)).ToArray(); |
34 | 54 | var cLen = currencies.Count(); |
35 | 55 | var currenciesNum = currencies.Length + 1; |
36 | 56 | } |
37 | 57 | <div class="grid-table" style="grid-template-columns: repeat(@currenciesNum,auto)"> |
38 | | - <div class="row"> |
39 | | - <div class="grid-header"> |
40 | | - <Select @bind-Value=@selectedCat |
41 | | - TItemValue="string" |
42 | | - TItem="string" |
43 | | - AllowClear=@true |
44 | | - DataSource=@totalSpentByCat.Keys |
45 | | - IgnoreItemChangesLeadsToException="false" /> |
| 58 | + <div class="row"> |
| 59 | + <div class="grid-header"> |
| 60 | + <Select @bind-Value=@selectedCat |
| 61 | + TItemValue="string" |
| 62 | + TItem="string" |
| 63 | + AllowClear=@true |
| 64 | + DataSource=@totalSpentByCat.Keys |
| 65 | + IgnoreItemChangesLeadsToException="false" /> |
| 66 | + </div> |
| 67 | + @{ |
| 68 | + foreach (var (c, i) in currencies) |
| 69 | + { |
| 70 | + <div class="grid-cell" align="center" style="@(c == Tour?.Currency ? "font-weight: bold; color: green;" : "")">@c.Name</div> |
| 71 | + } |
| 72 | + } |
| 73 | + </div> |
| 74 | + <div class="row"> |
| 75 | + <div class="grid-cell">Total</div> |
| 76 | + @foreach (var (c, i) in currencies) |
| 77 | + { |
| 78 | + var pp = totalSpentByCat[selectedCat]; |
| 79 | + var cc = Tour?.Currency ?? new(); |
| 80 | + var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
| 81 | + var amountInCurrency = pp * rate; |
| 82 | + <div class="grid-cell balance total"> |
| 83 | + <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b> |
| 84 | + @if (Tour?.IsMultiCurrency() ?? false) { |
| 85 | + <span style="font-size: x-small"> @(c.Name)</span> |
| 86 | + } |
46 | 87 | </div> |
47 | | - @{ |
48 | | - foreach (var (c, i) in currencies) |
49 | | - { |
50 | | - <div class="grid-cell" align="center" style="@(c == Tour?.Currency ? "font-weight: bold; color: green;" : "")">@c.Name</div> |
51 | | - } |
52 | | - } |
53 | | - </div> |
54 | | - <div class="row"> |
55 | | - <div class="grid-cell">Total</div> |
56 | | - @foreach (var (c, i) in currencies) |
57 | | - { |
58 | | - var pp = totalSpentByCat[selectedCat]; |
59 | | - var cc = Tour?.Currency ?? new(); |
60 | | - var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
61 | | - var amountInCurrency = pp * rate; |
62 | | - <div class="grid-cell balance total"> |
63 | | - <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b> |
64 | | - @if (Tour?.IsMultiCurrency() ?? false) { |
65 | | - <span style="font-size: x-small"> @(c.Name)</span> |
66 | | - } |
67 | | - </div> |
68 | | - } |
69 | | - </div> |
70 | | - <div class="row"> |
71 | | - <div class="grid-cell">Per Person (@adultPersonWeight w)</div> |
72 | | - @foreach (var (c, i) in currencies) |
73 | | - { |
74 | | - var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]); |
75 | | - var cc = Tour?.Currency ?? new(); |
76 | | - var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
77 | | - var amountInCurrency = pp * rate; |
78 | | - <div class="grid-cell balance"> |
79 | | - <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b> |
80 | | - @if (Tour?.IsMultiCurrency() ?? false) { |
81 | | - <span style="font-size: x-small"> @(c.Name)</span> |
82 | | - } |
83 | | - </div> |
84 | | - } |
85 | | - </div> |
86 | | - <div class="row"> |
87 | | - <div class="grid-cell"> |
88 | | - Per Day: <input type="number" @bind-value="duration" min="1" max="50"/> |
89 | | - |
| 88 | + } |
90 | 89 | </div> |
91 | | - @foreach (var (c, i) in currencies) |
92 | | - { |
93 | | - var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]); |
94 | | - var cc = Tour?.Currency ?? new(); |
95 | | - var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
96 | | - var amountInCurrency = pp * rate / (duration == 0 ? 1 : duration); |
97 | | - <div class="grid-cell balance"> |
98 | | - <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated)) </b> |
99 | | - @if (Tour?.IsMultiCurrency() ?? false) { |
100 | | - <span style="font-size: x-small"> @(c.Name)</span> |
101 | | - } |
102 | | - </div> |
103 | | - } |
104 | | - </div> |
105 | | - @if (Tour.IsMultiCurrency()) |
| 90 | + <div class="row"> |
| 91 | + <div class="grid-cell">Per Person (@adultPersonWeight w)</div> |
| 92 | + @foreach (var (c, i) in currencies) |
106 | 93 | { |
107 | | - <div class="row"> |
108 | | - <div class="grid-cell"> |
109 | | - Currency: <b style='color: green'>@Tour?.Currency?.Name</b> |
110 | | - </div> |
111 | | - @foreach (var (c, i) in currencies) |
112 | | - { |
113 | | - var cc = Tour?.Currency ?? new (); |
114 | | - var rate = cc.CurrencyRate > c.CurrencyRate ? cc.CurrencyRate * 1.0 / c.CurrencyRate : c.CurrencyRate * 1.0 / cc.CurrencyRate; |
115 | | - var (fc, sc) = cc.CurrencyRate > c.CurrencyRate ? (cc, c) : (c, cc); |
116 | | - <div class="grid-cell"> |
117 | | - @if (cc != c) |
118 | | - { |
119 | | - <span style="font-size: x-small"><b style="@(fc == cc ? "color:green" : "")">@fc.Name</b> / <b style="@(sc == cc ? "color:green" : "")">@sc.Name:</b> @($"{rate:#.00}")</span> |
120 | | - } |
121 | | - </div> |
| 94 | + var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]); |
| 95 | + var cc = Tour?.Currency ?? new(); |
| 96 | + var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
| 97 | + var amountInCurrency = pp * rate; |
| 98 | + <div class="grid-cell balance"> |
| 99 | + <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated))</b> |
| 100 | + @if (Tour?.IsMultiCurrency() ?? false) { |
| 101 | + <span style="font-size: x-small"> @(c.Name)</span> |
| 102 | + } |
| 103 | + </div> |
| 104 | + } |
| 105 | + </div> |
| 106 | + <div class="row"> |
| 107 | + <div class="grid-cell"> |
| 108 | + Per Day: <input type="number" @bind-value="duration" min="1" max="50"/> |
| 109 | + |
| 110 | + </div> |
| 111 | + @foreach (var (c, i) in currencies) |
| 112 | + { |
| 113 | + var pp = totalSpentByCat[selectedCat] * adultPersonWeight / (totalWeightByCat[selectedCat] == 0 ? 1 : totalWeightByCat[selectedCat]); |
| 114 | + var cc = Tour?.Currency ?? new(); |
| 115 | + var rate = cc.CurrencyRate * 1.0 / c.CurrencyRate; |
| 116 | + var amountInCurrency = pp * rate / (duration == 0 ? 1 : duration); |
| 117 | + <div class="grid-cell balance"> |
| 118 | + <b>@((amountInCurrency).ToString("N0", GlobConsts.NumGroupSpaceSeparated)) </b> |
| 119 | + @if (Tour?.IsMultiCurrency() ?? false) { |
| 120 | + <span style="font-size: x-small"> @(c.Name)</span> |
122 | 121 | } |
123 | 122 | </div> |
124 | 123 | } |
| 124 | + </div> |
| 125 | + @if (Tour.IsMultiCurrency()) |
| 126 | + { |
| 127 | + <div class="row"> |
| 128 | + <div class="grid-cell"> |
| 129 | + Currency: <b style='color: green'>@Tour?.Currency?.Name</b> |
| 130 | + </div> |
| 131 | + @foreach (var (c, i) in currencies) |
| 132 | + { |
| 133 | + var cc = Tour?.Currency ?? new (); |
| 134 | + var rate = cc.CurrencyRate > c.CurrencyRate ? cc.CurrencyRate * 1.0 / c.CurrencyRate : c.CurrencyRate * 1.0 / cc.CurrencyRate; |
| 135 | + var (fc, sc) = cc.CurrencyRate > c.CurrencyRate ? (cc, c) : (c, cc); |
| 136 | + <div class="grid-cell"> |
| 137 | + @if (cc != c) |
| 138 | + { |
| 139 | + <span style="font-size: x-small"><b style="@(fc == cc ? "color:green" : "")">@fc.Name</b> / <b style="@(sc == cc ? "color:green" : "")">@sc.Name:</b> @($"{rate:#.00}")</span> |
| 140 | + } |
| 141 | + </div> |
| 142 | + } |
| 143 | + </div> |
| 144 | + } |
125 | 145 | </div> |
126 | | -</div> |
| 146 | + </div> |
127 | 147 | </div> |
128 | 148 | @code { |
129 | 149 | [Parameter] |
130 | 150 | public Tour Tour { get; set; } = new Tour(); |
131 | 151 |
|
| 152 | + private bool chartDataByCat { get; set; } = true; |
| 153 | + |
132 | 154 | private IEnumerable<(string Name, int Amount)> summary = new List<(string Name, int Amount)>() |
133 | 155 | { |
134 | 156 | ("A", 10) |
135 | 157 | }; |
| 158 | + private IEnumerable<(string Name, int Amount)> summaryByPersons = new List<(string Name, int Amount)>() |
| 159 | + { |
| 160 | + ("N/A", 10) |
| 161 | + }; |
136 | 162 |
|
137 | 163 | private int duration { get; set; } = 4; |
138 | 164 |
|
|
194 | 220 | duration = Tour.Duration; |
195 | 221 | settings = await engine.GetUISettings(); |
196 | 222 | summary = GetSpendingForStat(); |
| 223 | + summaryByPersons = GetSpendingByPersonForStat(); |
197 | 224 | CalculatePerPerson(); |
198 | 225 | csg = new() { Magic = settings.Magic_Piechart_Color_Scheme_Number * 1.0 / 1000 }; |
199 | 226 | } |
|
202 | 229 | { |
203 | 230 | duration = Tour.Duration; |
204 | 231 | summary = GetSpendingForStat(); |
| 232 | + summaryByPersons = GetSpendingByPersonForStat(); |
205 | 233 | CalculatePerPerson(); |
206 | 234 | } |
207 | 235 |
|
|
274 | 302 | summary[s.Type] += s.AmountInCurrentCurrency(Tour); |
275 | 303 | } |
276 | 304 | return summary.DistinctBy(s => s.Key).OrderByDescending(s => s.Value).Select(s => (s.Key, (int)s.Value)); |
277 | | - } |
| 305 | + } |
| 306 | + public IEnumerable<(string Name, int Amount)> GetSpendingByPersonForStat() |
| 307 | + { |
| 308 | + var ss = Tour.Spendings |
| 309 | + .Where(s => !s.Planned && !string.IsNullOrWhiteSpace(s.Type) && (!s.IsDryRun || s.IncludeDryRunInCalc)) |
| 310 | + ; |
| 311 | + Dictionary<string, long> summary = new Dictionary<string, long>(); |
| 312 | + foreach (var s in ss) |
| 313 | + { |
| 314 | + var pName = (Tour.Persons.Where(pp => pp.GUID == s.FromGuid).FirstOrDefault()?.Name ?? "N/A").AsShortString(); |
| 315 | + if (!summary.ContainsKey(pName)) summary[pName] = 0; |
| 316 | + summary[pName] += s.AmountInCurrentCurrency(Tour); |
| 317 | + } |
| 318 | + return summary.DistinctBy(s => s.Key).OrderByDescending(s => s.Value).Select(s => (s.Key, (int)s.Value)); |
| 319 | + } |
278 | 320 |
|
279 | 321 | } |
0 commit comments