feat(plan): 형상계획 ②에 교대 부재 목록과 부재별 카드 추가 (1단계)

- 부재 · 교대 목록(받침, 벽체·흉벽, 날개벽, 접속슬래브, 지반·지층)과 각 행의 값·변경 표시 (src/core/abut/member-list.ts)
- 행을 누르면 그 부재의 카드만 표시. 날개벽 형식은 별도 카드로 분리
- 접속슬래브·지반·지층은 값만 표시 (입력은 2단계)
- 모델 변경 없음. 테스트 630건 통과, 타입 검사·빌드 통과. 브라우저 시각 확인은 미실시

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-03 15:10:47 +09:00
1 parent 929f8eb4a2
commit 18524460e8
5 files changed
+169 -2

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
import type { WingForm } from './geometry';
import { ABUT_SHAPE_DEFAULT, type AbutShape } from './shape';
/** 부재 · 교대 list in ② (시안): the card each row opens. */
export type AbutMemberId = 'bearing' | 'shape' | 'wing' | 'slab' | 'ground';
/** Cards that take input in this step; slab and ground only show their values (phase 1, 2026-11-03). */
export const ABUT_MEMBER_EDITABLE: Record<AbutMemberId, boolean> = {
bearing: true,
shape: true,
wing: true,
slab: false,
ground: false,
};
const WING_LABEL: Record<WingForm, string> = { general: '일반형', short: '단축형', none: '없음' };
/** The subset of an abutment record the list reads. */
export interface AbutMemberInput {
bearings: { seatEl?: number }[];
shape?: Partial<AbutShape>;
wings?: { left: WingForm; right: WingForm };
groundEl: number;
}
export interface AbutMemberRow {
id: AbutMemberId;
label: string;
summary: string;
/** True when the value differs from the default (or a 받침 has its own 교좌면 EL). */
changed: boolean;
}
/**
* The five rows of the 부재 · 교대 list. `slabWidth` is the computed 접속슬래브 폭 text, passed in
* so this stays a pure function of the record.
*/
export function abutMemberRows(rec: AbutMemberInput, slabWidth: string): AbutMemberRow[] {
const shape = { ...ABUT_SHAPE_DEFAULT, ...(rec.shape ?? {}) };
const shapeChanged = (Object.keys(ABUT_SHAPE_DEFAULT) as (keyof AbutShape)[]).some(
(key) => (rec.shape?.[key] ?? ABUT_SHAPE_DEFAULT[key]) !== ABUT_SHAPE_DEFAULT[key],
);
const wings = rec.wings ?? { left: 'general' as WingForm, right: 'general' as WingForm };
return [
{
id: 'bearing',
label: '교량받침·받침블럭·솔플레이트',
summary: `${rec.bearings.length}개 · z = 패드 상면`,
changed: rec.bearings.some((b) => b.seatEl !== undefined),
},
{
id: 'shape',
label: '벽체·흉벽',
summary: `벽체 두께 ${shape.wallThicknessMm} · 흉벽 ${shape.parapetHeightMm}`,
changed: shapeChanged,
},
{
id: 'wing',
label: '날개벽',
summary: `좌 ${WING_LABEL[wings.left]} · 우 ${WING_LABEL[wings.right]}`,
changed: wings.left !== 'general' || wings.right !== 'general',
},
{ id: 'slab', label: '접속슬래브', summary: slabWidth, changed: false },
{ id: 'ground', label: '지반·지층', summary: `지반고 ${rec.groundEl.toFixed(3)} m`, changed: false },
];
}