@dssp/project 0.0.2

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.
Files changed (195) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/assets/images/hatiolab-logo.png +0 -0
  3. package/assets/images/o-mark.png +0 -0
  4. package/assets/images/x-mark.png +0 -0
  5. package/client/bootstrap.ts +0 -0
  6. package/client/index.ts +0 -0
  7. package/client/pages/checklist/checklist-importer.ts +96 -0
  8. package/client/pages/checklist/checklist-list-page.ts +355 -0
  9. package/client/pages/lib/waether.ts +159 -0
  10. package/client/pages/project/ox-progress-circle.ts +133 -0
  11. package/client/pages/project/project-create-popup.ts +148 -0
  12. package/client/pages/project/project-detail.ts +618 -0
  13. package/client/pages/project/project-list.ts +354 -0
  14. package/client/pages/project/project-plan-management.ts +437 -0
  15. package/client/pages/project/project-schedule-list.ts +280 -0
  16. package/client/pages/project/project-schedule.ts +248 -0
  17. package/client/pages/project/project-setting-list.ts +298 -0
  18. package/client/pages/project/project-update.ts +797 -0
  19. package/client/pages/resource/resource-importer.ts +96 -0
  20. package/client/pages/resource/resource-list-page.ts +355 -0
  21. package/client/pages/task/task-importer.ts +96 -0
  22. package/client/pages/task/task-list-page.ts +355 -0
  23. package/client/route.ts +39 -0
  24. package/client/tsconfig.json +11 -0
  25. package/dist-client/bootstrap.d.ts +0 -0
  26. package/dist-client/bootstrap.js +2 -0
  27. package/dist-client/bootstrap.js.map +1 -0
  28. package/dist-client/index.d.ts +0 -0
  29. package/dist-client/index.js +2 -0
  30. package/dist-client/index.js.map +1 -0
  31. package/dist-client/pages/checklist/checklist-importer.d.ts +9 -0
  32. package/dist-client/pages/checklist/checklist-importer.js +100 -0
  33. package/dist-client/pages/checklist/checklist-importer.js.map +1 -0
  34. package/dist-client/pages/checklist/checklist-list-page.d.ts +62 -0
  35. package/dist-client/pages/checklist/checklist-list-page.js +331 -0
  36. package/dist-client/pages/checklist/checklist-list-page.js.map +1 -0
  37. package/dist-client/pages/lib/waether.d.ts +6 -0
  38. package/dist-client/pages/lib/waether.js +152 -0
  39. package/dist-client/pages/lib/waether.js.map +1 -0
  40. package/dist-client/pages/project/ox-progress-circle.d.ts +41 -0
  41. package/dist-client/pages/project/ox-progress-circle.js +182 -0
  42. package/dist-client/pages/project/ox-progress-circle.js.map +1 -0
  43. package/dist-client/pages/project/project-create-popup.d.ts +14 -0
  44. package/dist-client/pages/project/project-create-popup.js +153 -0
  45. package/dist-client/pages/project/project-create-popup.js.map +1 -0
  46. package/dist-client/pages/project/project-detail.d.ts +35 -0
  47. package/dist-client/pages/project/project-detail.js +617 -0
  48. package/dist-client/pages/project/project-detail.js.map +1 -0
  49. package/dist-client/pages/project/project-list.d.ts +88 -0
  50. package/dist-client/pages/project/project-list.js +303 -0
  51. package/dist-client/pages/project/project-list.js.map +1 -0
  52. package/dist-client/pages/project/project-plan-management.d.ts +27 -0
  53. package/dist-client/pages/project/project-plan-management.js +438 -0
  54. package/dist-client/pages/project/project-plan-management.js.map +1 -0
  55. package/dist-client/pages/project/project-schedule-list.d.ts +18 -0
  56. package/dist-client/pages/project/project-schedule-list.js +292 -0
  57. package/dist-client/pages/project/project-schedule-list.js.map +1 -0
  58. package/dist-client/pages/project/project-schedule.d.ts +23 -0
  59. package/dist-client/pages/project/project-schedule.js +256 -0
  60. package/dist-client/pages/project/project-schedule.js.map +1 -0
  61. package/dist-client/pages/project/project-setting-list.d.ts +23 -0
  62. package/dist-client/pages/project/project-setting-list.js +307 -0
  63. package/dist-client/pages/project/project-setting-list.js.map +1 -0
  64. package/dist-client/pages/project/project-update.d.ts +24 -0
  65. package/dist-client/pages/project/project-update.js +797 -0
  66. package/dist-client/pages/project/project-update.js.map +1 -0
  67. package/dist-client/pages/resource/resource-importer.d.ts +9 -0
  68. package/dist-client/pages/resource/resource-importer.js +100 -0
  69. package/dist-client/pages/resource/resource-importer.js.map +1 -0
  70. package/dist-client/pages/resource/resource-list-page.d.ts +62 -0
  71. package/dist-client/pages/resource/resource-list-page.js +331 -0
  72. package/dist-client/pages/resource/resource-list-page.js.map +1 -0
  73. package/dist-client/pages/task/task-importer.d.ts +9 -0
  74. package/dist-client/pages/task/task-importer.js +100 -0
  75. package/dist-client/pages/task/task-importer.js.map +1 -0
  76. package/dist-client/pages/task/task-list-page.d.ts +62 -0
  77. package/dist-client/pages/task/task-list-page.js +331 -0
  78. package/dist-client/pages/task/task-list-page.js.map +1 -0
  79. package/dist-client/route.d.ts +1 -0
  80. package/dist-client/route.js +32 -0
  81. package/dist-client/route.js.map +1 -0
  82. package/dist-client/tsconfig.tsbuildinfo +1 -0
  83. package/dist-server/controllers/index.js +1 -0
  84. package/dist-server/controllers/index.js.map +1 -0
  85. package/dist-server/controllers/project-to-excel.js +30 -0
  86. package/dist-server/controllers/project-to-excel.js.map +1 -0
  87. package/dist-server/index.js +6 -0
  88. package/dist-server/index.js.map +1 -0
  89. package/dist-server/middlewares/index.js +8 -0
  90. package/dist-server/middlewares/index.js.map +1 -0
  91. package/dist-server/routes.js +105 -0
  92. package/dist-server/routes.js.map +1 -0
  93. package/dist-server/service/check-item/check-item-mutation.js +129 -0
  94. package/dist-server/service/check-item/check-item-mutation.js.map +1 -0
  95. package/dist-server/service/check-item/check-item-query.js +86 -0
  96. package/dist-server/service/check-item/check-item-query.js.map +1 -0
  97. package/dist-server/service/check-item/check-item-type.js +69 -0
  98. package/dist-server/service/check-item/check-item-type.js.map +1 -0
  99. package/dist-server/service/check-item/check-item.js +84 -0
  100. package/dist-server/service/check-item/check-item.js.map +1 -0
  101. package/dist-server/service/check-item/index.js +9 -0
  102. package/dist-server/service/check-item/index.js.map +1 -0
  103. package/dist-server/service/checklist/checklist-mutation.js +129 -0
  104. package/dist-server/service/checklist/checklist-mutation.js.map +1 -0
  105. package/dist-server/service/checklist/checklist-query.js +86 -0
  106. package/dist-server/service/checklist/checklist-query.js.map +1 -0
  107. package/dist-server/service/checklist/checklist-type.js +69 -0
  108. package/dist-server/service/checklist/checklist-type.js.map +1 -0
  109. package/dist-server/service/checklist/checklist.js +120 -0
  110. package/dist-server/service/checklist/checklist.js.map +1 -0
  111. package/dist-server/service/checklist/index.js +9 -0
  112. package/dist-server/service/checklist/index.js.map +1 -0
  113. package/dist-server/service/index.js +36 -0
  114. package/dist-server/service/index.js.map +1 -0
  115. package/dist-server/service/project/index.js +11 -0
  116. package/dist-server/service/project/index.js.map +1 -0
  117. package/dist-server/service/project/project-mutation.js +190 -0
  118. package/dist-server/service/project/project-mutation.js.map +1 -0
  119. package/dist-server/service/project/project-query.js +143 -0
  120. package/dist-server/service/project/project-query.js.map +1 -0
  121. package/dist-server/service/project/project-type.js +106 -0
  122. package/dist-server/service/project/project-type.js.map +1 -0
  123. package/dist-server/service/project/project.js +146 -0
  124. package/dist-server/service/project/project.js.map +1 -0
  125. package/dist-server/service/resource/index.js +9 -0
  126. package/dist-server/service/resource/index.js.map +1 -0
  127. package/dist-server/service/resource/resource-mutation.js +129 -0
  128. package/dist-server/service/resource/resource-mutation.js.map +1 -0
  129. package/dist-server/service/resource/resource-query.js +86 -0
  130. package/dist-server/service/resource/resource-query.js.map +1 -0
  131. package/dist-server/service/resource/resource-type.js +69 -0
  132. package/dist-server/service/resource/resource-type.js.map +1 -0
  133. package/dist-server/service/resource/resource.js +62 -0
  134. package/dist-server/service/resource/resource.js.map +1 -0
  135. package/dist-server/service/task/index.js +9 -0
  136. package/dist-server/service/task/index.js.map +1 -0
  137. package/dist-server/service/task/task-mutation.js +129 -0
  138. package/dist-server/service/task/task-mutation.js.map +1 -0
  139. package/dist-server/service/task/task-query.js +86 -0
  140. package/dist-server/service/task/task-query.js.map +1 -0
  141. package/dist-server/service/task/task-type.js +69 -0
  142. package/dist-server/service/task/task-type.js.map +1 -0
  143. package/dist-server/service/task/task.js +106 -0
  144. package/dist-server/service/task/task.js.map +1 -0
  145. package/dist-server/tsconfig.tsbuildinfo +1 -0
  146. package/helps/management/alarm.md +160 -0
  147. package/helps/management/alter-video.md +160 -0
  148. package/helps/management/cctv.md +160 -0
  149. package/helps/management/device.md +160 -0
  150. package/helps/management/parking.md +160 -0
  151. package/helps/management/site.md +160 -0
  152. package/helps/management/sun-pnl.md +160 -0
  153. package/helps/project/checklist.md +160 -0
  154. package/helps/project/project.md +160 -0
  155. package/helps/project/resource.md +160 -0
  156. package/helps/project/task.md +160 -0
  157. package/package.json +38 -0
  158. package/server/controllers/index.ts +0 -0
  159. package/server/controllers/project-to-excel.ts +40 -0
  160. package/server/index.ts +3 -0
  161. package/server/middlewares/index.ts +3 -0
  162. package/server/routes.ts +108 -0
  163. package/server/service/check-item/check-item-mutation.ts +142 -0
  164. package/server/service/check-item/check-item-query.ts +56 -0
  165. package/server/service/check-item/check-item-type.ts +49 -0
  166. package/server/service/check-item/check-item.ts +74 -0
  167. package/server/service/check-item/index.ts +6 -0
  168. package/server/service/checklist/checklist-mutation.ts +142 -0
  169. package/server/service/checklist/checklist-query.ts +56 -0
  170. package/server/service/checklist/checklist-type.ts +49 -0
  171. package/server/service/checklist/checklist.ts +105 -0
  172. package/server/service/checklist/index.ts +6 -0
  173. package/server/service/index.ts +35 -0
  174. package/server/service/project/index.ts +8 -0
  175. package/server/service/project/project-mutation.ts +201 -0
  176. package/server/service/project/project-query.ts +103 -0
  177. package/server/service/project/project-type.ts +71 -0
  178. package/server/service/project/project.ts +131 -0
  179. package/server/service/resource/index.ts +6 -0
  180. package/server/service/resource/resource-mutation.ts +139 -0
  181. package/server/service/resource/resource-query.ts +56 -0
  182. package/server/service/resource/resource-type.ts +49 -0
  183. package/server/service/resource/resource.ts +56 -0
  184. package/server/service/task/index.ts +6 -0
  185. package/server/service/task/task-mutation.ts +136 -0
  186. package/server/service/task/task-query.ts +56 -0
  187. package/server/service/task/task-type.ts +49 -0
  188. package/server/service/task/task.ts +97 -0
  189. package/server/tsconfig.json +10 -0
  190. package/things-factory.config.js +20 -0
  191. package/translations/en.json +1 -0
  192. package/translations/ja.json +1 -0
  193. package/translations/ko.json +9 -0
  194. package/translations/ms.json +1 -0
  195. package/translations/zh.json +1 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6
+ and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
+
8
+ <!-- ## [Unreleased] -->
Binary file
Binary file
Binary file
File without changes
File without changes
@@ -0,0 +1,96 @@
1
+ import '@operato/data-grist'
2
+
3
+ import gql from 'graphql-tag'
4
+ import { css, html, LitElement } from 'lit'
5
+ import { property, state } from 'lit/decorators.js'
6
+
7
+ import { client } from '@operato/graphql'
8
+ import { i18next } from '@operato/i18n'
9
+ import { isMobileDevice } from '@operato/utils'
10
+
11
+ export class ChecklistImporter extends LitElement {
12
+ static styles = [
13
+ css`
14
+ :host {
15
+ display: flex;
16
+ flex-direction: column;
17
+
18
+ background-color: #fff;
19
+ }
20
+
21
+ ox-grist {
22
+ flex: 1;
23
+ }
24
+
25
+ .button-container {
26
+ display: flex;
27
+ margin-left: auto;
28
+ padding: var(--padding-default);
29
+ }
30
+
31
+ mwc-button {
32
+ margin-left: var(--margin-default);
33
+ }
34
+ `
35
+ ]
36
+
37
+ @state() private checklists: any[] = []
38
+ @state() private columns = {
39
+ list: { fields: ['name', 'description'] },
40
+ pagination: { infinite: true },
41
+ columns: [
42
+ {
43
+ type: 'string',
44
+ name: 'name',
45
+ header: i18next.t('field.name'),
46
+ width: 150
47
+ },
48
+ {
49
+ type: 'string',
50
+ name: 'description',
51
+ header: i18next.t('field.description'),
52
+ width: 200
53
+ },
54
+ {
55
+ type: 'checkbox',
56
+ name: 'active',
57
+ header: i18next.t('field.active'),
58
+ width: 60
59
+ }
60
+ ]
61
+ }
62
+
63
+ render() {
64
+ return html`
65
+ <ox-grist
66
+ .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
67
+ .config=${this.columns}
68
+ .data=${
69
+ {
70
+ records: this.checklists
71
+ }
72
+ }
73
+ ></ox-grist>
74
+
75
+ <div class="button-container">
76
+ <mwc-button raised @click="${this.save.bind(this)}">${i18next.t('button.save')}</mwc-button>
77
+ </div>
78
+ `
79
+ }
80
+
81
+ private async save() {
82
+ const response = await client.mutate({
83
+ mutation: gql`
84
+ mutation importChecklists($checklists: [ChecklistPatch!]!) {
85
+ importChecklists(checklists: $checklists)
86
+ }
87
+ `,
88
+ variables: { checklists: this.checklists }
89
+ })
90
+
91
+ if (response.errors?.length) return
92
+
93
+ this.dispatchEvent(new CustomEvent('imported'))
94
+ }
95
+ }
96
+
@@ -0,0 +1,355 @@
1
+ import '@operato/data-grist'
2
+
3
+ import { CommonButtonStyles, CommonGristStyles, ScrollbarStyles } from '@operato/styles'
4
+ import { PageView, store } from '@operato/shell'
5
+ import { css, html } from 'lit'
6
+ import { customElement, property, query, state } from 'lit/decorators.js'
7
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements'
8
+ import {
9
+ ColumnConfig,
10
+ DataGrist,
11
+ FetchOption,
12
+ SortersControl
13
+ } from '@operato/data-grist'
14
+ import { client } from '@operato/graphql'
15
+ import { i18next, localize } from '@operato/i18n'
16
+ import { notify, openPopup } from '@operato/layout'
17
+ import { OxPopup, OxPrompt } from '@operato/popup'
18
+ import { isMobileDevice } from '@operato/utils'
19
+
20
+ import { connect } from 'pwa-helpers/connect-mixin'
21
+ import gql from 'graphql-tag'
22
+
23
+ import { ChecklistImporter } from './checklist-importer'
24
+
25
+ @customElement('checklist-list-page')
26
+ export class ChecklistListPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
27
+
28
+ static styles = [
29
+ ScrollbarStyles,
30
+ CommonGristStyles,
31
+ css`
32
+ :host {
33
+ display: flex;
34
+
35
+ width: 100%;
36
+
37
+ --grid-record-emphasized-background-color: red;
38
+ --grid-record-emphasized-color: yellow;
39
+ }
40
+ `
41
+ ]
42
+
43
+ static get scopedElements() {
44
+ return {
45
+ 'checklist-importer': ChecklistImporter
46
+ }
47
+ }
48
+
49
+ @state() private gristConfig: any
50
+ @state() private mode: 'CARD' | 'GRID' | 'LIST' = isMobileDevice() ? 'CARD' : 'GRID'
51
+
52
+ @query('ox-grist') private grist!: DataGrist
53
+ @query('#sorter-control') private sortersControl!: OxPopup
54
+
55
+ get context() {
56
+ return {
57
+ title: i18next.t('title.checklist list'),
58
+ search: {
59
+ handler: (search: string) => {
60
+ this.grist.searchText = search
61
+ },
62
+ value: this.grist.searchText
63
+ },
64
+ filter: {
65
+ handler: () => {
66
+ this.grist.toggleHeadroom()
67
+ }
68
+ },
69
+ help: 'project/checklist',
70
+ actions: [
71
+ {
72
+ title: i18next.t('button.save'),
73
+ action: this.updateChecklist.bind(this),
74
+ ...CommonButtonStyles.save
75
+ },
76
+ {
77
+ title: i18next.t('button.delete'),
78
+ action: this.deleteChecklist.bind(this),
79
+ ...CommonButtonStyles.delete
80
+ }
81
+ ],
82
+ exportable: {
83
+ name: i18next.t('title.checklist list'),
84
+ data: this.exportHandler.bind(this)
85
+ },
86
+ importable: {
87
+ handler: this.importHandler.bind(this)
88
+ }
89
+ }
90
+ }
91
+
92
+ render() {
93
+ const mode = this.mode || (isMobileDevice() ? 'CARD' : 'GRID')
94
+
95
+ return html`
96
+ <ox-grist
97
+ .mode=${mode}
98
+ .config=${this.gristConfig}
99
+ .fetchHandler=${this.fetchHandler.bind(this)}
100
+ >
101
+ <div slot="headroom">
102
+ <div id="filters">
103
+ <ox-filters-form autofocus></ox-filters-form>
104
+ </div>
105
+
106
+ <div id="sorters">
107
+ Sort
108
+ <mwc-icon
109
+ @click=${e => {
110
+ const target = e.currentTarget
111
+ this.sortersControl.open({
112
+ right: 0,
113
+ top: target.offsetTop + target.offsetHeight
114
+ })
115
+ }}
116
+ >expand_more</mwc-icon
117
+ >
118
+ <ox-popup id="sorter-control">
119
+ <ox-sorters-control> </ox-sorters-control>
120
+ </ox-popup>
121
+ </div>
122
+
123
+ <div id="modes">
124
+ <mwc-icon @click=${() => (this.mode = 'GRID')} ?active=${mode == 'GRID'}>grid_on</mwc-icon>
125
+ <mwc-icon @click=${() => (this.mode = 'LIST')} ?active=${mode == 'LIST'}>format_list_bulleted</mwc-icon>
126
+ <mwc-icon @click=${() => (this.mode = 'CARD')} ?active=${mode == 'CARD'}>apps</mwc-icon>
127
+ </div>
128
+ </div>
129
+ </ox-grist>
130
+ `
131
+ }
132
+
133
+ async pageInitialized(lifecycle: any) {
134
+ this.gristConfig = {
135
+ list: {
136
+ fields: ['name', 'description'],
137
+ details: ['active', 'updatedAt']
138
+ },
139
+ columns: [
140
+ { type: 'gutter', gutterName: 'sequence' },
141
+ { type: 'gutter', gutterName: 'row-selector', multiple: true },
142
+ {
143
+ type: 'string',
144
+ name: 'name',
145
+ header: i18next.t('field.name'),
146
+ record: {
147
+ editable: true
148
+ },
149
+ filter: 'search',
150
+ sortable: true,
151
+ width: 150
152
+ },
153
+ {
154
+ type: 'string',
155
+ name: 'description',
156
+ header: i18next.t('field.description'),
157
+ record: {
158
+ editable: true
159
+ },
160
+ filter: 'search',
161
+ width: 200
162
+ },
163
+ {
164
+ type: 'checkbox',
165
+ name: 'active',
166
+ label: true,
167
+ header: i18next.t('field.active'),
168
+ record: {
169
+ editable: true
170
+ },
171
+ filter: true,
172
+ sortable: true,
173
+ width: 60
174
+ },
175
+ {
176
+ type: 'resource-object',
177
+ name: 'updater',
178
+ header: i18next.t('field.updater'),
179
+ record: {
180
+ editable: false
181
+ },
182
+ sortable: true,
183
+ width: 120
184
+ },
185
+ {
186
+ type: 'datetime',
187
+ name: 'updatedAt',
188
+ header: i18next.t('field.updated_at'),
189
+ record: {
190
+ editable: false
191
+ },
192
+ sortable: true,
193
+ width: 180
194
+ }
195
+ ],
196
+ rows: {
197
+ selectable: {
198
+ multiple: true
199
+ }
200
+ },
201
+ sorters: [
202
+ {
203
+ name: 'name'
204
+ }
205
+ ]
206
+ }
207
+ }
208
+
209
+ async pageUpdated(changes: any, lifecycle: any) {
210
+ if (this.active) {
211
+ // do something here when this page just became as active
212
+ }
213
+ }
214
+
215
+ async fetchHandler({ page = 1, limit = 100, sortings = [], filters = [] }: FetchOption) {
216
+ const response = await client.query({
217
+ query: gql`
218
+ query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
219
+ responses: checklists(filters: $filters, pagination: $pagination, sortings: $sortings) {
220
+ items {
221
+ id
222
+ name
223
+ description
224
+ active
225
+ updater {
226
+ id
227
+ name
228
+ }
229
+ updatedAt
230
+ }
231
+ total
232
+ }
233
+ }
234
+ `,
235
+ variables: {
236
+ filters,
237
+ pagination: { page, limit },
238
+ sortings
239
+ }
240
+ })
241
+
242
+ return {
243
+ total: response.data.responses.total || 0,
244
+ records: response.data.responses.items || []
245
+ }
246
+ }
247
+
248
+ private async deleteChecklist() {
249
+ if (
250
+ await OxPrompt.open({
251
+ title: i18next.t('text.are_you_sure'),
252
+ text: i18next.t('text.sure_to_x', { x: i18next.t('text.delete') }),
253
+ confirmButton: { text: i18next.t('button.confirm') },
254
+ cancelButton: { text: i18next.t('button.cancel') }
255
+ })
256
+ ) {
257
+ const ids = this.grist.selected.map(record => record.id)
258
+ if (ids && ids.length > 0) {
259
+ const response = await client.mutate({
260
+ mutation: gql`
261
+ mutation ($ids: [String!]!) {
262
+ deleteChecklists(ids: $ids)
263
+ }
264
+ `,
265
+ variables: {
266
+ ids
267
+ }
268
+ })
269
+
270
+ if (!response.errors) {
271
+ this.grist.fetch()
272
+ notify({
273
+ message: i18next.t('text.info_x_successfully', { x: i18next.t('text.delete') })
274
+ })
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ private async updateChecklist() {
281
+ let patches = this.grist.dirtyRecords
282
+ if (patches && patches.length) {
283
+ patches = patches.map(patch => {
284
+ let patchField: any = patch.id ? { id: patch.id } : {}
285
+ const dirtyFields = patch.__dirtyfields__
286
+ for (let key in dirtyFields) {
287
+ patchField[key] = dirtyFields[key].after
288
+ }
289
+ patchField.cuFlag = patch.__dirty__
290
+
291
+ return patchField
292
+ })
293
+
294
+ const response = await client.mutate({
295
+ mutation: gql`
296
+ mutation ($patches: [ChecklistPatch!]!) {
297
+ updateMultipleChecklist(patches: $patches) {
298
+ name
299
+ }
300
+ }
301
+ `,
302
+ variables: {
303
+ patches
304
+ }
305
+ })
306
+
307
+ if (!response.errors) {
308
+ this.grist.fetch()
309
+ }
310
+ }
311
+ }
312
+
313
+ private async exportHandler() {
314
+ const exportTargets = this.grist.selected.length ? this.grist.selected : this.grist.dirtyData.records
315
+ const targetFieldSet = new Set([
316
+ 'id',
317
+ 'name',
318
+ 'description',
319
+ 'active'
320
+ ])
321
+
322
+ return exportTargets.map(checklist => {
323
+ let tempObj = {}
324
+ for (const field of targetFieldSet) {
325
+ tempObj[field] = checklist[field]
326
+ }
327
+
328
+ return tempObj
329
+ })
330
+ }
331
+
332
+ private async importHandler(records) {
333
+ const popup = openPopup(
334
+ html`
335
+ <checklist-importer
336
+ .checklists=${records}
337
+ @imported=${() => {
338
+ history.back()
339
+ this.grist.fetch()
340
+ }}
341
+ ></checklist-importer>
342
+ `,
343
+ {
344
+ backdrop: true,
345
+ size: 'large',
346
+ title: i18next.t('title.import checklist')
347
+ }
348
+ )
349
+
350
+ popup.onclosed = () => {
351
+ this.grist.fetch()
352
+ }
353
+ }
354
+ }
355
+
@@ -0,0 +1,159 @@
1
+ const API_KEY = '9epdR01s19phfu%2B3%2F0elTxTi92Nibl3qEO1HSm2QydrWOlrDqyNn9qzeQRJ3jPOh3hV8TesHg1L%2BQ9D6UOPmWQ%3D%3D'
2
+ const URL = 'https://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getVilageFcst'
3
+ const NUM_OF_ROWS = 12
4
+ const DATA_TYPE = 'JSON'
5
+
6
+ export default async function _getWeather(latitude: number, longitude: number) {
7
+ const { nx, ny } = _getIndexByLatAndLong(latitude, longitude)
8
+ const { base_date, base_time } = _getTodayAndHour()
9
+ const result = await fetch(
10
+ `${URL}?serviceKey=${API_KEY}&base_date=${base_date}&base_time=${base_time}&nx=${nx}&ny=${ny}&pageNo=1&numOfRows=${NUM_OF_ROWS}&dataType=${DATA_TYPE}`
11
+ )
12
+
13
+ let rain = 0
14
+ let temperature = 0
15
+ let humidity = 0
16
+ let wind = ''
17
+
18
+ if (result.status == 200) {
19
+ let weather = await result.json().then(data => data?.response?.body)
20
+ weather = weather?.items?.item
21
+
22
+ for (let key in weather) {
23
+ const data = weather?.[key] || {}
24
+
25
+ if (data.category === 'POP') {
26
+ rain = data.fcstValue
27
+ }
28
+ if (data.category === 'REH') {
29
+ humidity = data.fcstValue
30
+ }
31
+ if (data.category === 'TMP') {
32
+ temperature = data.fcstValue
33
+ }
34
+ if (data.category === 'VEC') {
35
+ wind = _getWindDirectionByValue(data.fcstValue)
36
+ }
37
+ }
38
+
39
+ console.log('weather :', weather)
40
+ }
41
+
42
+ return { rain, temperature, humidity, wind }
43
+ }
44
+
45
+ const RE = 6371.00877 // 지구 반경(km)
46
+ const GRID = 5.0 // 격자 간격(km)
47
+ const SLAT1 = 30.0 // 투영 위도1(degree)
48
+ const SLAT2 = 60.0 // 투영 위도2(degree)
49
+ const OLON = 126.0 // 기준점 경도(degree)
50
+ const OLAT = 38.0 // 기준점 위도(degree)
51
+ const XO = 43 // 기준점 X좌표(GRID)
52
+ const YO = 136 // 기1준점 Y좌표(GRID)
53
+
54
+ // 위경도 -> 기상청 좌표
55
+ function _getIndexByLatAndLong(latitude: number, longitude: number) {
56
+ const DEGRAD = Math.PI / 180.0
57
+ const re = RE / GRID
58
+ const slat1 = SLAT1 * DEGRAD
59
+ const slat2 = SLAT2 * DEGRAD
60
+ const olon = OLON * DEGRAD
61
+ const olat = OLAT * DEGRAD
62
+
63
+ let sn = Math.tan(Math.PI * 0.25 + slat2 * 0.5) / Math.tan(Math.PI * 0.25 + slat1 * 0.5)
64
+ sn = Math.log(Math.cos(slat1) / Math.cos(slat2)) / Math.log(sn)
65
+ let sf = Math.tan(Math.PI * 0.25 + slat1 * 0.5)
66
+ sf = (Math.pow(sf, sn) * Math.cos(slat1)) / sn
67
+ let ro = Math.tan(Math.PI * 0.25 + olat * 0.5)
68
+ ro = (re * sf) / Math.pow(ro, sn)
69
+ let ra = Math.tan(Math.PI * 0.25 + latitude * DEGRAD * 0.5)
70
+ ra = (re * sf) / Math.pow(ra, sn)
71
+ let theta = longitude * DEGRAD - olon
72
+ if (theta > Math.PI) theta -= 2.0 * Math.PI
73
+ if (theta < -Math.PI) theta += 2.0 * Math.PI
74
+ theta *= sn
75
+
76
+ return {
77
+ nx: Math.floor(ra * Math.sin(theta) + XO + 0.5),
78
+ ny: Math.floor(ro - ra * Math.cos(theta) + YO + 0.5),
79
+ latitude,
80
+ longitude
81
+ }
82
+ }
83
+
84
+ function _getTodayAndHour() {
85
+ const now = new Date()
86
+ const todayDate = now.toISOString().slice(0, 10).replace(/-/g, '')
87
+ const yesterday = new Date(now)
88
+ yesterday.setDate(yesterday.getDate() - 1)
89
+ const yesterdayDate = yesterday.toISOString().slice(0, 10).replace(/-/g, '')
90
+
91
+ // 1일 총 8번 데이터가 업데이트 된다. (0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300)
92
+ let base_date
93
+ let base_time
94
+
95
+ if (now.getHours() < 2 || (now.getHours() === 2 && now.getMinutes() <= 10)) {
96
+ base_date = yesterdayDate
97
+ base_time = '2300'
98
+ } else if (now.getHours() < 5 || (now.getHours() === 5 && now.getMinutes() <= 10)) {
99
+ base_date = todayDate
100
+ base_time = '0200'
101
+ } else if (now.getHours() < 8 || (now.getHours() === 8 && now.getMinutes() <= 10)) {
102
+ base_date = todayDate
103
+ base_time = '0500'
104
+ } else if (now.getHours() <= 11 || now.getMinutes() <= 10) {
105
+ base_date = todayDate
106
+ base_time = '0800'
107
+ } else if (now.getHours() < 14 || (now.getHours() === 14 && now.getMinutes() <= 10)) {
108
+ base_date = todayDate
109
+ base_time = '1100'
110
+ } else if (now.getHours() < 17 || (now.getHours() === 17 && now.getMinutes() <= 10)) {
111
+ base_date = todayDate
112
+ base_time = '1400'
113
+ } else if (now.getHours() < 20 || (now.getHours() === 20 && now.getMinutes() <= 10)) {
114
+ base_date = todayDate
115
+ base_time = '1700'
116
+ } else if (now.getHours() < 23 || (now.getHours() === 23 && now.getMinutes() <= 10)) {
117
+ base_date = todayDate
118
+ base_time = '2000'
119
+ } else {
120
+ base_date = todayDate
121
+ base_time = '2300'
122
+ }
123
+
124
+ return { base_time, base_date }
125
+ }
126
+
127
+ const windTable = {
128
+ 0: 'N',
129
+ 1: 'NNE',
130
+ 2: 'NE',
131
+ 3: 'ENE',
132
+ 4: 'E',
133
+ 5: 'ESE',
134
+ 6: 'SE',
135
+ 7: 'SSE',
136
+ 8: 'S',
137
+ 9: 'SSW',
138
+ 10: 'SW',
139
+ 11: 'WSW',
140
+ 12: 'W',
141
+ 13: 'WNW',
142
+ 14: 'NW',
143
+ 15: 'NNW',
144
+ 16: 'N'
145
+ }
146
+ const directoinMapping = {
147
+ N: '북',
148
+ S: '남',
149
+ E: '동',
150
+ W: '서'
151
+ }
152
+
153
+ function _getWindDirectionByValue(value: number): string {
154
+ const calc: number | null = Math.floor((Number(value) + 22.5 * 0.5) / 22.5) || null
155
+
156
+ if (calc === null) return ''
157
+
158
+ return windTable[calc]?.replace(/[NSEW]/g, match => directoinMapping[match]) || ''
159
+ }