Compare commits

..

21 Commits

Author SHA1 Message Date
4dd68e2c98 Show linked codes as alias and code 2026-06-17 09:36:33 +09:00
7622ed2793 Repair dashboard database and disable WAL mode 2026-06-17 08:50:30 +09:00
a8f14e8c76 Use first address for map lookup 2026-06-16 20:06:14 +09:00
4bb2692ad0 Add project README 2026-06-16 19:57:26 +09:00
7d184d2e97 Update matching database 2026-06-16 19:53:58 +09:00
a510f34f71 Update linked code labels and alias cache 2026-06-16 19:51:23 +09:00
6790991471 Backfill site worksheet records from paymonth data 2026-06-15 10:56:32 +09:00
aca94d175c Disable startup DB maintenance in Docker 2026-06-15 10:34:04 +09:00
fd49c71910 Update shared dashboard database 2026-06-11 16:37:03 +09:00
7477a803e9 Run 8091 and 8092 dashboards with Docker 2026-06-11 16:35:09 +09:00
0c052abfa7 Update project dashboard routing and map directions 2026-06-10 16:22:04 +09:00
62b25b045b Show all 8092 crossbeam rows 2026-06-09 13:56:35 +09:00
0f32f8e7e7 Split 8092 bridge spec tables for alignment 2026-06-09 11:51:43 +09:00
754764edfa Normalize 8092 girder spec rowspan rows 2026-06-09 11:51:25 +09:00
20dcb839dd Auto-load missing 8092 overview and plan data 2026-06-09 11:20:57 +09:00
bc5d68e465 Improve 8092 default contract detail loading 2026-06-09 10:23:49 +09:00
54def57e99 Improve 8092 cache loading and SQLite stability 2026-06-09 10:12:15 +09:00
6ac0964618 Update 8092 bridge matching and construction plan view 2026-06-08 15:13:32 +09:00
0bae5fa7c3 Remove ERD and key usage artifacts 2026-06-08 09:51:09 +09:00
551a2447a4 Describe 8092 project code page 2026-06-05 15:59:53 +09:00
d848de48ae Describe 8091 dashboard page 2026-06-05 15:59:53 +09:00
24 changed files with 1615 additions and 870 deletions

View File

@@ -7,5 +7,5 @@ matching.db
csv csv
*.png *.png
*.xlsx *.xlsx
*.txt gitea-api.txt
data data

6
.gitignore vendored
View File

@@ -17,3 +17,9 @@ Thumbs.db
# Local scratch # Local scratch
*.tmp *.tmp
# SQLite runtime files / local recovery backups
*.db-wal
*.db-shm
*.db.bak-*
db-backups/

View File

@@ -2,18 +2,33 @@ FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \ ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \ PYTHONUNBUFFERED=1 \
PORT=8090 PORT=8091 \
CHROME_PATH=/usr/bin/chromium
WORKDIR /app WORKDIR /app
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
chromium \
fonts-noto-cjk \
nodejs \
npm \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./ COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
COPY app.py index.html detail-view.html detail-view-project.html ./ RUN npm install --omit=dev playwright-core
# matching.db는 볼륨으로 마운트해서 데이터 보존 COPY mysql_preview_server.py \
VOLUME ["/app/data"] index.html \
detail-view.html \
detail-view-project.html \
mysql-preview.html \
people-unified.html \
project-codes.html \
./
EXPOSE 8090 EXPOSE 8091 8092
CMD ["sh", "-c", "ln -sf /app/data/matching.db /app/matching.db 2>/dev/null || true; python3 app.py"] CMD ["python3", "mysql_preview_server.py"]

241
README.md Normal file
View File

@@ -0,0 +1,241 @@
# 장헌산업 업무 데이터 조회 시스템
이 저장소는 장헌산업 내부 업무 데이터를 조회하고, ERP 정보와 매칭해서 웹 화면으로 보여주는 사내용 도구입니다.
주요 목적은 아래 2가지입니다.
- `8091` 페이지: 사람별/프로젝트별 근무 데이터 조회
- `8092` 페이지: 시공 코드, 계약정보, 공사개요, 연계코드 조회
## 구성 개요
이 프로젝트는 Python 기반의 간단한 웹 서버와 SQLite DB(`matching.db`)를 사용합니다.
- 웹 서버: `mysql_preview_server.py`
- 공용 DB: `matching.db`
- 메인 대시보드 화면: `index.html`
- 사람별 근무 화면: `people-unified.html`
- 시공 코드 조회 화면: `project-codes.html`
같은 저장소 안에서 여러 HTML 화면을 제공하지만, 데이터는 공통으로 `matching.db`를 사용합니다.
## 페이지 설명
### `8091` 메인/근무 데이터 페이지
`8091` 포트는 근무 데이터와 집계 화면용입니다.
포함 내용:
- 프로젝트별 투입시간 집계
- 사람별 근무내역 조회
- 월별/기간별 프로젝트 투입 현황
- 사업관리 작업일보 기반 추가 공수 데이터 조회
관련 화면:
- `index.html`: 메인 대시보드
- `people-unified.html`: 사람별 / 프로젝트별 근무내역
- `detail-view.html`, `detail-view-project.html`: 상세 보기
### `8092` 시공 코드 조회 페이지
`8092` 포트는 ERP 시공 코드 전용 조회 화면입니다.
포함 내용:
- 시공코드 목록
- 계약정보
- 공사개요
- 교량 매칭 정보
- 공사시행계획서 기반 교량제원
- 연계코드 표시
연계코드는 아래 형식으로 표시됩니다.
- `영업/설계 약칭(코드번호)`가 아니라
- 현재는 `약칭(코드번호) · 약칭(코드번호)` 형식
예시:
- `새만금~전주간 고속도로 건설고사(제4공구) [8차](25-교영-09)`
- `새만금~전주간 고속도로 건설고사(제4공구) [8차](25-설계-05)`
관련 화면:
- `project-codes.html`
## 데이터 소스
이 시스템은 여러 데이터 소스를 함께 사용합니다.
### 1. SQLite 캐시 DB
- 파일: `matching.db`
- 저장소에 포함되어 있음
- 클론한 사람도 같은 시점의 데이터를 바로 볼 수 있음
주요 저장 내용:
- 직원 정보
- `dailyproject` 근무 데이터
- 프로젝트 약칭
- ERP 시공 코드 캐시
- ERP 계약정보 캐시
- ERP 교량 개요 캐시
- ERP 공사시행계획서 캐시
- 영업/설계/시공 연계코드 캐시
### 2. MySQL 원본 데이터
사내 MySQL에서 근무 데이터를 읽어와 SQLite로 적재합니다.
관련 환경값:
- `MYSQL_HOST`
- `MYSQL_PORT`
- `MYSQL_USER`
- `MYSQL_PASSWORD`
- `MYSQL_DB`
### 3. ERP 데이터
ERP에서 아래 정보를 가져옵니다.
- 프로젝트 약칭
- 시공 코드 목록
- 계약정보
- 공사관리 / 공사개요
- 공사시행계획서
- 영업/설계/시공 연계코드
관련 기본 URL:
- `http://erp.jangheon.co.kr/projt_mng`
## DB 관련 중요 사항
이 저장소는 **코드만이 아니라 `matching.db`도 함께 관리**합니다.
이유:
- 클론한 사람이 바로 같은 데이터를 볼 수 있어야 함
- 내부 페이지가 DB 캐시를 전제로 동작함
- ERP/MySQL 접속 없이도 기본 조회가 가능해야 함
즉, 이 저장소에서는 `matching.db`도 실제 배포/공유 자산입니다.
다만 아래 파일은 운영 중 자동 생성될 수 있습니다.
- `matching.db-wal`
- `matching.db-shm`
- `matching.db.bak-*`
이 파일들은 보조 파일/백업 파일이며, 기본 공유 대상은 `matching.db`입니다.
## 연계코드 저장 방식
시공코드 페이지의 연계코드는 DB에도 저장됩니다.
관련 테이블:
- `project_alias`
- `erp_project_alias_cache`
- `erp_linked_code_cache`
예를 들어 시공코드 하나에 대해 아래 정보를 저장합니다.
- 시공코드
- 사업코드
- 연관 영업코드
- 연관 영업 약칭
- 연관 설계코드
- 연관 설계 약칭
그래서 나중에 아래와 같은 질문에 바로 답할 수 있습니다.
- “이 시공코드의 연관 영업코드는 뭐야?”
- “이 설계코드 약칭이 뭐야?”
## 실행 방법
### 로컬 실행
Python 서버 실행:
```bash
python3 mysql_preview_server.py
```
기본 포트:
- `8091`: 메인/근무 데이터
- `8092`: 시공 코드 조회
### Docker 실행
이미지/컨테이너는 `docker-compose.yml``Dockerfile`로 실행할 수 있습니다.
관련 문서:
- `DEPLOY_DOCKER.md`
## 주요 파일 설명
- `mysql_preview_server.py`: 현재 실제 기능 대부분이 들어있는 메인 서버
- `app.py`: 이전/보조 서버 코드
- `index.html`: 8091 메인 대시보드
- `people-unified.html`: 사람별/프로젝트별 근무 조회
- `project-codes.html`: 8092 시공 코드 전용 화면
- `matching.db`: 공용 SQLite 데이터베이스
- `docker-compose.yml`: Docker 배포 설정
- `DEPLOY_DOCKER.md`: Docker 배포 방법
## 사용 흐름
### 근무 데이터 흐름
1. MySQL 원본 데이터를 읽음
2. SQLite `matching.db`에 적재
3. `8091` 페이지에서 집계/상세 조회
### 시공 코드 데이터 흐름
1. ERP에서 시공코드 목록 조회
2. ERP 계약정보 / 공사개요 / 공사시행계획서 조회
3. 영업/설계/시공 연계코드와 약칭 매칭
4. SQLite `matching.db`에 캐시 저장
5. `8092` 페이지에서 빠르게 조회
## 운영 시 주의사항
- `matching.db`는 실제 운영 데이터가 들어 있으므로 함부로 초기화하면 안 됩니다.
- ERP 재조회 버튼을 누르면 캐시가 갱신될 수 있습니다.
- 운영 중에는 DB 파일이 변경될 수 있어 `matching.db-wal`, `matching.db-shm`가 생길 수 있습니다.
- 다른 사람이 같은 결과를 보려면 저장소의 `matching.db`도 함께 최신 상태여야 합니다.
## 권장 공유 방식
다른 사람이 이 저장소를 받아서 바로 확인하려면:
1. 저장소를 클론
2. `matching.db`가 포함되어 있는지 확인
3. 서버 실행
4. `8091`, `8092` 페이지 접속
이렇게 하면 ERP를 다시 긁지 않아도 커밋 시점 기준의 데이터를 바로 볼 수 있습니다.

View File

@@ -21,12 +21,10 @@
.legend{display:grid;grid-template-columns:1fr 1fr;gap:8px} .legend{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.legend-item{display:flex;gap:8px;align-items:center;font-size:12px;background:#fff;border:1px solid #e1d7cb;border-radius:10px;padding:7px 9px} .legend-item{display:flex;gap:8px;align-items:center;font-size:12px;background:#fff;border:1px solid #e1d7cb;border-radius:10px;padding:7px 9px}
.dot{width:11px;height:11px;border-radius:999px} .dot{width:11px;height:11px;border-radius:999px}
.shared-note{margin:0 0 12px;padding:10px 12px;border:1px solid #d7e5ee;border-radius:12px;background:#eef8fb;color:#355468;font-size:12px;line-height:1.55}
</style> </style>
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="shared-note">이 화면은 선택한 프로젝트의 년도별 인원 투입 비중과 월별 투입 상세를 보여줍니다.</div>
<div class="card"><div class="row" style="justify-content:space-between"><h3 id="title" style="margin:0">선택 프로젝트 상세 (년도별)</h3><label>년도 <select id="yearSel"></select></label></div></div> <div class="card"><div class="row" style="justify-content:space-between"><h3 id="title" style="margin:0">선택 프로젝트 상세 (년도별)</h3><label>년도 <select id="yearSel"></select></label></div></div>
<div class="card"><div id="donutWrap" class="donut-wrap"></div></div> <div class="card"><div id="donutWrap" class="donut-wrap"></div></div>
<div class="card"><h3 style="margin:0 0 8px">인원 투입 상세 (년/월)</h3><div class="table-wrap"><table id="tblA"></table></div></div> <div class="card"><h3 style="margin:0 0 8px">인원 투입 상세 (년/월)</h3><div class="table-wrap"><table id="tblA"></table></div></div>

View File

@@ -23,12 +23,10 @@
.dot{width:11px;height:11px;border-radius:999px} .dot{width:11px;height:11px;border-radius:999px}
.hours-summary{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px} .hours-summary{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.hours-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid #e1d7cb;border-radius:999px;font-size:12px;background:#fff} .hours-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 10px;border:1px solid #e1d7cb;border-radius:999px;font-size:12px;background:#fff}
.shared-note{margin:0 0 12px;padding:10px 12px;border:1px solid #d7e5ee;border-radius:12px;background:#eef8fb;color:#355468;font-size:12px;line-height:1.55}
</style> </style>
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="shared-note">이 화면은 선택한 인원의 년도별 프로젝트 투입 비중과 월별 투입 상세를 보여줍니다.</div>
<div class="card"><div class="row" style="justify-content:space-between"><h3 id="detailTitle" style="margin:0">선택 인원 상세 (년도별)</h3><label>년도 <select id="yearSel"></select></label></div></div> <div class="card"><div class="row" style="justify-content:space-between"><h3 id="detailTitle" style="margin:0">선택 인원 상세 (년도별)</h3><label>년도 <select id="yearSel"></select></label></div></div>
<div class="card"><div id="donutWrap" class="donut-wrap"></div></div> <div class="card"><div id="donutWrap" class="donut-wrap"></div></div>
<div class="card"><h3 style="margin:0 0 8px">프로젝트 투입 상세 (년/월/유형)</h3><div class="table-wrap"><table id="tblA"></table></div></div> <div class="card"><h3 style="margin:0 0 8px">프로젝트 투입 상세 (년/월/유형)</h3><div class="table-wrap"><table id="tblA"></table></div></div>

View File

@@ -1,13 +1,12 @@
version: "3.9"
services: services:
manhour-dashboard: jh-people-8091:
build: . build: .
container_name: manhour-dashboard container_name: jh-people-8091
ports: ports:
- "8090:8090" - "8091:8091"
environment: environment:
PORT: "8090" PORT: "8091"
STARTUP_MAINTENANCE: "0"
MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}" MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}"
MYSQL_PORT: "${MYSQL_PORT:-3306}" MYSQL_PORT: "${MYSQL_PORT:-3306}"
MYSQL_USER: "${MYSQL_USER:-root}" MYSQL_USER: "${MYSQL_USER:-root}"
@@ -20,5 +19,30 @@ services:
INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}" INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}"
INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}" INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}"
volumes: volumes:
- ./data:/app/data - ./matching.db:/app/matching.db
restart: unless-stopped
jh-project-8092:
build: .
container_name: jh-project-8092
ports:
- "8092:8092"
environment:
PORT: "8092"
STARTUP_MAINTENANCE: "0"
MYSQL_HOST: "${MYSQL_HOST:-172.16.42.111}"
MYSQL_PORT: "${MYSQL_PORT:-3306}"
MYSQL_USER: "${MYSQL_USER:-root}"
MYSQL_PASSWORD: "${MYSQL_PASSWORD:-hanmacerp!}"
MYSQL_DB: "${MYSQL_DB:-jangheon_manhour}"
ERP_BASE_URL: "${ERP_BASE_URL:-http://erp.jangheon.co.kr/projt_mng}"
ERP_LOGIN_ID: "${ERP_LOGIN_ID:-g25001}"
ERP_LOGIN_PW: "${ERP_LOGIN_PW:-00000}"
INTRANET_BASE_URL: "${INTRANET_BASE_URL:-http://erp.jangheon.co.kr/intranet/}"
INTRANET_LOGIN_ID: "${INTRANET_LOGIN_ID:-G25001}"
INTRANET_LOGIN_PW: "${INTRANET_LOGIN_PW:-00000}"
volumes:
- ./matching.db:/app/matching.db
depends_on:
- jh-people-8091
restart: unless-stopped restart: unless-stopped

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 KiB

View File

@@ -1,146 +0,0 @@
{
"left_core_tables": [
"dallyproject_tbl",
"member_tbl"
],
"right_tables": [
"dallyproject_2005_2015_tbl",
"dallyproject_2016_tbl",
"dallyproject_2017_tbl",
"dallyproject_2018_tbl",
"dallyproject_2019_tbl",
"dallyproject_2020_tbl",
"project_tbl",
"systemconfig_tbl",
"userstate_tbl",
"worker_tardy_tbl"
],
"relations": [
{
"from": "dallyproject_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "worker_tardy_tbl",
"from_col": "MemberNo",
"to": "member_tbl",
"to_col": "MemberNo",
"card": "N:1"
},
{
"from": "dallyproject_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "EntryPCode",
"to": "project_tbl",
"to_col": "ProjectCode",
"card": "N:1"
},
{
"from": "member_tbl",
"from_col": "RankCode",
"to": "systemconfig_tbl",
"to_col": "Code(PositionCode)",
"card": "N:1"
},
{
"from": "member_tbl",
"from_col": "GroupCode",
"to": "systemconfig_tbl",
"to_col": "Code(GroupCode*)",
"card": "N:1"
},
{
"from": "member_tbl",
"from_col": "WorkPosition",
"to": "systemconfig_tbl",
"to_col": "Code(WorkPositionCode)",
"card": "N:1"
}
]
}

View File

@@ -1,145 +0,0 @@
{
"database": "jangheon_manhour",
"tables": [
"dallyproject_2005_2015_tbl",
"dallyproject_2016_tbl",
"dallyproject_2017_tbl",
"dallyproject_2018_tbl",
"dallyproject_2019_tbl",
"dallyproject_2020_tbl",
"dallyproject_tbl",
"member_tbl",
"project_tbl",
"systemconfig_tbl",
"userstate_tbl",
"worker_tardy_tbl"
],
"relations": [
{
"from_table": "dallyproject_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2005_2015_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2016_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2017_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2018_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2019_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2020_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "worker_tardy_tbl",
"from_col": "MemberNo",
"to_table": "member_tbl",
"to_col": "MemberNo",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2005_2015_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2016_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2017_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2018_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2019_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "dallyproject_2020_tbl",
"from_col": "EntryPCode",
"to_table": "project_tbl",
"to_col": "ProjectCode",
"cardinality": "N:1"
},
{
"from_table": "member_tbl",
"from_col": "RankCode",
"to_table": "systemconfig_tbl",
"to_col": "Code (SysKey=PositionCode)",
"cardinality": "N:1"
},
{
"from_table": "member_tbl",
"from_col": "GroupCode",
"to_table": "systemconfig_tbl",
"to_col": "Code (SysKey=GroupCode*)",
"cardinality": "N:1"
},
{
"from_table": "member_tbl",
"from_col": "WorkPosition",
"to_table": "systemconfig_tbl",
"to_col": "Code (SysKey=WorkPositionCode)",
"cardinality": "N:1"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

View File

@@ -1,340 +0,0 @@
{
"tables": [
"dallyproject_2005_2015_tbl",
"dallyproject_2016_tbl",
"dallyproject_2017_tbl",
"dallyproject_2018_tbl",
"dallyproject_2019_tbl",
"dallyproject_2020_tbl",
"dallyproject_tbl",
"member_tbl",
"project_tbl",
"systemconfig_tbl",
"userstate_tbl",
"worker_tardy_tbl"
],
"relationships": [
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2016_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2017_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2018_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2019_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2020_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2005_2015_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2017_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2018_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2019_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2020_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2016_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2018_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2019_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2020_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2017_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2019_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2020_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2018_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_2020_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2019_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "entryjobcode,entrypcode",
"to": "dallyproject_tbl",
"to_col": "entryjobcode,entrypcode",
"type": "INFERRED"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_2020_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_tbl",
"from_col": "memberno",
"to": "member_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_tbl",
"from_col": "memberno",
"to": "userstate_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "dallyproject_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "member_tbl",
"from_col": "groupcode,memberno",
"to": "userstate_tbl",
"to_col": "groupcode,memberno",
"type": "INFERRED"
},
{
"from": "member_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
},
{
"from": "project_tbl",
"from_col": "projectcode",
"to": "userstate_tbl",
"to_col": "projectcode",
"type": "INFERRED"
},
{
"from": "userstate_tbl",
"from_col": "memberno",
"to": "worker_tardy_tbl",
"to_col": "memberno",
"type": "INFERRED"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 182 KiB

View File

@@ -1,62 +0,0 @@
table,column,keyflag,rows,distinct,empty,fill_rate,uniqueness,usage_score
userstate_tbl,num,PRI,14133,14133,0,1.0,1.0,1.0
project_tbl,ProjectCode,PRI,2149,2149,0,1.0,1.0,1.0
worker_tardy_tbl,row_num,PRI,233,233,0,1.0,1.0,1.0
member_tbl,MemberNo,PRI,320,319,0,1.0,0.9969,0.9984
member_tbl,korName,PRI,320,301,2,0.9938,0.9406,0.9672
dallyproject_tbl,EntryTime,PRI,73489,60540,0,1.0,0.8238,0.9119
dallyproject_2020_tbl,EntryTime,PRI,8732,7172,0,1.0,0.8213,0.9107
dallyproject_2019_tbl,EntryTime,PRI,8779,6747,0,1.0,0.7685,0.8843
dallyproject_2016_tbl,EntryTime,PRI,9359,7167,0,1.0,0.7658,0.8829
dallyproject_2018_tbl,EntryTime,PRI,9485,7219,0,1.0,0.7611,0.8805
dallyproject_2017_tbl,EntryTime,PRI,9177,6859,0,1.0,0.7474,0.8737
dallyproject_2005_2015_tbl,EntryTime,PRI,80964,57059,0,1.0,0.7047,0.8524
systemconfig_tbl,Code,-,676,352,0,1.0,0.5207,0.7604
worker_tardy_tbl,memberno,-,233,103,0,1.0,0.4421,0.721
project_tbl,mpCode,-,2149,884,355,0.8348,0.4114,0.6231
project_tbl,oldProjectCode,-,2149,906,669,0.6887,0.4216,0.5551
member_tbl,RankCode,-,320,22,0,1.0,0.0688,0.5344
userstate_tbl,ProjectCode,-,14133,604,15,0.9989,0.0427,0.5208
member_tbl,GroupCode,-,320,12,0,1.0,0.0375,0.5188
dallyproject_2016_tbl,EntryPCode,-,9359,214,17,0.9982,0.0229,0.5105
dallyproject_2017_tbl,EntryPCode,-,9177,195,8,0.9991,0.0212,0.5102
dallyproject_2020_tbl,EntryPCode,-,8732,176,3,0.9997,0.0202,0.5099
dallyproject_2019_tbl,EntryPCode,-,8779,153,2,0.9998,0.0174,0.5086
dallyproject_2018_tbl,EntryPCode,-,9485,166,10,0.9989,0.0175,0.5082
member_tbl,WorkPosition,-,320,4,0,1.0,0.0125,0.5062
dallyproject_tbl,EntryPCode,-,73489,854,35,0.9995,0.0116,0.5056
userstate_tbl,MemberNo,-,14133,109,0,1.0,0.0077,0.5039
dallyproject_2018_tbl,MemberNo,PRI,9485,58,1,0.9999,0.0061,0.503
dallyproject_2016_tbl,MemberNo,PRI,9359,55,1,0.9999,0.0059,0.5029
dallyproject_2019_tbl,MemberNo,PRI,8779,52,1,0.9999,0.0059,0.5029
dallyproject_2017_tbl,MemberNo,PRI,9177,53,1,0.9999,0.0058,0.5028
dallyproject_2005_2015_tbl,EntryPCode,-,80964,603,160,0.998,0.0074,0.5027
dallyproject_2020_tbl,MemberNo,PRI,8732,47,0,1.0,0.0054,0.5027
dallyproject_2019_tbl,EntryJobCode,-,8779,30,2,0.9998,0.0034,0.5016
dallyproject_2020_tbl,EntryJobCode,-,8732,32,4,0.9995,0.0037,0.5016
dallyproject_2016_tbl,EntryJobCode,-,9359,40,14,0.9985,0.0043,0.5014
dallyproject_2017_tbl,EntryJobCode,-,9177,33,9,0.999,0.0036,0.5013
dallyproject_2018_tbl,EntryJobCode,-,9485,33,11,0.9988,0.0035,0.5012
dallyproject_2005_2015_tbl,MemberNo,PRI,80964,149,36,0.9996,0.0018,0.5007
dallyproject_tbl,MemberNo,PRI,73489,96,6,0.9999,0.0013,0.5006
userstate_tbl,GroupCode,-,14133,10,0,1.0,0.0007,0.5004
dallyproject_tbl,EntryJobCode,-,73489,49,57,0.9992,0.0007,0.4999
dallyproject_2005_2015_tbl,EntryJobCode,-,80964,124,743,0.9908,0.0015,0.4962
dallyproject_2020_tbl,LeavePCode,-,8732,168,1486,0.8298,0.0192,0.4245
dallyproject_2016_tbl,LeavePCode,-,9359,206,1643,0.8244,0.022,0.4232
dallyproject_2020_tbl,LeaveJobCode,-,8732,32,1488,0.8296,0.0037,0.4166
dallyproject_2019_tbl,LeavePCode,-,8779,149,1621,0.8154,0.017,0.4162
dallyproject_2017_tbl,LeavePCode,-,9177,189,1748,0.8095,0.0206,0.4151
dallyproject_tbl,LeavePCode,-,73489,861,13412,0.8175,0.0117,0.4146
dallyproject_2016_tbl,LeaveJobCode,-,9359,36,1640,0.8248,0.0038,0.4143
dallyproject_2019_tbl,LeaveJobCode,-,8779,29,1622,0.8152,0.0033,0.4093
dallyproject_tbl,LeaveJobCode,-,73489,44,13500,0.8163,0.0006,0.4084
dallyproject_2005_2015_tbl,LeavePCode,-,80964,594,15683,0.8063,0.0073,0.4068
dallyproject_2017_tbl,LeaveJobCode,-,9177,31,1749,0.8094,0.0034,0.4064
dallyproject_2018_tbl,LeavePCode,-,9485,162,2057,0.7831,0.0171,0.4001
dallyproject_2018_tbl,LeaveJobCode,-,9485,33,2062,0.7826,0.0035,0.393
dallyproject_2005_2015_tbl,LeaveJobCode,-,80964,112,22652,0.7202,0.0014,0.3608
project_tbl,OrderCompanyCode,-,2149,12,1256,0.4155,0.0056,0.2106
systemconfig_tbl,orderno,-,676,50,555,0.179,0.074,0.1265
userstate_tbl,sub_code,-,14133,449,12614,0.1075,0.0318,0.0696
userstate_tbl,active_code,-,14133,34,13939,0.0137,0.0024,0.0081
1 table column keyflag rows distinct empty fill_rate uniqueness usage_score
2 userstate_tbl num PRI 14133 14133 0 1.0 1.0 1.0
3 project_tbl ProjectCode PRI 2149 2149 0 1.0 1.0 1.0
4 worker_tardy_tbl row_num PRI 233 233 0 1.0 1.0 1.0
5 member_tbl MemberNo PRI 320 319 0 1.0 0.9969 0.9984
6 member_tbl korName PRI 320 301 2 0.9938 0.9406 0.9672
7 dallyproject_tbl EntryTime PRI 73489 60540 0 1.0 0.8238 0.9119
8 dallyproject_2020_tbl EntryTime PRI 8732 7172 0 1.0 0.8213 0.9107
9 dallyproject_2019_tbl EntryTime PRI 8779 6747 0 1.0 0.7685 0.8843
10 dallyproject_2016_tbl EntryTime PRI 9359 7167 0 1.0 0.7658 0.8829
11 dallyproject_2018_tbl EntryTime PRI 9485 7219 0 1.0 0.7611 0.8805
12 dallyproject_2017_tbl EntryTime PRI 9177 6859 0 1.0 0.7474 0.8737
13 dallyproject_2005_2015_tbl EntryTime PRI 80964 57059 0 1.0 0.7047 0.8524
14 systemconfig_tbl Code - 676 352 0 1.0 0.5207 0.7604
15 worker_tardy_tbl memberno - 233 103 0 1.0 0.4421 0.721
16 project_tbl mpCode - 2149 884 355 0.8348 0.4114 0.6231
17 project_tbl oldProjectCode - 2149 906 669 0.6887 0.4216 0.5551
18 member_tbl RankCode - 320 22 0 1.0 0.0688 0.5344
19 userstate_tbl ProjectCode - 14133 604 15 0.9989 0.0427 0.5208
20 member_tbl GroupCode - 320 12 0 1.0 0.0375 0.5188
21 dallyproject_2016_tbl EntryPCode - 9359 214 17 0.9982 0.0229 0.5105
22 dallyproject_2017_tbl EntryPCode - 9177 195 8 0.9991 0.0212 0.5102
23 dallyproject_2020_tbl EntryPCode - 8732 176 3 0.9997 0.0202 0.5099
24 dallyproject_2019_tbl EntryPCode - 8779 153 2 0.9998 0.0174 0.5086
25 dallyproject_2018_tbl EntryPCode - 9485 166 10 0.9989 0.0175 0.5082
26 member_tbl WorkPosition - 320 4 0 1.0 0.0125 0.5062
27 dallyproject_tbl EntryPCode - 73489 854 35 0.9995 0.0116 0.5056
28 userstate_tbl MemberNo - 14133 109 0 1.0 0.0077 0.5039
29 dallyproject_2018_tbl MemberNo PRI 9485 58 1 0.9999 0.0061 0.503
30 dallyproject_2016_tbl MemberNo PRI 9359 55 1 0.9999 0.0059 0.5029
31 dallyproject_2019_tbl MemberNo PRI 8779 52 1 0.9999 0.0059 0.5029
32 dallyproject_2017_tbl MemberNo PRI 9177 53 1 0.9999 0.0058 0.5028
33 dallyproject_2005_2015_tbl EntryPCode - 80964 603 160 0.998 0.0074 0.5027
34 dallyproject_2020_tbl MemberNo PRI 8732 47 0 1.0 0.0054 0.5027
35 dallyproject_2019_tbl EntryJobCode - 8779 30 2 0.9998 0.0034 0.5016
36 dallyproject_2020_tbl EntryJobCode - 8732 32 4 0.9995 0.0037 0.5016
37 dallyproject_2016_tbl EntryJobCode - 9359 40 14 0.9985 0.0043 0.5014
38 dallyproject_2017_tbl EntryJobCode - 9177 33 9 0.999 0.0036 0.5013
39 dallyproject_2018_tbl EntryJobCode - 9485 33 11 0.9988 0.0035 0.5012
40 dallyproject_2005_2015_tbl MemberNo PRI 80964 149 36 0.9996 0.0018 0.5007
41 dallyproject_tbl MemberNo PRI 73489 96 6 0.9999 0.0013 0.5006
42 userstate_tbl GroupCode - 14133 10 0 1.0 0.0007 0.5004
43 dallyproject_tbl EntryJobCode - 73489 49 57 0.9992 0.0007 0.4999
44 dallyproject_2005_2015_tbl EntryJobCode - 80964 124 743 0.9908 0.0015 0.4962
45 dallyproject_2020_tbl LeavePCode - 8732 168 1486 0.8298 0.0192 0.4245
46 dallyproject_2016_tbl LeavePCode - 9359 206 1643 0.8244 0.022 0.4232
47 dallyproject_2020_tbl LeaveJobCode - 8732 32 1488 0.8296 0.0037 0.4166
48 dallyproject_2019_tbl LeavePCode - 8779 149 1621 0.8154 0.017 0.4162
49 dallyproject_2017_tbl LeavePCode - 9177 189 1748 0.8095 0.0206 0.4151
50 dallyproject_tbl LeavePCode - 73489 861 13412 0.8175 0.0117 0.4146
51 dallyproject_2016_tbl LeaveJobCode - 9359 36 1640 0.8248 0.0038 0.4143
52 dallyproject_2019_tbl LeaveJobCode - 8779 29 1622 0.8152 0.0033 0.4093
53 dallyproject_tbl LeaveJobCode - 73489 44 13500 0.8163 0.0006 0.4084
54 dallyproject_2005_2015_tbl LeavePCode - 80964 594 15683 0.8063 0.0073 0.4068
55 dallyproject_2017_tbl LeaveJobCode - 9177 31 1749 0.8094 0.0034 0.4064
56 dallyproject_2018_tbl LeavePCode - 9485 162 2057 0.7831 0.0171 0.4001
57 dallyproject_2018_tbl LeaveJobCode - 9485 33 2062 0.7826 0.0035 0.393
58 dallyproject_2005_2015_tbl LeaveJobCode - 80964 112 22652 0.7202 0.0014 0.3608
59 project_tbl OrderCompanyCode - 2149 12 1256 0.4155 0.0056 0.2106
60 systemconfig_tbl orderno - 676 50 555 0.179 0.074 0.1265
61 userstate_tbl sub_code - 14133 449 12614 0.1075 0.0318 0.0696
62 userstate_tbl active_code - 14133 34 13939 0.0137 0.0024 0.0081

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

View File

@@ -33,7 +33,6 @@
box-shadow: 0 8px 20px rgba(24, 33, 47, 0.06); box-shadow: 0 8px 20px rgba(24, 33, 47, 0.06);
margin-bottom: 16px; margin-bottom: 16px;
} }
.shared-note { margin-bottom: 16px; padding: 12px 14px; border: 1px solid #d7e5ee; border-radius: 12px; background: #eef8fb; color: #355468; font-size: 13px; line-height: 1.6; }
h1 { margin: 0 0 10px; font-size: 24px; } h1 { margin: 0 0 10px; font-size: 24px; }
p { margin: 8px 0; color: var(--muted); } p { margin: 8px 0; color: var(--muted); }
.row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; } .row { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
@@ -62,7 +61,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="shared-note">이 화면은 `MemberNo`와 `korName` 매칭 상태를 확인하고 비교하는 페이지입니다.</div>
<div class="card"> <div class="card">
<h1>MemberNo → korName 매칭 페이지</h1> <h1>MemberNo → korName 매칭 페이지</h1>
<p>`dallyproject.csv`의 `MemberNo`를 `member.csv`의 `MemberNo`와 매치해서 `korName`을 붙입니다.</p> <p>`dallyproject.csv`의 `MemberNo`를 `member.csv`의 `MemberNo`와 매치해서 `korName`을 붙입니다.</p>

View File

@@ -24,12 +24,10 @@
table { border-collapse: collapse; width: 100%; min-width: 900px; background: #fff; } table { border-collapse: collapse; width: 100%; min-width: 900px; background: #fff; }
th, td { border-bottom: 1px solid #ebf0f8; padding: 7px 9px; font-size: 13px; text-align: left; white-space: nowrap; } th, td { border-bottom: 1px solid #ebf0f8; padding: 7px 9px; font-size: 13px; text-align: left; white-space: nowrap; }
th { position: sticky; top: 0; background: #f8fbff; z-index: 1; } th { position: sticky; top: 0; background: #f8fbff; z-index: 1; }
.shared-note { margin-bottom: 14px; padding: 12px 14px; border: 1px solid #d7e5ee; border-radius: 12px; background: #eef8fb; color: #355468; font-size: 13px; line-height: 1.6; }
</style> </style>
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="shared-note">이 화면은 MySQL 테이블 목록과 선택한 테이블의 원본 데이터를 미리보는 페이지입니다.</div>
<div class="card"> <div class="card">
<h2 style="margin-top:0;">MySQL 데이터 미리보기</h2> <h2 style="margin-top:0;">MySQL 데이터 미리보기</h2>
<div class="row"> <div class="row">

File diff suppressed because it is too large Load Diff

View File

@@ -38,7 +38,6 @@
.summary-metrics { display:flex; flex-wrap:wrap; gap:8px 14px; margin-bottom:8px; font-size:12px; color:#334155; } .summary-metrics { display:flex; flex-wrap:wrap; gap:8px 14px; margin-bottom:8px; font-size:12px; color:#334155; }
.metric { padding:0; border:0; background:transparent; } .metric { padding:0; border:0; background:transparent; }
.metric-label { font-size:11px; color:#64748b; margin-right:4px; } .metric-label { font-size:11px; color:#64748b; margin-right:4px; }
.shared-note { margin-bottom: 12px; padding: 12px 14px; border: 1px solid #d7e5ee; border-radius: 12px; background: #eef8fb; color: #355468; font-size: 13px; line-height: 1.6; }
.metric-value { font-size:12px; font-weight:700; color:#0f172a; display:inline; } .metric-value { font-size:12px; font-weight:700; color:#0f172a; display:inline; }
.summary-sub { font-size:11px; color:#64748b; margin:6px 0 8px; } .summary-sub { font-size:11px; color:#64748b; margin:6px 0 8px; }
.summary-table-wrap { max-height:none; overflow:visible; border:1px solid #dbe4f0; border-radius:8px; background:#fff; } .summary-table-wrap { max-height:none; overflow:visible; border:1px solid #dbe4f0; border-radius:8px; background:#fff; }
@@ -106,7 +105,6 @@
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<div class="shared-note">이 화면은 사람별 근무내역, 현장 기록, 월별 요약을 한 번에 보는 통합 페이지입니다.</div>
<div class="card"> <div class="card">
<h2 style="margin:0 0 10px;">dailyproject 사람별 근무내역</h2> <h2 style="margin:0 0 10px;">dailyproject 사람별 근무내역</h2>
<div class="tabs"> <div class="tabs">

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@ class ProjectCodeViewerHandler(base.Handler):
if __name__ == '__main__': if __name__ == '__main__':
os.makedirs(base.BASE_DIR, exist_ok=True) os.makedirs(base.BASE_DIR, exist_ok=True)
try: try:
with sqlite3.connect(base.DB_PATH, timeout=30) as conn: with base.open_db_connection() as conn:
base.init_db(conn) base.init_db(conn)
except sqlite3.OperationalError as error: except sqlite3.OperationalError as error:
if 'locked' in str(error).lower(): if 'locked' in str(error).lower():