- 기초단가 표: 칸 나갈 때 즉시 저장 없앰 · 고친 칸·새 줄·지울 줄은 초안(sessionStorage z01-draft:base:{kind})에 쌓고 [저장] 한 번에 보냄 · [고친 것 버리기]·[줄 추가]·[줄 삭제]·[초기값으로] · 409 면 초안 지키고 알림 · 서버가 revision 을 줄 때만 고치기 단추 섬
- 옛 덮개 길(칸 단위 PUT · 고친 것 모아 보기 · 덮개 판정 표시)과 그 사전 글자 뺌 — 계약 1-0 에서 서버 쪽 삭제
- 공종 편집(Z01_MasterData_UI_WorkItem.ts · _WorkItem_Rows.ts): 왼쪽 목록(상태별 개수·검색) / 머리 / 구성 줄 표(갈래별 · 자원 찾기 = 기초단가 검색) / 품셈 원문 표+[주] 읽기 전용 / [저장]·[초기값으로]·[검수 완료] · 초안 열쇠 z01-draft:work_item:{key}
- 공종 API(sub_laptop_3 e1c71c3e) 모양에 맞춤 — 줄은 id + 계약 칸 열하나만 보냄(extra=forbid) · 저장·초기값 응답(새 GET 모양)으로 바로 다시 그림 · 저장된 고침(changed_columns·is_added) 표시
- 초안 순수 함수 Z01_MasterData_UI_Draft.ts + 시험 test_z01_master_draft.py
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0145cr1DMC5Ft8fouQSXtp69
519 lines
12 KiB
CSS
519 lines
12 KiB
CSS
/* Z01 마스터 데이터 — 좌측 도킹 사이드바(기초단가 · 마스터 트리) / 우측 표 */
|
|
.z01-master [hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* ── 좌측 패널: B08 과 같은 상자 틀(겉선·접기는 공용 ui-sidebar-section · ui-collapsible) ── */
|
|
.z01-master__side {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-8);
|
|
padding-top: var(--spacing-8);
|
|
}
|
|
|
|
.z01-master__section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-4);
|
|
margin: 0;
|
|
padding: 10px 12px;
|
|
border-radius: var(--radius-cards);
|
|
background-color: var(--color-surface-raised);
|
|
}
|
|
|
|
.z01-master__section-title {
|
|
margin: 0 0 2px;
|
|
color: var(--color-text-secondary);
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.z01-master__base-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: var(--spacing-4);
|
|
}
|
|
|
|
.z01-master__base {
|
|
padding: var(--spacing-4) var(--spacing-8);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-buttons);
|
|
background: var(--color-surface);
|
|
color: var(--color-text-body);
|
|
font: inherit;
|
|
font-size: var(--text-body-sm);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.z01-master__base--wide {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.z01-master__base:hover,
|
|
.z01-master__table:hover {
|
|
background: var(--color-paper);
|
|
}
|
|
|
|
.z01-master__base.is-active,
|
|
.z01-master__table.is-active {
|
|
background: var(--color-mist-violet);
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
.z01-master__tree {
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__tree summary {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-8);
|
|
padding: var(--spacing-4) var(--spacing-4);
|
|
cursor: pointer;
|
|
color: var(--color-text-body);
|
|
}
|
|
|
|
.z01-master__group > summary {
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.z01-master__file {
|
|
margin-left: var(--spacing-12);
|
|
}
|
|
|
|
.z01-master__key {
|
|
margin-left: var(--spacing-4);
|
|
color: var(--color-text-muted);
|
|
font-size: var(--text-caption);
|
|
font-weight: var(--font-weight-regular);
|
|
}
|
|
|
|
.z01-master__note {
|
|
margin: 0 var(--spacing-8) var(--spacing-4);
|
|
color: var(--color-text-muted);
|
|
font-size: var(--text-caption);
|
|
}
|
|
|
|
.z01-master__table {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: var(--spacing-8);
|
|
width: 100%;
|
|
padding: var(--spacing-4) var(--spacing-8) var(--spacing-4) var(--spacing-24);
|
|
border: 0;
|
|
border-radius: var(--radius-sm);
|
|
background: transparent;
|
|
color: var(--color-text-body);
|
|
font: inherit;
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* ── 우측 표 ── */
|
|
.z01-master__panel {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-12);
|
|
min-width: 0;
|
|
padding: var(--spacing-16) var(--spacing-24);
|
|
}
|
|
|
|
.z01-master__title {
|
|
display: inline;
|
|
color: var(--color-text);
|
|
font-size: var(--text-body);
|
|
}
|
|
|
|
/* 뒤처진 자료 띠 — 받는 자리까지 적힘 · 또렷이 · 원본마다 한 줄 */
|
|
.z01-master__outdated p {
|
|
margin: 0;
|
|
}
|
|
|
|
.z01-master__outdated {
|
|
margin: 0;
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
border-left: 4px solid var(--color-danger);
|
|
background: color-mix(in srgb, var(--color-danger) 12%, var(--color-canvas));
|
|
color: var(--color-danger);
|
|
font-size: var(--text-body-sm);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
/* 표 머리 알림 — 고친 값이 닿는 자리·법정값 경고. 흐리면 「저장이 안 됐다」로 읽힘(2026-09-16 브레인) */
|
|
.z01-master__notice {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-4);
|
|
margin: 0;
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
border-left: 4px solid var(--color-accent);
|
|
background: var(--color-mist-violet);
|
|
color: var(--color-accent);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__notice p {
|
|
margin: 0;
|
|
}
|
|
|
|
.z01-master__toolbar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: var(--spacing-16);
|
|
}
|
|
|
|
.z01-master__check {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-4);
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
/* 칸 설명 줄 — 고칠 수 있나 · 까닭 · 원래 값 · 산출근거 */
|
|
.z01-master__detail {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
gap: var(--spacing-4) var(--spacing-12);
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-cards);
|
|
background: var(--color-surface);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__detail-line {
|
|
color: var(--color-text-body);
|
|
}
|
|
|
|
.z01-master__detail-line.is-warning {
|
|
color: var(--color-danger);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
.z01-master__grid-wrap {
|
|
max-height: calc(100vh - 320px);
|
|
overflow: auto;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-cards);
|
|
}
|
|
|
|
.z01-master__grid-wrap.is-loading {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.z01-master__grid {
|
|
border-collapse: collapse;
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__grid th,
|
|
.z01-master__grid td {
|
|
max-width: 320px;
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
overflow: hidden;
|
|
border-bottom: 1px solid var(--color-border);
|
|
text-align: left;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.z01-master__grid th {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1;
|
|
background: var(--color-surface);
|
|
color: var(--color-text-secondary);
|
|
font-weight: var(--font-weight-medium);
|
|
}
|
|
|
|
.z01-master__grid th .z01-master__key {
|
|
display: block;
|
|
margin-left: 0;
|
|
}
|
|
|
|
.z01-master__grid th.is-sortable {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.z01-master__sort {
|
|
margin-left: var(--spacing-4);
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
.z01-master__mark {
|
|
margin-left: var(--spacing-4);
|
|
cursor: help;
|
|
}
|
|
|
|
.z01-master__grid td.is-editable {
|
|
cursor: text;
|
|
text-decoration: underline dotted var(--color-text-muted);
|
|
}
|
|
|
|
.z01-master__grid td.is-selected {
|
|
outline: 2px solid var(--color-accent);
|
|
outline-offset: -2px;
|
|
}
|
|
|
|
/* 고쳐짐 — 덮개 값을 쓰는 칸 */
|
|
.z01-master__grid td.is-overridden {
|
|
background: var(--color-mist-violet);
|
|
color: var(--color-accent);
|
|
font-weight: var(--font-weight-medium);
|
|
}
|
|
|
|
/* 원본 바뀜 · 주인 없음 · 판정 없음 — 줄째 또렷이(흐리면 옛 값이 조용히 쓰임) */
|
|
.z01-master__grid tr.has-warning td {
|
|
background: color-mix(in srgb, var(--color-danger) 8%, var(--color-canvas));
|
|
}
|
|
|
|
.z01-master__grid tr.has-warning td:first-child,
|
|
.z01-master__grid tr.has-danger td:first-child {
|
|
box-shadow: inset 4px 0 0 var(--color-danger);
|
|
}
|
|
|
|
/* 뜻 바뀜 — 값 어긋남보다 나쁨(같은 번호에 딴 물건). 줄째 더 진하게. */
|
|
.z01-master__grid tr.has-danger td {
|
|
background: color-mix(in srgb, var(--color-danger) 18%, var(--color-canvas));
|
|
}
|
|
|
|
.z01-master__grid tr td.is-meaning-changed {
|
|
background: var(--color-danger);
|
|
color: var(--color-primary-text);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
/* tr 을 넣어 줄 배경(tr.has-warning td)보다 무겁게 — 칸이 줄보다 더 진해야 함 */
|
|
.z01-master__grid tr td.is-source-changed,
|
|
.z01-master__grid tr td.is-orphan,
|
|
.z01-master__grid tr td.is-missing {
|
|
background: color-mix(in srgb, var(--color-danger) 22%, var(--color-canvas));
|
|
color: var(--color-danger);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
.z01-master__cell-input {
|
|
width: 100%;
|
|
min-width: 6em;
|
|
padding: 2px var(--spacing-4);
|
|
}
|
|
|
|
.z01-master__pager {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
gap: var(--spacing-12);
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__page-input {
|
|
width: 6em;
|
|
text-align: right;
|
|
}
|
|
|
|
/* ── 고치기 — 저장 전 초안 · 저장된 고침(초기값과 다름) · 새 줄 · 지울 줄 (PLAN 1-4) ── */
|
|
.z01-master__grid td.is-draft,
|
|
.z01-wi__field.is-draft {
|
|
background: color-mix(in srgb, var(--color-warning) 24%, var(--color-canvas));
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
.z01-master__grid td.is-changed,
|
|
.z01-wi__field.is-changed {
|
|
background: var(--color-mist-violet);
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
.z01-master__grid tr.is-new td {
|
|
background: color-mix(in srgb, var(--color-success) 12%, var(--color-canvas));
|
|
}
|
|
|
|
.z01-master__grid tr.is-added td:first-child {
|
|
box-shadow: inset 4px 0 0 var(--color-success);
|
|
}
|
|
|
|
.z01-master__grid tr.is-deleted td {
|
|
color: var(--color-text-muted);
|
|
text-decoration: line-through;
|
|
}
|
|
|
|
.z01-master__draft-status {
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-master__draft-status.is-warning {
|
|
color: var(--color-danger);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
/* ── 공종 편집 — 왼쪽 목록 / 오른쪽 머리·구성 줄·원문 ── */
|
|
.z01-master__panel.z01-wi {
|
|
display: grid;
|
|
grid-template-columns: minmax(200px, 260px) minmax(0, 1fr);
|
|
align-items: start;
|
|
gap: var(--spacing-16);
|
|
}
|
|
|
|
.z01-wi__side {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-8);
|
|
position: sticky;
|
|
top: 0;
|
|
}
|
|
|
|
.z01-wi__list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: calc(100vh - 260px);
|
|
overflow: auto;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-cards);
|
|
}
|
|
|
|
.z01-wi__list.is-loading {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.z01-wi__item {
|
|
display: grid;
|
|
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
align-items: center;
|
|
gap: var(--spacing-4) var(--spacing-8);
|
|
padding: var(--spacing-4) var(--spacing-8);
|
|
border: 0;
|
|
border-bottom: 1px solid var(--color-border);
|
|
background: transparent;
|
|
color: var(--color-text-body);
|
|
font: inherit;
|
|
font-size: var(--text-body-sm);
|
|
text-align: left;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.z01-wi__item:hover {
|
|
background: var(--color-paper);
|
|
}
|
|
|
|
.z01-wi__item.is-active {
|
|
background: var(--color-mist-violet);
|
|
color: var(--color-accent);
|
|
}
|
|
|
|
.z01-wi__item-name {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.z01-wi__status {
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-caption);
|
|
}
|
|
|
|
.z01-wi__status.is-needs-input,
|
|
.z01-wi__status.is-partial,
|
|
.z01-wi__unmatched {
|
|
color: var(--color-danger);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
.z01-wi__status.is-reviewed {
|
|
color: var(--color-success);
|
|
}
|
|
|
|
.z01-wi__editor {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-12);
|
|
min-width: 0;
|
|
}
|
|
|
|
.z01-wi__head {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
gap: var(--spacing-8) var(--spacing-16);
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-cards);
|
|
background: var(--color-surface);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-wi__head:empty {
|
|
display: none;
|
|
}
|
|
|
|
.z01-wi__field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
padding: 2px var(--spacing-4);
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
.z01-wi__label {
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-caption);
|
|
}
|
|
|
|
.z01-wi__heading {
|
|
margin: 0;
|
|
color: var(--color-text);
|
|
font-size: var(--text-body);
|
|
}
|
|
|
|
.z01-wi__variant {
|
|
margin: var(--spacing-8) 0 var(--spacing-4);
|
|
color: var(--color-text-secondary);
|
|
font-size: var(--text-body-sm);
|
|
}
|
|
|
|
.z01-wi__grid td {
|
|
padding: 2px var(--spacing-4);
|
|
}
|
|
|
|
.z01-wi__grid input,
|
|
.z01-wi__grid select {
|
|
min-width: 4em;
|
|
padding: 2px var(--spacing-4);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.z01-wi__grid select {
|
|
min-width: 6em;
|
|
}
|
|
|
|
.z01-wi__grid input[type="number"] {
|
|
width: 6em;
|
|
}
|
|
|
|
.z01-wi__finder {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--spacing-8);
|
|
padding: var(--spacing-8) var(--spacing-12);
|
|
border: 2px solid var(--color-accent);
|
|
border-radius: var(--radius-cards);
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
.z01-wi__found {
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: 240px;
|
|
overflow: auto;
|
|
}
|
|
|
|
.z01-wi__notes {
|
|
margin: 0;
|
|
padding-left: 1.2em;
|
|
font-size: var(--text-body-sm);
|
|
}
|