@eturnity/eturnity_reusable_components 7.48.0 → 7.48.1-EPDM-12680.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,533 @@
1
+ <template>
2
+ <PageContainer>
3
+ <PageTitleContainer>
4
+ <SectionTitleText>{{ $gettext('inverters') }}</SectionTitleText>
5
+ <ButtonIcon
6
+ custom-color="black"
7
+ :icon-name="hasExpandedSection ? 'collapse_all' : 'expand'"
8
+ :text="$gettext(hasExpandedSection ? 'collapse_all' : 'expand_all')"
9
+ @click="toggleAllSections"
10
+ />
11
+ </PageTitleContainer>
12
+ <SectionContainer v-for="item in dataList" :key="item.inverterId">
13
+ <TitleContainer>
14
+ <IconWrapper size="20px" @click="toggleSection(item.inverterId)">
15
+ <RCIcon
16
+ color="white"
17
+ :name="isExpanded(item.inverterId) ? 'arrow_up' : 'arrow_down'"
18
+ size="10px"
19
+ />
20
+ </IconWrapper>
21
+ <TextContainer>
22
+ <TitleText :title="item.model">{{ item.model }}</TitleText>
23
+ <TitleSubText>{{ item.brandName }}</TitleSubText>
24
+ </TextContainer>
25
+ <IconsContainer>
26
+ <IconWrapper>
27
+ <RCIcon color="red" cursor="pointer" name="delete" size="14px" />
28
+ </IconWrapper>
29
+ <IconWrapper @click="$emit('on-edit', item)">
30
+ <RCIcon
31
+ color="white"
32
+ cursor="pointer"
33
+ name="edit_button"
34
+ size="14px"
35
+ />
36
+ </IconWrapper>
37
+ <IconWrapper>
38
+ <RCIcon
39
+ color="white"
40
+ cursor="pointer"
41
+ name="document"
42
+ size="14px"
43
+ />
44
+ </IconWrapper>
45
+ </IconsContainer>
46
+ </TitleContainer>
47
+ <MarkersContainer>
48
+ <MarkerItem>??%</MarkerItem>
49
+ <MarkerItem>{{
50
+ item.hasTemplate ? 'Template!' : $gettext('no_template')
51
+ }}</MarkerItem>
52
+ <MarkerItem>
53
+ <RCIcon color="white" :name="getIconName(item.type)" size="14px" />
54
+ <div>{{ getTypeName(item.type) }}</div>
55
+ </MarkerItem>
56
+ <ContainerValue>? kWp</ContainerValue>
57
+ </MarkersContainer>
58
+ <BoxContainer
59
+ v-for="mppt in item.mppts"
60
+ v-show="isExpanded(item.inverterId)"
61
+ :key="mppt.mpptId"
62
+ >
63
+ <BoxTitleWrapper>
64
+ <IconWrapper size="20px" @click="toggleMppt(mppt.mpptId)">
65
+ <RCIcon
66
+ color="white"
67
+ cursor="pointer"
68
+ :name="isMpptExpanded(mppt.mpptId) ? 'arrow_up' : 'arrow_down'"
69
+ size="10px"
70
+ />
71
+ </IconWrapper>
72
+ <BoxTitleText>{{ mppt.name }}</BoxTitleText>
73
+ <BoxIconsContainer>
74
+ <BoxIconWrapper>
75
+ <RCIcon
76
+ color="white"
77
+ cursor="pointer"
78
+ name="string_design"
79
+ size="11px"
80
+ />
81
+ <div>
82
+ {{ mppt.strings.length }}/{{
83
+ mppt.numberOfMppts ? mppt.numberOfMppts : 0
84
+ }}
85
+ </div>
86
+ </BoxIconWrapper>
87
+ <BoxIconWrapper>
88
+ <RCIcon
89
+ color="white"
90
+ cursor="pointer"
91
+ name="panels_tool"
92
+ size="11px"
93
+ />
94
+ <div>{{ getNumberOfMpptModules(mppt.strings) }}</div>
95
+ </BoxIconWrapper>
96
+ </BoxIconsContainer>
97
+ </BoxTitleWrapper>
98
+ <div v-show="isMpptExpanded(mppt.mpptId)">
99
+ <StringBox v-for="string in mppt.strings" :key="string.id">
100
+ <StringColorContainer :background-color="string.color" />
101
+ <StringContainer>
102
+ <div>{{ string.name }}</div>
103
+ <StringIconContainer>
104
+ <div>{{ string.modules.length }}</div>
105
+ <RCIcon color="white" name="module" size="14px" />
106
+ </StringIconContainer>
107
+ </StringContainer>
108
+ </StringBox>
109
+ </div>
110
+ </BoxContainer>
111
+ </SectionContainer>
112
+ </PageContainer>
113
+ </template>
114
+
115
+ <script>
116
+ // import DropdownMenu from '@eturnity/eturnity_reusable_components/src/components/stringDesign/DropdownMenu'
117
+ import styled from 'vue3-styled-components'
118
+ import RCIcon from '../../icon'
119
+ import ButtonIcon from '../../buttons/buttonIcon'
120
+
121
+ const PageContainer = styled.div``
122
+
123
+ const SectionContainer = styled.div`
124
+ &:not(:last-child) {
125
+ margin-bottom: 8px;
126
+ }
127
+ background-color: ${(props) => props.theme.colors.black};
128
+ padding: 8px;
129
+ border-radius: 4px;
130
+ color: ${(props) => props.theme.colors.white};
131
+ `
132
+
133
+ const TitleContainer = styled.div`
134
+ display: flex;
135
+ gap: 14px;
136
+ align-items: center;
137
+ `
138
+
139
+ const IconsContainer = styled.div`
140
+ display: flex;
141
+ align-items: center;
142
+ margin-left: auto;
143
+ `
144
+
145
+ const TextContainer = styled.div`
146
+ display: grid;
147
+ `
148
+
149
+ const TitleText = styled.div`
150
+ font-size: 13px;
151
+ white-space: nowrap;
152
+ overflow: hidden;
153
+ text-overflow: ellipsis;
154
+ `
155
+
156
+ const TitleSubText = styled.div`
157
+ font-size: 10px;
158
+ `
159
+
160
+ const MarkersContainer = styled.div`
161
+ display: flex;
162
+ flex-wrap: wrap;
163
+ gap: 8px;
164
+ margin: 8px 0 16px 30px;
165
+ align-items: end;
166
+ `
167
+
168
+ const MarkerAttrs = { backgroundColor: String }
169
+ const MarkerItem = styled('div', MarkerAttrs)`
170
+ display: flex;
171
+ gap: 5px;
172
+ align-items: center;
173
+ padding: 2px 7px;
174
+ border-radius: 4px;
175
+ background-color: ${(props) =>
176
+ props.backgroundColor
177
+ ? props.theme.colors[props.backgroundColor]
178
+ : props.theme.colors.grey6};
179
+ font-size: 11px;
180
+ color: ${(props) => props.theme.colors.white};
181
+ `
182
+
183
+ const ContainerValue = styled.div`
184
+ font-size: 11px;
185
+ `
186
+
187
+ const IconAttrs = { size: { type: String, default: '36px' } }
188
+ const IconWrapper = styled('div', IconAttrs)`
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: center;
192
+ border-radius: 4px;
193
+ cursor: pointer;
194
+ width: ${(props) => props.size};
195
+ height: ${(props) => props.size};
196
+
197
+ &:hover {
198
+ background: rgba(255, 255, 255, 0.1);
199
+ }
200
+
201
+ &:active {
202
+ background: rgba(255, 255, 255, 0.2);
203
+ }
204
+ `
205
+
206
+ const BoxContainer = styled.div`
207
+ border-radius: 4px;
208
+ background: ${(props) => props.theme.colors.grey6};
209
+ padding: 8px;
210
+ margin-top: 8px;
211
+ margin-left: 30px;
212
+ `
213
+
214
+ const BoxTitleWrapper = styled.div`
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 8px;
218
+ `
219
+
220
+ const BoxTitleText = styled.div`
221
+ font-size: 13px;
222
+ `
223
+
224
+ const BoxIconsContainer = styled.div`
225
+ display: flex;
226
+ gap: 8px;
227
+ align-items: center;
228
+ margin-left: auto;
229
+ font-size: 11px;
230
+ `
231
+
232
+ const BoxIconWrapper = styled.div`
233
+ display: flex;
234
+ align-items: center;
235
+ justify-content: center;
236
+ gap: 4px;
237
+ padding: 4px;
238
+ `
239
+
240
+ const StringBox = styled.div`
241
+ display: grid;
242
+ grid-template-columns: auto 1fr;
243
+ margin-top: 8px;
244
+ border-radius: 4px;
245
+ border: 1px solid ${(props) => props.theme.colors.grey3};
246
+ `
247
+
248
+ const StringContainer = styled.div`
249
+ display: flex;
250
+ justify-content: space-between;
251
+ gap: 8px;
252
+ padding: 8px;
253
+ font-size: 11px;
254
+ `
255
+
256
+ const StringColorAttrs = { backgroundColor: String }
257
+ const StringColorContainer = styled('div', StringColorAttrs)`
258
+ background-color: ${(props) => props.backgroundColor};
259
+ width: 22px;
260
+ min-height: 100%;
261
+ border-top-left-radius: 4px;
262
+ border-bottom-left-radius: 4px;
263
+ `
264
+
265
+ const StringIconContainer = styled.div`
266
+ display: flex;
267
+ align-items: center;
268
+ justify-content: center;
269
+ gap: 2px;
270
+ padding: 0 4px;
271
+ `
272
+
273
+ const PageTitleContainer = styled.div`
274
+ display: flex;
275
+ justify-content: space-between;
276
+ align-items: center;
277
+ padding-bottom: 8px;
278
+ `
279
+
280
+ const SectionTitleText = styled.div`
281
+ font-size: 14px;
282
+ font-weight: 700;
283
+ color: ${(props) => props.theme.colors.white};
284
+ `
285
+
286
+ export default {
287
+ name: 'DropdownMenu',
288
+ components: {
289
+ SectionContainer,
290
+ TitleContainer,
291
+ IconsContainer,
292
+ TextContainer,
293
+ TitleText,
294
+ TitleSubText,
295
+ RCIcon,
296
+ MarkersContainer,
297
+ MarkerItem,
298
+ ContainerValue,
299
+ IconWrapper,
300
+ BoxContainer,
301
+ BoxTitleWrapper,
302
+ BoxTitleText,
303
+ BoxIconsContainer,
304
+ BoxIconWrapper,
305
+ StringBox,
306
+ StringContainer,
307
+ StringColorContainer,
308
+ StringIconContainer,
309
+ PageTitleContainer,
310
+ SectionTitleText,
311
+ ButtonIcon,
312
+ PageContainer,
313
+ },
314
+ props: {
315
+ dataList: {
316
+ required: true,
317
+ type: Array,
318
+ },
319
+ },
320
+ emits: ['on-edit'],
321
+ data() {
322
+ return {
323
+ expandedInverters: [],
324
+ expandedMppts: [],
325
+ // mockData: [
326
+ // {
327
+ // id: 1,
328
+ // brand: 'PVI-10.0-TL-OUTD',
329
+ // model: 'ABB',
330
+ // num_modules: 20,
331
+ // power: 110,
332
+ // template: true,
333
+ // technology: 'PV',
334
+ // power_kWp: 24,
335
+ // mppt_list: [
336
+ // {
337
+ // id: 1,
338
+ // name: 'MPPT 1',
339
+ // num_modules: 2,
340
+ // num_strings: 2,
341
+ // num_strings_available: 3,
342
+ // strings: [
343
+ // {
344
+ // id: 1,
345
+ // name: 'String A',
346
+ // num_modules: 2,
347
+ // color: 'red',
348
+ // },
349
+ // {
350
+ // id: 2,
351
+ // name: 'String B',
352
+ // num_modules: 4,
353
+ // color: 'green',
354
+ // },
355
+ // {
356
+ // id: 3,
357
+ // name: 'String C',
358
+ // num_modules: 5,
359
+ // color: 'blue',
360
+ // },
361
+ // ],
362
+ // },
363
+ // {
364
+ // id: 2,
365
+ // name: 'String B',
366
+ // num_modules: 3,
367
+ // num_strings: 3,
368
+ // num_strings_available: 3,
369
+ // strings: [
370
+ // {
371
+ // id: 4,
372
+ // name: 'String D',
373
+ // num_modules: 3,
374
+ // color: 'purple',
375
+ // },
376
+ // {
377
+ // id: 5,
378
+ // name: 'String E',
379
+ // num_modules: 6,
380
+ // color: 'orange',
381
+ // },
382
+ // {
383
+ // id: 6,
384
+ // name: 'String F',
385
+ // num_modules: 8,
386
+ // color: 'yellow',
387
+ // },
388
+ // ],
389
+ // },
390
+ // ],
391
+ // },
392
+ // {
393
+ // id: 2,
394
+ // brand: 'SUN2000-15KTL-M0',
395
+ // model: 'Huawei',
396
+ // num_modules: 30,
397
+ // power: 95,
398
+ // template: false,
399
+ // technology: 'PV',
400
+ // power_kWp: 32,
401
+ // mppt_list: [
402
+ // {
403
+ // id: 3,
404
+ // name: 'MPPT A',
405
+ // num_modules: 4,
406
+ // num_strings: 1,
407
+ // num_strings_available: 2,
408
+ // strings: [
409
+ // {
410
+ // id: 7,
411
+ // name: 'String G',
412
+ // num_modules: 4,
413
+ // color: 'pink',
414
+ // },
415
+ // ],
416
+ // },
417
+ // {
418
+ // id: 4,
419
+ // name: 'MPPT B',
420
+ // num_modules: 6,
421
+ // num_strings: 2,
422
+ // num_strings_available: 2,
423
+ // strings: [
424
+ // {
425
+ // id: 8,
426
+ // name: 'String H',
427
+ // num_modules: 3,
428
+ // color: 'cyan',
429
+ // },
430
+ // {
431
+ // id: 9,
432
+ // name: 'String I',
433
+ // num_modules: 3,
434
+ // color: 'brown',
435
+ // },
436
+ // ],
437
+ // },
438
+ // ],
439
+ // },
440
+ // ],
441
+ }
442
+ },
443
+ computed: {
444
+ hasExpandedSection() {
445
+ return this.expandedInverters.length > 0
446
+ },
447
+ },
448
+ methods: {
449
+ getNumberOfMpptModules(strings) {
450
+ return strings.reduce((acc, curr) => acc + curr.modules.length, 0)
451
+ },
452
+ getStringColor(idx) {
453
+ // ToDo: get correct colors
454
+ const colors = [
455
+ '#FF6B6B', // coral red
456
+ '#4ECDC4', // turquoise
457
+ '#45B7D1', // sky blue
458
+ '#96CEB4', // sage green
459
+ '#FFEEAD', // cream yellow
460
+ '#D4A5A5', // dusty rose
461
+ '#9B59B6', // purple
462
+ '#3498DB', // bright blue
463
+ '#E67E22', // orange
464
+ '#27AE60', // emerald green
465
+ ]
466
+ return colors[idx]
467
+ },
468
+ isExpanded(id) {
469
+ return this.expandedInverters.includes(id)
470
+ },
471
+ isMpptExpanded(id) {
472
+ return this.expandedMppts.includes(id)
473
+ },
474
+ toggleSection(id) {
475
+ const index = this.expandedInverters.indexOf(id)
476
+ if (index === -1) {
477
+ this.expandedInverters.push(id)
478
+ } else {
479
+ this.expandedInverters.splice(index, 1)
480
+ }
481
+ },
482
+ toggleMppt(id) {
483
+ const index = this.expandedMppts.indexOf(id)
484
+ if (index === -1) {
485
+ this.expandedMppts.push(id)
486
+ } else {
487
+ this.expandedMppts.splice(index, 1)
488
+ }
489
+ },
490
+ toggleAllSections() {
491
+ if (this.hasExpandedSection) {
492
+ this.expandedInverters = []
493
+ this.expandedMppts = []
494
+ } else {
495
+ this.expandedInverters = this.dataList.map((item) => item.inverterId)
496
+ this.expandedMppts = this.dataList.flatMap((item) =>
497
+ item.mppts.map((mppt) => mppt.mpptId)
498
+ )
499
+ }
500
+ },
501
+ getTypeName(type) {
502
+ const value = type.toLowerCase()
503
+ switch (value) {
504
+ case 'pv':
505
+ return this.$gettext('PV')
506
+ case 'hybrid':
507
+ return this.$gettext('hybrid')
508
+ case 'battery':
509
+ return this.$gettext('battery')
510
+ case 'optimizer':
511
+ return this.$gettext('inverter_type_optimizer')
512
+ default:
513
+ return this.$gettext('PV')
514
+ }
515
+ },
516
+ getIconName(type) {
517
+ const value = type.toLowerCase()
518
+ switch (value) {
519
+ case 'pv':
520
+ return 'pv'
521
+ case 'hybrid':
522
+ return 'hybrid'
523
+ case 'battery':
524
+ return 'battery'
525
+ case 'optimizer':
526
+ return 'optimizer'
527
+ default:
528
+ return 'pv'
529
+ }
530
+ },
531
+ },
532
+ }
533
+ </script>