@things-factory/worklist 10.1.185 → 10.1.186
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.
- package/dist-client/my-work-menus.d.ts +0 -5
- package/dist-client/my-work-menus.js +1 -2
- package/dist-client/my-work-menus.js.map +1 -1
- package/dist-client/pages/activity-catalog/activity-catalog-page.d.ts +18 -74
- package/dist-client/pages/activity-catalog/activity-catalog-page.js +292 -527
- package/dist-client/pages/activity-catalog/activity-catalog-page.js.map +1 -1
- package/dist-client/pages/activity-thread/activity-thread-page.d.ts +1 -1
- package/dist-client/pages/work-door/door-links.d.ts +1 -9
- package/dist-client/pages/work-door/door-links.js +1 -11
- package/dist-client/pages/work-door/door-links.js.map +1 -1
- package/dist-client/pages/work-door/door-sentence.d.ts +26 -14
- package/dist-client/pages/work-door/door-sentence.js +58 -60
- package/dist-client/pages/work-door/door-sentence.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +0 -3
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/service/activity/activity-query.js +2 -31
- package/dist-server/service/activity/activity-query.js.map +1 -1
- package/dist-server/service/activity/approval-line-seats.d.ts +12 -0
- package/dist-server/service/activity/approval-line-seats.js +68 -0
- package/dist-server/service/activity/approval-line-seats.js.map +1 -0
- package/dist-server/service/activity/index.d.ts +1 -1
- package/dist-server/service/activity-instance/activity-instance-query.js +2 -54
- package/dist-server/service/activity-instance/activity-instance-query.js.map +1 -1
- package/dist-server/service/activity-instance/index.d.ts +1 -1
- package/dist-server/service/index.d.ts +3 -3
- package/dist-server/service/work-door/work-door-resolver.js +7 -2
- package/dist-server/service/work-door/work-door-resolver.js.map +1 -1
- package/dist-server/service/work-door/work-door-service.d.ts +8 -1
- package/dist-server/service/work-door/work-door-service.js +11 -2
- package/dist-server/service/work-door/work-door-service.js.map +1 -1
- package/dist-server/service/work-door/work-door-type.d.ts +2 -0
- package/dist-server/service/work-door/work-door-type.js +8 -0
- package/dist-server/service/work-door/work-door-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/tests/work-door-door-words.test.ts +1 -1
- package/things-factory.config.js +1 -6
- package/translations/en.json +11 -45
- package/translations/es.json +11 -45
- package/translations/ja.json +11 -45
- package/translations/ko.json +11 -45
- package/translations/ms.json +11 -45
- package/translations/zh.json +11 -45
- package/tests/work-door-sentence.test.ts +0 -199
|
@@ -1,649 +1,414 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import '@material/web/icon/icon.js';
|
|
3
2
|
import '@operato/list-state/ox-page-state.js';
|
|
3
|
+
import '@things-factory/organization/dist-client/component/approval-line-brief.js';
|
|
4
4
|
import gql from 'graphql-tag';
|
|
5
5
|
import { css, html } from 'lit';
|
|
6
6
|
import { customElement, state } from 'lit/decorators.js';
|
|
7
7
|
import { client } from '@operato/graphql';
|
|
8
8
|
import { i18next, localize } from '@operato/i18n';
|
|
9
|
-
import {
|
|
9
|
+
import { PageView } from '@operato/shell';
|
|
10
|
+
import { DocumentPageStyles } from '@operato/styles';
|
|
11
|
+
import { isApprovalStep } from '@things-factory/organization/dist-client';
|
|
10
12
|
import { guideLines } from './activity-guide.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
+
import { detailAddress, opensDetail } from '../work-door/door-links.js';
|
|
14
|
+
import { doorLabel, doorsSummary, followsNote, lineNote, whenNoLineTag } from '../work-door/door-sentence.js';
|
|
15
|
+
import { kindWord, reasonWord, standingWord, whenNoLineBecauseWord, whenNoLineWord } from '../work-door/door-words.js';
|
|
13
16
|
/**
|
|
14
|
-
* 업무 카탈로그 —
|
|
17
|
+
* 업무 카탈로그 — **이 사업장의 업무가 무엇을 하고, 누가 결재하나.**
|
|
15
18
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
20
|
+
* ── 두 화면을 하나로 (2026-10-18, 사용자 판단) ──────────────────────────────
|
|
21
|
+
* 「결재·배정 양식 현황」과 「업무 양식 목록」이 같은 업무를 두 번 늘어놓았다. 앞은 결재선이 섰나를,
|
|
22
|
+
* 뒤는 업무가 무엇인가를 말했고, 뒤에는 만드는 쪽이 읽는 값(모델 수 · 판단 키 · 시험 실행)이 섞여
|
|
23
|
+
* 있었다. 틀은 앞 화면 것을 쓰고, 뒤에서는 업무 설명 한 줄만 가져왔다.
|
|
21
24
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
25
|
+
* ── 왜 이 화면이 있나 ──────────────────────────────────────────────────────
|
|
26
|
+
* 양식은 제품이 세우고 **결재선은 그 사업장이 채운다.** 비어 있는 것은 결함이 아니라 선택인데, 그
|
|
27
|
+
* 선택이 어디에도 안 보였다. 실측(2026-09-11): 미라텍에 양식 11개가 다 서 있고 11개 전부 결재자가
|
|
28
|
+
* 없었다 — 실적 정정도 폐기도 승인 없이 반영되는데 화면에는 결재가 있는 것처럼 보였다.
|
|
24
29
|
*
|
|
25
|
-
*
|
|
30
|
+
* ── 결재선은 그려서 보인다 ─────────────────────────────────────────────────
|
|
31
|
+
* 「…은 결재자 2명을 지납니다」는 몇 명인지만 말하고 누구인지는 안 말했다. 줄마다 결재선을 단계와
|
|
32
|
+
* 이름으로 그린다 — 업무함 띠가 쓰는 organization 의 approval-line-brief 를 그대로 쓴다. 서버는 그
|
|
33
|
+
* 업무가 실제로 거치는 결재선을 보낸다(다른 업무의 결재선을 따르면 그 업무의 것).
|
|
26
34
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
35
|
+
* ── 빈 결재선의 결과는 업무마다 선언돼 있다 ────────────────────────────────
|
|
36
|
+
* `run` 업무는 상신하는 사람이 자기 건을 승인한 것이 되고, `refuse` 업무는 상신 자체가 거절된다
|
|
37
|
+
* (ADR-0077). 결재선 밑 한 줄이 그것을 말한다.
|
|
30
38
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* 그래서 층을 진짜로 가른다.
|
|
40
|
-
*
|
|
41
|
-
* - **사용자가 읽는 것**: 이 업무가 무엇이고, 여기서 쓰이고 있나. 그것만 크게.
|
|
42
|
-
* - **개발 정보**: 어디까지 됐나 · 시험. **값이 있을 때만** 접어서 아래에 둔다. 없는 것을 줄줄이
|
|
43
|
-
* 적지 않는다 — 빈 줄을 나열하는 것은 정직한 게 아니라 아무 말도 안 하는 것이다.
|
|
44
|
-
*
|
|
45
|
-
* 여전히 판단하지 않고 선언을 그린다. 어디까지 됐는지는 화면이 실행 중에 알 수 없고, 그 업무를
|
|
46
|
-
* 등록한 모듈이 자기 코드 옆에 적는다(ActivityReadiness).
|
|
39
|
+
* ── 할 일이 있는 것부터 ────────────────────────────────────────────────────
|
|
40
|
+
* 정할 것이 남은 것을 위로 올린다. 같은 무리 안에서는 선언 순서를 지킨다.
|
|
41
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
*/
|
|
43
|
+
/*
|
|
44
|
+
* A step is asked for every field it carries, though this screen only draws it - organization's
|
|
45
|
+
* approval-line-step-fields test holds every selection to the editor's set.
|
|
47
46
|
*/
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const CATALOG = gql `
|
|
48
|
+
{
|
|
49
|
+
workDoors {
|
|
50
|
+
todo
|
|
51
|
+
on
|
|
52
|
+
off
|
|
53
|
+
missing
|
|
54
|
+
notUsed
|
|
55
|
+
seatsStanding
|
|
56
|
+
seatsOffered
|
|
57
|
+
doors {
|
|
58
|
+
name
|
|
59
|
+
labelKey
|
|
60
|
+
kind
|
|
61
|
+
standing
|
|
62
|
+
reason
|
|
63
|
+
approvers
|
|
64
|
+
from
|
|
65
|
+
whenNoLine
|
|
66
|
+
whenNoLineBecause
|
|
67
|
+
followsLabelKey
|
|
68
|
+
assigneeRole
|
|
69
|
+
notUsedBecause
|
|
70
|
+
approvalLine {
|
|
71
|
+
type
|
|
72
|
+
value
|
|
73
|
+
participation
|
|
74
|
+
notifyAfter
|
|
75
|
+
approver {
|
|
76
|
+
id
|
|
77
|
+
name
|
|
78
|
+
description
|
|
79
|
+
controlNo
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
installableActivities {
|
|
51
85
|
items {
|
|
52
86
|
name
|
|
53
|
-
label
|
|
54
|
-
labelTKey
|
|
55
|
-
readinessNotesTKey
|
|
56
|
-
readinessGapTKeys
|
|
57
|
-
description
|
|
58
87
|
guide
|
|
59
88
|
guideTKeys
|
|
60
|
-
category
|
|
61
|
-
activityType
|
|
62
|
-
provider
|
|
63
|
-
release
|
|
64
|
-
approvalSteps
|
|
65
|
-
uiType
|
|
66
|
-
viewType
|
|
67
|
-
viewSource
|
|
68
|
-
model {
|
|
69
|
-
inout
|
|
70
|
-
hidden
|
|
71
|
-
}
|
|
72
|
-
activity {
|
|
73
|
-
id
|
|
74
|
-
decisionKeys {
|
|
75
|
-
role
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
readiness {
|
|
79
|
-
stage
|
|
80
|
-
gaps
|
|
81
|
-
tests
|
|
82
|
-
notes
|
|
83
|
-
lastRun {
|
|
84
|
-
passed
|
|
85
|
-
total
|
|
86
|
-
at
|
|
87
|
-
command
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
89
|
}
|
|
91
|
-
total
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
92
|
`;
|
|
95
|
-
|
|
96
|
-
* 카드에 보이는 이름. 정렬도 이 글자로 한다 — 보이는 글자와 정렬 기준이 다르면 목록이 뒤섞여 보인다.
|
|
97
|
-
*
|
|
98
|
-
* 번역 키는 서버가 `name` 에서 계산해 보낸다(labelTKey). 화면은 키 규칙을 모른다. label 이 없으면
|
|
99
|
-
* name 이다 — name 은 콜백을 찾는 키라 번역하지 않는다.
|
|
100
|
-
*/
|
|
101
|
-
function shownName(one) {
|
|
102
|
-
if (!one?.label)
|
|
103
|
-
return String(one?.name ?? '');
|
|
104
|
-
return one.labelTKey ? String(i18next.t(one.labelTKey, { defaultValue: one.label })) : String(one.label);
|
|
105
|
-
}
|
|
106
|
-
/*
|
|
107
|
-
* 단계를 읽고 차례를 매기는 판단은 `activity-stage.ts` 한 벌이다 — 업무 상세도 같은 답을 내야 해서
|
|
108
|
-
* 여기 사본을 두지 않는다. 그 파일이 왜 그렇게 되돌리고 왜 그 차례인지 적고 있다.
|
|
109
|
-
*/
|
|
93
|
+
const ORDER = { missing: 0, off: 1, on: 2, 'not-used': 3 };
|
|
110
94
|
let ActivityCatalogPage = class ActivityCatalogPage extends localize(i18next)(PageView) {
|
|
111
95
|
constructor() {
|
|
112
96
|
super(...arguments);
|
|
113
|
-
this.
|
|
114
|
-
this.
|
|
115
|
-
this.
|
|
116
|
-
|
|
97
|
+
this.counts = { on: 0, off: 0, missing: 0, notUsed: 0, todo: 0 };
|
|
98
|
+
this.todo = 0;
|
|
99
|
+
this.seatsStanding = 0;
|
|
100
|
+
this.seatsOffered = 0;
|
|
117
101
|
this.loadError = null;
|
|
118
102
|
}
|
|
119
103
|
static { this.styles = [
|
|
120
|
-
/* The frame owns the page shell and the reading column (ADR-0060 decision 8). */
|
|
121
104
|
DocumentPageStyles,
|
|
122
|
-
ScrollbarStyles,
|
|
123
105
|
css `
|
|
124
106
|
/*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
107
|
+
* One activity, one row: what it is on the left, what it does and who approves on the right.
|
|
108
|
+
* The rows share one grid (subgrid), so every right column starts at the same x.
|
|
127
109
|
*/
|
|
128
|
-
|
|
129
|
-
color: var(--md-sys-color-on-background);
|
|
130
|
-
font-size: var(--ui-t-body, 13px);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/* 단계별 수. 설명이 아니라 자료라서 둔다 — 개발 기간에 이 수가 남은 일을 말한다. */
|
|
134
|
-
[counts] {
|
|
135
|
-
display: flex;
|
|
136
|
-
flex-wrap: wrap;
|
|
137
|
-
gap: 4px 14px;
|
|
138
|
-
|
|
139
|
-
margin: 0 0 12px 0;
|
|
140
|
-
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
[counts] b {
|
|
144
|
-
color: var(--md-sys-color-on-surface, #1d1b20);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
[failed] {
|
|
148
|
-
display: flex;
|
|
149
|
-
align-items: center;
|
|
150
|
-
gap: 6px;
|
|
151
|
-
|
|
152
|
-
padding: 8px 10px;
|
|
153
|
-
border-radius: 6px;
|
|
154
|
-
|
|
155
|
-
background-color: var(--md-sys-color-error-container, #ffdad6);
|
|
156
|
-
color: var(--md-sys-color-on-error-container, #410002);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
ul {
|
|
110
|
+
.doors {
|
|
160
111
|
display: grid;
|
|
161
|
-
|
|
162
|
-
|
|
112
|
+
grid-template-columns: max-content minmax(0, 1fr);
|
|
113
|
+
column-gap: var(--spacing-huge, 24px);
|
|
163
114
|
margin: 0;
|
|
164
115
|
padding: 0;
|
|
165
116
|
list-style: none;
|
|
166
117
|
}
|
|
167
118
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
* 카드가 눌린 것처럼 읽힌다. 뜨는 것과 눌리는 것은 다른 말이라 방향이 뒤집히면 안 된다.
|
|
177
|
-
*/
|
|
178
|
-
li {
|
|
179
|
-
padding: 12px 14px;
|
|
180
|
-
border: 1px solid var(--md-sys-color-outline-variant, #cac4d0);
|
|
181
|
-
border-radius: 6px;
|
|
119
|
+
.door {
|
|
120
|
+
grid-column: 1 / -1;
|
|
121
|
+
display: grid;
|
|
122
|
+
grid-template-columns: subgrid;
|
|
123
|
+
row-gap: var(--spacing-small, 4px);
|
|
124
|
+
padding: var(--spacing-large, 12px) 0;
|
|
125
|
+
border-top: 1px solid var(--md-sys-color-outline-variant);
|
|
126
|
+
}
|
|
182
127
|
|
|
183
|
-
|
|
184
|
-
|
|
128
|
+
.door:first-child {
|
|
129
|
+
border-top: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@media (max-width: 600px) {
|
|
133
|
+
.doors {
|
|
134
|
+
grid-template-columns: minmax(0, 1fr);
|
|
135
|
+
}
|
|
185
136
|
}
|
|
186
137
|
|
|
187
|
-
.
|
|
138
|
+
.what {
|
|
188
139
|
display: flex;
|
|
189
|
-
align-items: baseline;
|
|
190
140
|
flex-wrap: wrap;
|
|
191
|
-
|
|
141
|
+
align-items: baseline;
|
|
142
|
+
gap: var(--spacing-small, 4px) var(--spacing-medium, 8px);
|
|
192
143
|
}
|
|
193
144
|
|
|
194
|
-
/*
|
|
195
|
-
* 이름이 상세로 가는 문이다. 링크처럼 보이게 두되 색은 바꾸지 않는다 — 카드에서 가장 크게
|
|
196
|
-
* 읽혀야 하는 글자라, 파랗게 만들면 이름보다 「링크」가 먼저 읽힌다. 마우스가 오면 말한다.
|
|
197
|
-
*/
|
|
198
145
|
.name {
|
|
199
|
-
font-size: var(--ui-t-title, 15px);
|
|
200
146
|
font-weight: 600;
|
|
201
|
-
color: inherit;
|
|
202
|
-
text-decoration: none;
|
|
203
|
-
cursor: pointer;
|
|
204
147
|
}
|
|
205
148
|
|
|
206
|
-
.
|
|
207
|
-
.
|
|
208
|
-
|
|
149
|
+
/* Kind in words: an empty approval line and an empty assignment line do opposite things. */
|
|
150
|
+
.kind {
|
|
151
|
+
color: var(--ui-muted);
|
|
152
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
209
153
|
}
|
|
210
154
|
|
|
211
|
-
/*
|
|
212
|
-
.
|
|
213
|
-
padding:
|
|
214
|
-
border
|
|
215
|
-
|
|
155
|
+
/* The state says it in words as well as colour: colour alone says nothing to someone who cannot see it. */
|
|
156
|
+
.mark {
|
|
157
|
+
padding: 0 var(--spacing-small, 4px);
|
|
158
|
+
border: 1px solid currentColor;
|
|
159
|
+
border-radius: var(--md-sys-shape-corner-small, 4px);
|
|
160
|
+
font-size: var(--ui-t-micro, 11px);
|
|
161
|
+
font-weight: 600;
|
|
162
|
+
line-height: 1.6;
|
|
216
163
|
white-space: nowrap;
|
|
217
|
-
|
|
218
|
-
background-color: var(--md-sys-color-secondary-container, #e8def8);
|
|
219
|
-
color: var(--md-sys-color-on-secondary-container, #1d192b);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.use[idle] {
|
|
223
|
-
background-color: var(--md-sys-color-surface-variant, #e7e0ec);
|
|
224
|
-
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/* 이 업무가 무엇인가. 카드에서 가장 먼저 읽히는 줄이다. */
|
|
228
|
-
.guide {
|
|
229
|
-
margin: 8px 0 0 0;
|
|
230
|
-
line-height: 1.55;
|
|
231
164
|
}
|
|
232
165
|
|
|
233
|
-
.
|
|
234
|
-
|
|
166
|
+
.mark.on {
|
|
167
|
+
color: var(--md-sys-color-primary);
|
|
235
168
|
}
|
|
236
169
|
|
|
237
|
-
.
|
|
238
|
-
|
|
239
|
-
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/*
|
|
243
|
-
* 개발 정보. 값이 있을 때만 그린다. 사용자에게는 접힌 한 줄로만 보이고, 열면 우리가 볼 것이
|
|
244
|
-
* 나온다.
|
|
245
|
-
*/
|
|
246
|
-
/*
|
|
247
|
-
* 단계 표. **철자를 하나만 쓴다.**
|
|
248
|
-
*
|
|
249
|
-
* 앞 판은 단계마다 boolean 속성을 뒀다. 그러면 하이픈 없는 두 번째 철자가 생기고
|
|
250
|
-
* (notworklist) i18n 키(label.readiness-not-worklist)와 어긋난다. 값 하나를 data-stage 에
|
|
251
|
-
* 실으면 선택자 · 키 꼬리 · 서버 enum 값이 **같은 글자**가 된다.
|
|
252
|
-
*
|
|
253
|
-
* 색과 말로 함께 말한다 — 색만 쓰면 색을 못 가리는 사람에게 아무 말도 하지 않는다.
|
|
254
|
-
*/
|
|
255
|
-
.stage {
|
|
256
|
-
padding: 1px 7px;
|
|
257
|
-
border-radius: 999px;
|
|
258
|
-
font-size: 11px;
|
|
259
|
-
white-space: nowrap;
|
|
260
|
-
|
|
261
|
-
background-color: var(--md-sys-color-surface-variant, #e7e0ec);
|
|
262
|
-
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
170
|
+
.mark.off {
|
|
171
|
+
color: var(--md-sys-color-tertiary);
|
|
263
172
|
}
|
|
264
173
|
|
|
265
|
-
.
|
|
266
|
-
|
|
267
|
-
color: var(--md-sys-color-on-secondary-container, #1d192b);
|
|
174
|
+
.mark.missing {
|
|
175
|
+
color: var(--md-sys-color-error);
|
|
268
176
|
}
|
|
269
177
|
|
|
270
|
-
.
|
|
271
|
-
.
|
|
272
|
-
|
|
273
|
-
color: var(--md-sys-color-on-tertiary-container, #31111d);
|
|
178
|
+
/* Not a task, so quieter. Not removed: that it was turned off has to be readable. */
|
|
179
|
+
.mark.not-used {
|
|
180
|
+
color: var(--md-sys-color-outline);
|
|
274
181
|
}
|
|
275
182
|
|
|
276
|
-
|
|
277
|
-
.
|
|
278
|
-
|
|
279
|
-
border: 1px solid var(--md-sys-color-outline-variant, #cac4d0);
|
|
183
|
+
.door.not-used .what,
|
|
184
|
+
.door.not-used .says {
|
|
185
|
+
opacity: 0.7;
|
|
280
186
|
}
|
|
281
187
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
188
|
+
.says {
|
|
189
|
+
display: flex;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: var(--spacing-small, 4px);
|
|
192
|
+
min-width: 0;
|
|
286
193
|
}
|
|
287
194
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
195
|
+
.line {
|
|
196
|
+
display: flex;
|
|
197
|
+
flex-wrap: wrap;
|
|
198
|
+
align-items: center;
|
|
199
|
+
gap: var(--spacing-small, 4px) var(--spacing-large, 12px);
|
|
292
200
|
}
|
|
293
201
|
|
|
294
202
|
/*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* summary 는 눌리는 것이라 tab 이 멈추는 자리다. 내가 이 절을 만들면서 표시를 안 줘서
|
|
298
|
-
* plant 의 접근성 래칫 시험이 「포커스가 안 보이는 자리 7 → 8」로 잡아냈다. 화면을 하나
|
|
299
|
-
* 더할 때마다 한 칸씩 늘어나는 것을 막는 시험이고, 허용 수를 올려 통과시킬 자리가 아니다.
|
|
203
|
+
* The brief spreads its seats over the width it is given; a two-step line across a wide column
|
|
204
|
+
* reads as three islands. Each seat gets about the width of a name.
|
|
300
205
|
*/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
206
|
+
approval-line-brief {
|
|
207
|
+
flex: 0 1 auto;
|
|
208
|
+
width: calc(var(--seats) * 88px);
|
|
209
|
+
max-width: 100%;
|
|
210
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
304
211
|
}
|
|
305
212
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
margin: 8px 0 0 0;
|
|
213
|
+
.when,
|
|
214
|
+
.from {
|
|
215
|
+
color: var(--ui-muted);
|
|
216
|
+
font-size: var(--ui-t-small, 11.5px);
|
|
312
217
|
}
|
|
313
218
|
|
|
314
|
-
|
|
315
|
-
|
|
219
|
+
.state {
|
|
220
|
+
margin: 0 0 var(--spacing-medium, 8px);
|
|
221
|
+
font-weight: 600;
|
|
316
222
|
}
|
|
317
223
|
|
|
318
|
-
|
|
224
|
+
ol.next {
|
|
319
225
|
margin: 0;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
code {
|
|
323
|
-
font-family: var(--ui-font-mono, monospace);
|
|
324
|
-
font-size: 12px;
|
|
325
|
-
word-break: break-all;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
div[empty] {
|
|
226
|
+
padding-left: var(--spacing-huge, 24px);
|
|
329
227
|
display: flex;
|
|
330
228
|
flex-direction: column;
|
|
331
|
-
gap:
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
div[empty] .title {
|
|
335
|
-
font-size: var(--ui-t-title, 15px);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
div[empty] .why {
|
|
339
|
-
color: var(--md-sys-color-on-surface-variant, #49454f);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
@media (max-width: 480px) {
|
|
343
|
-
dl {
|
|
344
|
-
grid-template-columns: 1fr;
|
|
345
|
-
gap: 0;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
dt {
|
|
349
|
-
margin-top: 6px;
|
|
350
|
-
}
|
|
229
|
+
gap: var(--spacing-medium, 8px);
|
|
351
230
|
}
|
|
352
231
|
`
|
|
353
232
|
]; }
|
|
354
233
|
get context() {
|
|
355
234
|
return {
|
|
356
|
-
/*
|
|
357
|
-
* 이 화면이 어떤 틀인가 — 동작 줄이 이것을 읽고 자기 오른쪽 끝을 내용에 맞춘다
|
|
358
|
-
* (ADR-0060 결정 9 보탬). 안 적으면 창 폭이고, 그것은 작업면의 모양이다.
|
|
359
|
-
*/
|
|
360
|
-
frame: 'document',
|
|
361
235
|
title: i18next.t('title.activity catalog'),
|
|
362
|
-
|
|
236
|
+
frame: 'document'
|
|
363
237
|
};
|
|
364
238
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return html `<div class="page">
|
|
368
|
-
<ox-page-state .loading=${!this.loaded} .error=${this.loadError} @retry=${() => this.retry()}
|
|
369
|
-
>${this.loaded && !this.loadError ? this.renderCatalog() : ''}</ox-page-state
|
|
370
|
-
>
|
|
371
|
-
</div>`;
|
|
372
|
-
}
|
|
373
|
-
retry() {
|
|
374
|
-
this.failed = false;
|
|
375
|
-
this.loadError = null;
|
|
376
|
-
this.loaded = false;
|
|
377
|
-
this.fetch();
|
|
239
|
+
async pageInitialized() {
|
|
240
|
+
await this.load();
|
|
378
241
|
}
|
|
379
|
-
|
|
380
|
-
if (!this.
|
|
381
|
-
|
|
382
|
-
<span class="title">${i18next.t('text.no-installable-activity')}</span>
|
|
383
|
-
<span class="why">${i18next.t('text.no-installable-activity-why')}</span>
|
|
384
|
-
</div>`;
|
|
242
|
+
async pageUpdated(changes, lifecycle) {
|
|
243
|
+
if (lifecycle.active && !this.doors) {
|
|
244
|
+
await this.load();
|
|
385
245
|
}
|
|
386
|
-
return html `
|
|
387
|
-
<div counts>
|
|
388
|
-
${STAGE_ORDER.map(stage => {
|
|
389
|
-
const n = this.items.filter(one => canonicalStage(one.readiness?.stage) == stage).length;
|
|
390
|
-
return n ? html `<span>${i18next.t('label.readiness-' + stage)} <b>${n}</b></span>` : '';
|
|
391
|
-
})}
|
|
392
|
-
</div>
|
|
393
|
-
|
|
394
|
-
<ul>
|
|
395
|
-
${this.items.map(one => this.renderOne(one))}
|
|
396
|
-
</ul>
|
|
397
|
-
`;
|
|
398
|
-
}
|
|
399
|
-
renderOne(one) {
|
|
400
|
-
const stage = canonicalStage(one.readiness?.stage);
|
|
401
|
-
/*
|
|
402
|
-
* 아직 만들지 않은 것은 **설치될 수가 없다.** 그런 카드에 「아직 사용 안 함」을 붙이면 「예정」과
|
|
403
|
-
* 같은 말을 두 번 하는 것이고, 읽는 사람은 둘이 다른 뜻인 줄 알고 두 번 읽는다.
|
|
404
|
-
*/
|
|
405
|
-
const registered = isRegistered(stage);
|
|
406
|
-
const inUse = !!one.activity?.id;
|
|
407
|
-
return html `<li>
|
|
408
|
-
<div class="head">
|
|
409
|
-
<!--
|
|
410
|
-
이름은 label 이 있으면 label 이다. name 은 콜백을 찾는 키라서 사람이 읽는 말이 아닐 수
|
|
411
|
-
있다 — 한국어 스물셋 사이에 「MES Disposition Approval」 하나가 그렇게 떴다.
|
|
412
|
-
-->
|
|
413
|
-
<!--
|
|
414
|
-
이름이 상세로 가는 문이다. 전에는 이 화면에 나가는 자리가 하나도 없었고(navigate 0 ·
|
|
415
|
-
<a href> 0), 카드가 「결재선 없음」이라고 적어 놓고 어디서 정하는지는 말하지 않았다.
|
|
416
|
-
[확인함 2026-09-23] 결재선 하나를 세워 확인하는 데 화면 셋, 역할에 사람이 없으면 다섯.
|
|
417
|
-
|
|
418
|
-
카드 전체가 아니라 **이름만** 문으로 둔다 — 카드 안에 펼치는 절이 있어서, 카드를 누르면
|
|
419
|
-
펼치려던 사람이 화면을 떠나게 된다.
|
|
420
|
-
-->
|
|
421
|
-
<a class="name" @click=${() => navigate(`activity-detail?name=${encodeURIComponent(one.name)}`)}
|
|
422
|
-
>${shownName(one)}</a
|
|
423
|
-
>
|
|
424
|
-
|
|
425
|
-
<!--
|
|
426
|
-
단계를 카드 머리에 둔다.
|
|
427
|
-
한 판에서 이것을 개발 정보 안으로 옮겼다가 되돌렸다. 업무가 마흔을 넘고 그중 대부분이 아직
|
|
428
|
-
안 만든 것이면, 접힌 절 안에 든 단계는 하나씩 펼쳐야 아는 값이 된다. 그러면 목록이 다
|
|
429
|
-
같아 보인다.
|
|
430
|
-
-->
|
|
431
|
-
${stage ? html `<span class="stage" data-stage=${stage}>${i18next.t('label.readiness-' + stage)}</span>` : ''}
|
|
432
|
-
${registered
|
|
433
|
-
? html `<span class="use" ?idle=${!inUse}
|
|
434
|
-
>${inUse ? i18next.t('text.activity-in-use-here') : i18next.t('text.activity-not-in-use-here')}</span
|
|
435
|
-
>`
|
|
436
|
-
: ''}
|
|
437
|
-
</div>
|
|
438
|
-
|
|
439
|
-
${this.renderGuide(one)} ${registered ? this.renderApprovers(one) : ''} ${this.renderBuild(one)}
|
|
440
|
-
</li>`;
|
|
441
246
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
* 우리끼리 쓰는 영어 한 줄이라 여기에 그대로 내지 않는다. 한국어 화면에서 영어 한 줄은 설명이
|
|
448
|
-
* 아니다.
|
|
449
|
-
*
|
|
450
|
-
* 없으면 **한 줄로** 없다고 말한다. 없는 것을 여러 줄로 늘리지 않는다.
|
|
451
|
-
*/
|
|
452
|
-
/**
|
|
453
|
-
* Reads declared sentences in the reader's language, falling back to the sentence as declared
|
|
454
|
-
* when there is no key or no translation for it. Lines and keys pair by position, as guide does.
|
|
455
|
-
*/
|
|
456
|
-
readSentences(lines, keys) {
|
|
457
|
-
return (lines || []).map((line, n) => (keys?.[n] ? String(i18next.t(keys[n], { defaultValue: line })) : line));
|
|
458
|
-
}
|
|
459
|
-
renderGuide(one) {
|
|
460
|
-
/* 줄을 고르는 판단은 상세 화면과 한 벌로 둔다 — 두 벌이면 같은 업무가 두 화면에서 달라진다. */
|
|
461
|
-
const lines = guideLines(one, (key, options) => i18next.t(key, options));
|
|
462
|
-
if (!lines.length) {
|
|
463
|
-
return html `<p class="unwritten">${i18next.t('text.activity-guide-unwritten')}</p>`;
|
|
247
|
+
async load() {
|
|
248
|
+
this.loadError = null;
|
|
249
|
+
let response;
|
|
250
|
+
try {
|
|
251
|
+
response = await client.query({ query: CATALOG, fetchPolicy: 'no-cache' });
|
|
464
252
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
* 이 공장이 이 단계를 쓰나 — **결재선에 결재자가 있나.**
|
|
469
|
-
*
|
|
470
|
-
* 결재선은 양식이 아니라 그 현장이 정하는 것이라, 같은 업무가 어느 공장에서는 결재를 받고 어느
|
|
471
|
-
* 공장에서는 그냥 지나간다. 그 사실이 지금까지 기동 로그 한 줄에만 있었다.
|
|
472
|
-
*
|
|
473
|
-
* **사람 수가 아니라 단계 수다** — 역할로 걸린 한 단계는 여러 사람이 본다. 그리고 비어 있다는 것이
|
|
474
|
-
* 무슨 일을 뜻하는지는 업무마다 달라서(상신이 막히거나, 확인 없이 지나가거나) 여기서 결과를 말하지
|
|
475
|
-
* 않는다. 그건 그 업무의 설명이 할 말이다.
|
|
476
|
-
*
|
|
477
|
-
* 「아직 사용 안 함」인 카드에는 그리지 않는다 — 세워지지 않은 양식에 결재선이 있을 수 없다.
|
|
478
|
-
*/
|
|
479
|
-
renderApprovers(one) {
|
|
480
|
-
if (!one.activity?.id) {
|
|
481
|
-
return '';
|
|
253
|
+
catch (error) {
|
|
254
|
+
this.loadError = error;
|
|
255
|
+
return;
|
|
482
256
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
? i18next.t('text.approval-line-steps', { n: steps })
|
|
491
|
-
: html `<span class="unwritten">${i18next.t('text.approval-line-empty')}</span>`}
|
|
492
|
-
</dd>
|
|
493
|
-
</dl>`;
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* 개발 정보 — **값이 있을 때만.**
|
|
497
|
-
*
|
|
498
|
-
* 첫 판은 값이 없어도 「…선언되지 않았습니다」를 네 줄 그렸다. 사용자에게는 뜻 없는 벽이고 우리에게도
|
|
499
|
-
* 아무 정보가 아니다. 아무것도 없으면 이 절 자체를 그리지 않는다 — 그 업무가 카탈로그에 「개발 정보
|
|
500
|
-
* 없음」으로 남는 것은 화면 위쪽의 목적을 방해하지 않는다.
|
|
501
|
-
*/
|
|
502
|
-
renderBuild(one) {
|
|
503
|
-
const readiness = one.readiness || {};
|
|
504
|
-
const stage = canonicalStage(readiness.stage);
|
|
505
|
-
const run = readiness.lastRun;
|
|
506
|
-
const hasRun = run && typeof run.total == 'number';
|
|
507
|
-
const built = this.renderBuilt(one);
|
|
508
|
-
if (!stage && !built && !readiness.tests?.length && !hasRun && !readiness.notes && !readiness.gaps?.length) {
|
|
509
|
-
return '';
|
|
257
|
+
/*
|
|
258
|
+
* 못 읽은 것을 빈 목록으로 그리지 않는다. 「업무가 하나도 없습니다」와 「못 읽었습니다」는 사람이 할
|
|
259
|
+
* 일이 다르다. ox-page-state 가 서버의 문장과 다시 읽기를 그린다(ADR-0060 결정 8).
|
|
260
|
+
*/
|
|
261
|
+
if (response.errors?.length) {
|
|
262
|
+
this.loadError = response.errors[0];
|
|
263
|
+
return;
|
|
510
264
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
:
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
:
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
? html `<dt>${i18next.t('field.readiness-notes')}</dt>
|
|
534
|
-
<dd>
|
|
535
|
-
${one.readinessNotesTKey
|
|
536
|
-
? i18next.t(one.readinessNotesTKey, { defaultValue: readiness.notes })
|
|
537
|
-
: readiness.notes}
|
|
538
|
-
</dd>`
|
|
539
|
-
: ''}
|
|
540
|
-
</dl>
|
|
541
|
-
</details>`;
|
|
265
|
+
const guides = new Map((response.data?.installableActivities?.items ?? []).map((one) => [one.name, one]));
|
|
266
|
+
/* 전선의 철자를 여기서 **한 번** 옮긴다(§`door-words`). */
|
|
267
|
+
this.doors = (response.data?.workDoors?.doors ?? []).map((one) => ({
|
|
268
|
+
...one,
|
|
269
|
+
standing: standingWord(one.standing) ?? one.standing,
|
|
270
|
+
kind: kindWord(one.kind) ?? one.kind,
|
|
271
|
+
reason: reasonWord(one.reason) ?? one.reason,
|
|
272
|
+
whenNoLine: whenNoLineWord(one.whenNoLine),
|
|
273
|
+
whenNoLineBecause: whenNoLineBecauseWord(one.whenNoLineBecause),
|
|
274
|
+
about: guideLines(guides.get(one.name), (key, options) => i18next.t(key, options))[0]
|
|
275
|
+
}));
|
|
276
|
+
const read = response.data?.workDoors ?? {};
|
|
277
|
+
this.todo = read.todo ?? 0;
|
|
278
|
+
this.counts = {
|
|
279
|
+
on: read.on ?? 0,
|
|
280
|
+
off: read.off ?? 0,
|
|
281
|
+
missing: read.missing ?? 0,
|
|
282
|
+
notUsed: read.notUsed ?? 0,
|
|
283
|
+
todo: this.todo
|
|
284
|
+
};
|
|
285
|
+
this.seatsStanding = read.seatsStanding ?? 0;
|
|
286
|
+
this.seatsOffered = read.seatsOffered ?? 0;
|
|
542
287
|
}
|
|
543
|
-
/**
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
* 이 화면은 단계 이름 하나로 「계획」·「동작함」만 말했다. 그런데 사용자가 카탈로그를 보고 물은 것은
|
|
547
|
-
* 「화면 설정도 없이 이게 정의냐」였고, 화면이 그 칸을 안 보이니 세는 사람이 파일을 열어야 했다.
|
|
548
|
-
* 액티비티가 서려면 주고받는 값과 화면과 콜백이 있어야 하고, 선언만 된 항목에는 그중 아무것도 없다.
|
|
549
|
-
*
|
|
550
|
-
* 설치되지 않은 항목에는 그리지 않는다. 45건에 「없음 · 없음 · 없음」을 세 줄씩 붙이면 그 자체가
|
|
551
|
-
* 벽이고, 무엇이 없는지는 그 항목의 gaps 가 이미 사람 말로 적고 있다.
|
|
552
|
-
*/
|
|
553
|
-
renderBuilt(one) {
|
|
554
|
-
if (!one.activity?.id) {
|
|
288
|
+
/** 결재선은 각 업무에서 지정하고, 역할이 부족할 때만 별도로 안내한다. */
|
|
289
|
+
renderNext() {
|
|
290
|
+
if (!this.todo || this.seatsStanding >= this.seatsOffered) {
|
|
555
291
|
return '';
|
|
556
292
|
}
|
|
557
|
-
const model = (one.model || []).filter((item) => !item?.hidden);
|
|
558
|
-
const taking = model.filter((item) => item?.inout == 'in' || item?.inout == 'inout').length;
|
|
559
|
-
const giving = model.filter((item) => item?.inout == 'out' || item?.inout == 'inout').length;
|
|
560
|
-
const decisions = (one.activity?.decisionKeys || []).length;
|
|
561
|
-
/*
|
|
562
|
-
* 결재 화면이 무엇으로 그려지나. 전용 요소는 이름까지 적는다 — 「전용 화면이 있다」만으로는 어느
|
|
563
|
-
* 것인지 못 찾고, 이 절을 읽는 사람은 그 파일을 열려는 사람이다.
|
|
564
|
-
*
|
|
565
|
-
* 선언이 채워지면 기본 화면도 판단을 그린다. 그래서 「기본 화면」 뒤에 판단 항목 수가 붙는다 —
|
|
566
|
-
* 0 이면 그 화면은 아직 칸 목록이다.
|
|
567
|
-
*/
|
|
568
|
-
const screen = one.viewSource
|
|
569
|
-
? html `${i18next.t('text.own-approval-view')} · <code>${one.viewSource}</code>`
|
|
570
|
-
: html `${i18next.t('text.generated-approval-view')}`;
|
|
571
293
|
return html `
|
|
572
|
-
<
|
|
573
|
-
|
|
574
|
-
|
|
294
|
+
<section class="page-section">
|
|
295
|
+
<div class="page-section-header"><h3>${i18next.t('title.work-doors-next')}</h3></div>
|
|
296
|
+
<ol class="next">
|
|
297
|
+
<li>
|
|
298
|
+
${i18next.t('text.work-doors-next-seats', {
|
|
299
|
+
standing: this.seatsStanding,
|
|
300
|
+
offered: this.seatsOffered
|
|
301
|
+
})}
|
|
302
|
+
<a class="page-nav-link" href="roles">${i18next.t('field.roles')}</a>
|
|
303
|
+
</li>
|
|
304
|
+
</ol>
|
|
305
|
+
</section>
|
|
575
306
|
`;
|
|
576
307
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
month: 'numeric',
|
|
584
|
-
day: 'numeric',
|
|
585
|
-
hour: 'numeric',
|
|
586
|
-
minute: '2-digit',
|
|
587
|
-
hour12: false
|
|
588
|
-
})
|
|
589
|
-
: '';
|
|
590
|
-
return html `${typeof run.passed == 'number' ? run.passed : '—'} /
|
|
591
|
-
${run.total}${when ? html ` · ${when}` : ''}${run.command ? html `<div><code>${run.command}</code></div>` : ''}`;
|
|
308
|
+
render() {
|
|
309
|
+
return html `<div class="page">
|
|
310
|
+
<ox-page-state .loading=${!this.doors && !this.loadError} .error=${this.loadError} @retry=${() => this.load()}
|
|
311
|
+
>${this.doors && !this.loadError ? this.renderDoors() : ''}</ox-page-state
|
|
312
|
+
>
|
|
313
|
+
</div>`;
|
|
592
314
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
315
|
+
renderDoors() {
|
|
316
|
+
const sorted = [...this.doors].sort((a, b) => ORDER[a.standing] - ORDER[b.standing]);
|
|
317
|
+
return html `
|
|
318
|
+
<section class="page-section">
|
|
319
|
+
<p class="state">${doorsSummary(i18next.t, this.counts)}</p>
|
|
320
|
+
<ul class="doors">
|
|
321
|
+
${sorted.map(door => this.renderDoor(door))}
|
|
322
|
+
</ul>
|
|
323
|
+
</section>
|
|
324
|
+
|
|
325
|
+
${this.renderNext()}
|
|
326
|
+
`;
|
|
597
327
|
}
|
|
598
328
|
/**
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
* 메뉴에서 눌러 들어오면 화면이 꺼졌다 켜지면서 `pageUpdated` 가 오고 거기서 읽는다. 그런데 주소를
|
|
602
|
-
* 직접 열면 이 요소가 **이미 active 인 채로** 만들어져서 그 전환이 없다. 실측했다: `active` 는
|
|
603
|
-
* 참인데 `loaded` 가 거짓이고, 화면은 아무것도 없이 조용했다 — 오류도 빈 화면 문구도 없다.
|
|
604
|
-
*
|
|
605
|
-
* 목록 화면들은 이 자리가 안 비어 있다. grist 가 첫 렌더에서 스스로 `fetchHandler` 를 부르기
|
|
606
|
-
* 때문이다. 이 화면은 grist 를 안 쓰니 부르는 사람이 없었다.
|
|
607
|
-
*
|
|
608
|
-
* 그래서 켜져 있는데 아직 안 읽었으면 여기서 읽는다. `loaded` 가 그 조건이라 두 번 읽지 않는다.
|
|
329
|
+
* Where 「결재선 지정」 goes: this activity's detail, or - when it follows another activity's line - that
|
|
330
|
+
* activity's, since the line is set there. None for a form borrowed from another site.
|
|
609
331
|
*/
|
|
610
|
-
|
|
611
|
-
if (
|
|
612
|
-
|
|
332
|
+
lineEditAddress(door) {
|
|
333
|
+
if (door.kind !== 'approval' || (door.standing !== 'on' && door.standing !== 'off')) {
|
|
334
|
+
return '';
|
|
613
335
|
}
|
|
336
|
+
const owner = door.followsLabelKey ? this.doors.find(one => one.labelKey === door.followsLabelKey) : door;
|
|
337
|
+
return owner && opensDetail(owner) && opensDetail(door) ? detailAddress(owner.name) : '';
|
|
614
338
|
}
|
|
615
|
-
|
|
616
|
-
const
|
|
339
|
+
renderDoor(door) {
|
|
340
|
+
const label = doorLabel(i18next.t, door);
|
|
341
|
+
const steps = (door.approvalLine || []).filter(isApprovalStep).length;
|
|
342
|
+
const drawsLine = door.kind === 'approval' && steps > 0;
|
|
343
|
+
const note = lineNote(i18next.t, door, drawsLine);
|
|
344
|
+
const follows = followsNote(i18next.t, door);
|
|
345
|
+
const when = whenNoLineTag(i18next.t, door);
|
|
346
|
+
const edit = this.lineEditAddress(door);
|
|
347
|
+
return html `
|
|
348
|
+
<li class="door ${door.standing}">
|
|
349
|
+
<div class="what">
|
|
350
|
+
${opensDetail(door)
|
|
351
|
+
? html `<a class="name" href=${detailAddress(door.name)}>${label}</a>`
|
|
352
|
+
: html `<span class="name">${label}</span>`}
|
|
353
|
+
<span class="kind">${i18next.t(`text.door-kind-${door.kind}`)}</span>
|
|
354
|
+
<span class="mark ${door.standing}">${i18next.t(`text.door-standing-${door.standing}`)}</span>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="says">
|
|
357
|
+
${door.about ? html `<span class="about">${door.about}</span>` : ''}
|
|
358
|
+
${drawsLine || note || edit
|
|
359
|
+
? html `<div class="line">
|
|
360
|
+
${drawsLine
|
|
361
|
+
? html `<approval-line-brief
|
|
362
|
+
plan
|
|
363
|
+
style="--seats: ${(door.approvalLine || []).length + 1}"
|
|
364
|
+
.model=${door.approvalLine}
|
|
365
|
+
></approval-line-brief>`
|
|
366
|
+
: ''}
|
|
367
|
+
${note ? html `<span>${note}</span>` : ''}
|
|
368
|
+
${edit
|
|
369
|
+
? html `<a class="page-nav-link" href=${edit}>${i18next.t('button.activity-set-approval-line')}</a>`
|
|
370
|
+
: ''}
|
|
371
|
+
</div>`
|
|
372
|
+
: ''}
|
|
373
|
+
${follows ? html `<span class="when">${follows}</span>` : ''}
|
|
374
|
+
${when ? html `<span class="when">${when}</span>` : ''}
|
|
375
|
+
${
|
|
617
376
|
/*
|
|
618
|
-
*
|
|
619
|
-
*
|
|
377
|
+
* 남의 양식을 쓰는 것은 정상이지만, 안 말하면 「정한 적 없는데」가 된다. 차 있으면 어디서
|
|
378
|
+
* 정했는지, 비어 있으면 여기서는 못 고친다는 것을 말한다.
|
|
620
379
|
*/
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
this.items = [...items].sort((a, b) => stageRank(a.readiness?.stage) - stageRank(b.readiness?.stage) || shownName(a).localeCompare(shownName(b)));
|
|
632
|
-
this.loaded = true;
|
|
380
|
+
door.from
|
|
381
|
+
? html `<span class="from"
|
|
382
|
+
>${door.standing === 'on'
|
|
383
|
+
? i18next.t('text.door-filled-from', { name: door.from })
|
|
384
|
+
: i18next.t('text.door-form-from', { name: door.from })}</span
|
|
385
|
+
>`
|
|
386
|
+
: ''}
|
|
387
|
+
</div>
|
|
388
|
+
</li>
|
|
389
|
+
`;
|
|
633
390
|
}
|
|
634
391
|
};
|
|
635
392
|
__decorate([
|
|
636
393
|
state(),
|
|
637
394
|
__metadata("design:type", Array)
|
|
638
|
-
], ActivityCatalogPage.prototype, "
|
|
395
|
+
], ActivityCatalogPage.prototype, "doors", void 0);
|
|
396
|
+
__decorate([
|
|
397
|
+
state(),
|
|
398
|
+
__metadata("design:type", Object)
|
|
399
|
+
], ActivityCatalogPage.prototype, "counts", void 0);
|
|
400
|
+
__decorate([
|
|
401
|
+
state(),
|
|
402
|
+
__metadata("design:type", Object)
|
|
403
|
+
], ActivityCatalogPage.prototype, "todo", void 0);
|
|
639
404
|
__decorate([
|
|
640
405
|
state(),
|
|
641
406
|
__metadata("design:type", Object)
|
|
642
|
-
], ActivityCatalogPage.prototype, "
|
|
407
|
+
], ActivityCatalogPage.prototype, "seatsStanding", void 0);
|
|
643
408
|
__decorate([
|
|
644
409
|
state(),
|
|
645
410
|
__metadata("design:type", Object)
|
|
646
|
-
], ActivityCatalogPage.prototype, "
|
|
411
|
+
], ActivityCatalogPage.prototype, "seatsOffered", void 0);
|
|
647
412
|
__decorate([
|
|
648
413
|
state(),
|
|
649
414
|
__metadata("design:type", Object)
|