feat(B01,B07): 설계일자 사용자 지정 입력 + 도면번호 자동 부여
사용자 확정(2026-09-02): 설계일자는 확정일 자동이 아니라 **사용자가 넣는다**. 도면번호는 Claude 판단으로 목록 순번을 쓴다. 설계일자 - `013_company_assets.sql` 로 `projects.design_date DATE` 추가(같은 마이그레이션에 로고·서명 공유 테이블 자리도 함께 만들었음 — 배선은 다음 커밋). - B01 프로젝트 수정 모달에 날짜 칸. 공용 `createInputField` 가 `type="date"` 를 받게 넓힘. - 표제란에는 도면 표기 관행대로 `2026. 09. 02.` 꼴로 적는다. 도면번호 - 단건 조회는 목록 순서를 모른다 — 알려면 횡단 장 계획을 다시 계산해야 하고 도면을 열 때마다 그러면 비싸다. **목록이 매긴 번호를 manifest 에 적어 두고** 단건 조회가 읽는다. 목록은 화면 진입 때 늘 먼저 뜨므로 성립하고, 목록이 바뀌면 다음 조회에서 다시 적힌다. - `add_title_fields()` 신설 — 도면을 읽는 도중에 아는 값을 문맥에 얹는 창구. 검증: `pytest tmp/tests/ -q` 139 passed / 0 failed, 루트 `tsc --noEmit` 통과. 실사용자 경로(5174, wdw) — 대시보드 [수정] 모달 라벨 10개(설계일자 칸 추가 확인) → `2026-09-02` 입력 → [확인] → 종단면도 표제란에 `2026. 09. 02.`. 도면번호는 목록 13건 기준 종단 1 · 유역도 6 · 용지도 13 이 도각에 그대로 실림 (표지는 도각을 두르지 않아 번호 칸이 없다). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ export interface ProjectItem {
|
||||
client_org?: string | null;
|
||||
project_number?: string | null;
|
||||
work_amount?: string | null;
|
||||
design_date?: string | null;
|
||||
owner_name?: string | null;
|
||||
workflow_stage: number;
|
||||
progress_percent: number;
|
||||
@@ -139,6 +140,7 @@ export interface UpdateProjectRequest {
|
||||
client_org?: string | null;
|
||||
project_number?: string | null;
|
||||
work_amount?: string | null;
|
||||
design_date?: string | null;
|
||||
}
|
||||
|
||||
export interface AdminUpdateUserRequest extends UpdateUserRequest {
|
||||
|
||||
@@ -149,7 +149,7 @@ async def list_user_projects(user_id: int) -> list[dict[str, Any]]:
|
||||
await cursor.execute(
|
||||
"""SELECT id, company_id, name, region, road_type, project_year,
|
||||
estimated_length_m, memo, status, updated_at, created_at,
|
||||
client_org, project_number, work_amount
|
||||
client_org, project_number, work_amount, design_date
|
||||
FROM projects WHERE user_id = %s AND deleted_at IS NULL
|
||||
ORDER BY updated_at DESC, created_at DESC""",
|
||||
(user_id,),
|
||||
@@ -171,7 +171,7 @@ async def list_company_projects(company_id: int) -> list[dict[str, Any]]:
|
||||
await cursor.execute(
|
||||
"""SELECT p.id, p.company_id, p.name, p.region, p.road_type, p.project_year,
|
||||
p.estimated_length_m, p.memo, p.status, p.updated_at, p.created_at,
|
||||
p.client_org, p.project_number, p.work_amount,
|
||||
p.client_org, p.project_number, p.work_amount, p.design_date,
|
||||
u.name AS owner_name, u.email AS owner_email
|
||||
FROM projects p LEFT JOIN users u ON u.id = p.user_id
|
||||
WHERE p.company_id = %s AND p.deleted_at IS NULL
|
||||
@@ -195,7 +195,7 @@ async def list_all_projects() -> list[dict[str, Any]]:
|
||||
await cursor.execute(
|
||||
"""SELECT p.id, p.company_id, p.name, p.region, p.road_type, p.project_year,
|
||||
p.estimated_length_m, p.memo, p.status, p.updated_at, p.created_at,
|
||||
p.client_org, p.project_number, p.work_amount,
|
||||
p.client_org, p.project_number, p.work_amount, p.design_date,
|
||||
u.name AS owner_name, u.email AS owner_email
|
||||
FROM projects p LEFT JOIN users u ON u.id = p.user_id
|
||||
WHERE p.deleted_at IS NULL
|
||||
@@ -218,7 +218,7 @@ async def get_project(project_id: str) -> dict[str, Any] | None:
|
||||
await cursor.execute(
|
||||
"""SELECT id, user_id, company_id, name, region, road_type, project_year,
|
||||
estimated_length_m, memo, status,
|
||||
client_org, project_number, work_amount
|
||||
client_org, project_number, work_amount, design_date
|
||||
FROM projects WHERE id = %s AND deleted_at IS NULL""",
|
||||
(project_id,),
|
||||
)
|
||||
@@ -233,7 +233,8 @@ async def update_project(project_id: str, data: dict[str, Any], actor_id: int) -
|
||||
"""UPDATE projects
|
||||
SET name = %s, region = %s, road_type = %s, project_year = %s,
|
||||
estimated_length_m = %s, memo = %s, status = COALESCE(%s, status),
|
||||
client_org = %s, project_number = %s, work_amount = %s
|
||||
client_org = %s, project_number = %s, work_amount = %s,
|
||||
design_date = %s
|
||||
WHERE id = %s AND deleted_at IS NULL""",
|
||||
(
|
||||
data["name"],
|
||||
@@ -246,6 +247,7 @@ async def update_project(project_id: str, data: dict[str, Any], actor_id: int) -
|
||||
data.get("client_org"),
|
||||
data.get("project_number"),
|
||||
data.get("work_amount"),
|
||||
data.get("design_date"),
|
||||
project_id,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""B01_Dashboard 요청 스키마."""
|
||||
|
||||
from datetime import date
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
@@ -50,6 +52,8 @@ class UpdateProjectRequest(BaseModel):
|
||||
client_org: str | None = Field(default=None, max_length=255)
|
||||
project_number: str | None = Field(default=None, max_length=100)
|
||||
work_amount: str | None = Field(default=None, max_length=100)
|
||||
# 설계일자는 확정일 자동이 아니라 사용자 지정이다 (2026-09-02 사용자 확정).
|
||||
design_date: date | None = None
|
||||
|
||||
|
||||
class AdminUpdateUserRequest(UpdateUserRequest):
|
||||
|
||||
@@ -105,6 +105,12 @@ export function openEditProjectModal(user: DashboardUser, project: ProjectItem):
|
||||
value: project.work_amount ?? "",
|
||||
placeholder: "예: L=2.14km",
|
||||
});
|
||||
// 설계일자는 확정일 자동이 아니라 사용자가 지정한다 (2026-09-02 사용자 확정).
|
||||
const designDate = createInputField({
|
||||
label: "설계일자 (도면 표제란)",
|
||||
type: "date",
|
||||
value: (project.design_date ?? "").slice(0, 10),
|
||||
});
|
||||
|
||||
if (isUserOnly) {
|
||||
name.input.disabled = true;
|
||||
@@ -116,6 +122,7 @@ export function openEditProjectModal(user: DashboardUser, project: ProjectItem):
|
||||
clientOrg.input.disabled = true;
|
||||
projectNumber.input.disabled = true;
|
||||
workAmount.input.disabled = true;
|
||||
designDate.input.disabled = true;
|
||||
}
|
||||
|
||||
openModal(
|
||||
@@ -130,6 +137,7 @@ export function openEditProjectModal(user: DashboardUser, project: ProjectItem):
|
||||
clientOrg.root,
|
||||
projectNumber.root,
|
||||
workAmount.root,
|
||||
designDate.root,
|
||||
],
|
||||
async () => {
|
||||
await updateProject(project.id, {
|
||||
@@ -143,6 +151,7 @@ export function openEditProjectModal(user: DashboardUser, project: ProjectItem):
|
||||
client_org: clientOrg.input.value.trim() || null,
|
||||
project_number: projectNumber.input.value.trim() || null,
|
||||
work_amount: workAmount.input.value.trim() || null,
|
||||
design_date: designDate.input.value || null,
|
||||
});
|
||||
showToast(L("B01_Dashboard_Saved"), "success");
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user