@charzing/vehicle-utils 0.2.3 → 0.2.5
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/README.md +313 -56
- package/dist/cjs/index.d.ts +13 -1
- package/dist/cjs/index.js +95 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/report/cellMap.d.ts +106 -0
- package/dist/cjs/report/cellMap.js +119 -0
- package/dist/cjs/report/cellMap.js.map +1 -0
- package/dist/esm/index.d.mts +13 -1
- package/dist/esm/index.mjs +89 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/report/cellMap.d.mts +106 -0
- package/dist/esm/report/cellMap.mjs +89 -0
- package/dist/esm/report/cellMap.mjs.map +1 -0
- package/package.json +15 -1
- package/dist/index.d.mts +0 -714
- package/dist/index.d.ts +0 -714
- package/dist/index.js +0 -357
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,130 +1,387 @@
|
|
|
1
1
|
# @charzing/vehicle-utils
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Charzing 차량 데이터 관리를 위한 공유 유틸리티 라이브러리
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 📋 프로젝트 개요
|
|
6
|
+
|
|
7
|
+
**@charzing/vehicle-utils**는 Charzing 생태계의 모든 플랫폼(웹, 모바일, 관리자)에서 일관되게 사용할 수 있는 차량 데이터 변환 및 매핑 유틸리티를 제공합니다.
|
|
8
|
+
|
|
9
|
+
### 주요 기능
|
|
10
|
+
- 🔄 브랜드/모델 ID 정규화 (한국어 ↔ 영어)
|
|
11
|
+
- 🖼️ Firebase Storage 차량 이미지 URL 생성
|
|
12
|
+
- 🏷️ 표준 파일명 생성 규칙
|
|
13
|
+
- 📦 TypeScript 완전 타입 지원
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 🛠️ 기술 스택
|
|
18
|
+
|
|
19
|
+
- **Language**: TypeScript 5
|
|
20
|
+
- **Build**: tsup (esbuild 기반)
|
|
21
|
+
- **Package Manager**: npm
|
|
22
|
+
- **Module**: ESM + CJS 모두 지원
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 📦 설치 방법
|
|
6
27
|
|
|
7
28
|
### 로컬 개발 (npm link)
|
|
8
29
|
|
|
9
30
|
```bash
|
|
31
|
+
# 1. vehicle-utils 빌드
|
|
10
32
|
cd /Users/sungmin/charzing-vehicle-utils
|
|
11
33
|
npm install
|
|
12
34
|
npm run build
|
|
13
35
|
npm link
|
|
14
36
|
|
|
15
|
-
# 각 프로젝트에서
|
|
37
|
+
# 2. 각 프로젝트에서 링크
|
|
16
38
|
cd /Users/sungmin/charzing-admin
|
|
17
39
|
npm link @charzing/vehicle-utils
|
|
18
40
|
|
|
19
41
|
cd /Users/sungmin/CharzingApp-Expo
|
|
20
42
|
npm link @charzing/vehicle-utils
|
|
21
43
|
|
|
22
|
-
cd /Users/sungmin/
|
|
44
|
+
cd /Users/sungmin/Desktop/project/react/charzing
|
|
23
45
|
npm link @charzing/vehicle-utils
|
|
24
46
|
```
|
|
25
47
|
|
|
26
|
-
|
|
48
|
+
### npm 패키지로 설치 (프로덕션)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @charzing/vehicle-utils
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🚀 주요 API
|
|
27
57
|
|
|
28
58
|
### 1. 브랜드 매핑
|
|
29
59
|
|
|
60
|
+
#### `normalizeBrandId(brand: string): string`
|
|
61
|
+
브랜드명을 표준 Firestore ID로 정규화합니다.
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { normalizeBrandId } from '@charzing/vehicle-utils';
|
|
65
|
+
|
|
66
|
+
// 한국어 → 영어 소문자
|
|
67
|
+
normalizeBrandId('현대'); // 'hyundai'
|
|
68
|
+
normalizeBrandId('기아'); // 'kia'
|
|
69
|
+
normalizeBrandId('테슬라'); // 'tesla'
|
|
70
|
+
|
|
71
|
+
// 대문자 유지 브랜드 (BMW, MINI, PORSCHE)
|
|
72
|
+
normalizeBrandId('BMW'); // 'bmw'
|
|
73
|
+
normalizeBrandId('MINI'); // 'mini'
|
|
74
|
+
normalizeBrandId('PORSCHE'); // 'porsche'
|
|
75
|
+
|
|
76
|
+
// 메르세데스-벤츠 처리
|
|
77
|
+
normalizeBrandId('메르세데스-벤츠'); // 'mercedes-benz'
|
|
78
|
+
normalizeBrandId('벤츠'); // 'mercedes-benz'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### `getBrandNameKorean(brandId: string): string`
|
|
82
|
+
Firestore ID로 한글 브랜드명을 가져옵니다.
|
|
83
|
+
|
|
30
84
|
```typescript
|
|
31
|
-
import {
|
|
85
|
+
import { getBrandNameKorean } from '@charzing/vehicle-utils';
|
|
86
|
+
|
|
87
|
+
getBrandNameKorean('hyundai'); // '현대'
|
|
88
|
+
getBrandNameKorean('mercedes-benz'); // '메르세데스-벤츠'
|
|
89
|
+
getBrandNameKorean('BMW'); // 'BMW'
|
|
90
|
+
```
|
|
32
91
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const brandId2 = normalizeBrandId('BMW'); // 'bmw'
|
|
92
|
+
#### `getBrandNameEnglish(brandId: string): string`
|
|
93
|
+
Firestore ID로 영문 브랜드명을 가져옵니다.
|
|
36
94
|
|
|
37
|
-
|
|
38
|
-
|
|
95
|
+
```typescript
|
|
96
|
+
import { getBrandNameEnglish } from '@charzing/vehicle-utils';
|
|
39
97
|
|
|
40
|
-
//
|
|
41
|
-
|
|
98
|
+
getBrandNameEnglish('hyundai'); // 'HYUNDAI'
|
|
99
|
+
getBrandNameEnglish('bmw'); // 'BMW'
|
|
100
|
+
getBrandNameEnglish('mini'); // 'MINI'
|
|
42
101
|
```
|
|
43
102
|
|
|
103
|
+
---
|
|
104
|
+
|
|
44
105
|
### 2. 모델 매핑
|
|
45
106
|
|
|
107
|
+
#### `normalizeModelId(model: string): string`
|
|
108
|
+
모델명을 표준 Firestore ID로 정규화합니다.
|
|
109
|
+
|
|
46
110
|
```typescript
|
|
47
|
-
import { normalizeModelId
|
|
111
|
+
import { normalizeModelId } from '@charzing/vehicle-utils';
|
|
48
112
|
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
113
|
+
// 한국어 → 영어 소문자
|
|
114
|
+
normalizeModelId('아이오닉 5'); // 'ioniq-5'
|
|
115
|
+
normalizeModelId('EV6'); // 'ev6'
|
|
116
|
+
normalizeModelId('Model S'); // 'model-s'
|
|
52
117
|
|
|
53
|
-
//
|
|
54
|
-
|
|
118
|
+
// 공백 → 하이픈 변환
|
|
119
|
+
normalizeModelId('쿠퍼'); // 'cooper'
|
|
120
|
+
normalizeModelId('Model 3'); // 'model-3'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `getModelNameKorean(modelId: string): string`
|
|
124
|
+
Firestore ID로 한글 모델명을 가져옵니다.
|
|
55
125
|
|
|
56
|
-
|
|
57
|
-
|
|
126
|
+
```typescript
|
|
127
|
+
import { getModelNameKorean } from '@charzing/vehicle-utils';
|
|
128
|
+
|
|
129
|
+
getModelNameKorean('ioniq-5'); // '아이오닉 5'
|
|
130
|
+
getModelNameKorean('ev6'); // 'EV6'
|
|
131
|
+
getModelNameKorean('cooper'); // '쿠퍼'
|
|
58
132
|
```
|
|
59
133
|
|
|
134
|
+
#### `getModelNameEnglish(modelId: string): string`
|
|
135
|
+
Firestore ID로 영문 모델명을 가져옵니다.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { getModelNameEnglish } from '@charzing/vehicle-utils';
|
|
139
|
+
|
|
140
|
+
getModelNameEnglish('ioniq-5'); // 'IONIQ-5'
|
|
141
|
+
getModelNameEnglish('model-s'); // 'MODEL-S'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
60
146
|
### 3. 이미지 URL 생성
|
|
61
147
|
|
|
148
|
+
#### `generateVehicleImageUrl(params: ImageParams): string`
|
|
149
|
+
Firebase Storage 차량 이미지 URL을 생성합니다.
|
|
150
|
+
|
|
62
151
|
```typescript
|
|
63
|
-
import { generateVehicleImageUrl
|
|
152
|
+
import { generateVehicleImageUrl } from '@charzing/vehicle-utils';
|
|
64
153
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
154
|
+
// 기본 이미지 (트림 없음)
|
|
155
|
+
const url1 = generateVehicleImageUrl({
|
|
67
156
|
brand: 'hyundai',
|
|
68
157
|
model: 'ioniq-5',
|
|
69
|
-
year: 2024
|
|
70
|
-
trim: 'exclusive'
|
|
158
|
+
year: 2024
|
|
71
159
|
});
|
|
72
160
|
// → https://firebasestorage.googleapis.com/v0/b/charzing-d1600.firebasestorage.app/o/
|
|
73
|
-
// vehicle-images%2FHYUNDAI%2FIONIQ-5%2F2024%2Fhyundai__ioniq-
|
|
74
|
-
|
|
75
|
-
// 이미지
|
|
76
|
-
const
|
|
77
|
-
brand: '
|
|
78
|
-
model: '
|
|
79
|
-
year:
|
|
80
|
-
trim: '
|
|
161
|
+
// vehicle-images%2FHYUNDAI%2FIONIQ-5%2F2024%2Fhyundai__ioniq-5__2024.png?alt=media
|
|
162
|
+
|
|
163
|
+
// 트림별 이미지
|
|
164
|
+
const url2 = generateVehicleImageUrl({
|
|
165
|
+
brand: 'mini',
|
|
166
|
+
model: 'cooper',
|
|
167
|
+
year: 2025,
|
|
168
|
+
trim: 'jcw'
|
|
81
169
|
});
|
|
82
|
-
// →
|
|
170
|
+
// → https://firebasestorage.googleapis.com/v0/b/charzing-d1600.firebasestorage.app/o/
|
|
171
|
+
// vehicle-images%2FMINI%2FCOOPER%2F2025%2Fmini__cooper__2025__jcw.png?alt=media
|
|
172
|
+
```
|
|
83
173
|
|
|
84
|
-
|
|
85
|
-
|
|
174
|
+
**파라미터**:
|
|
175
|
+
```typescript
|
|
176
|
+
interface ImageParams {
|
|
177
|
+
brand: string; // 브랜드 ID (예: 'hyundai', 'bmw')
|
|
178
|
+
model: string; // 모델 ID (예: 'ioniq-5', 'model-s')
|
|
179
|
+
year: number; // 연도 (예: 2024)
|
|
180
|
+
trim?: string; // 트림 ID (선택, 예: 'exclusive', 'jcw')
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### `generateImageFilename(params: ImageParams): string`
|
|
185
|
+
이미지 파일명만 생성합니다.
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { generateImageFilename } from '@charzing/vehicle-utils';
|
|
189
|
+
|
|
190
|
+
// 기본 파일명
|
|
191
|
+
generateImageFilename({
|
|
86
192
|
brand: 'tesla',
|
|
87
193
|
model: 'model-s',
|
|
88
194
|
year: 2024
|
|
89
195
|
});
|
|
90
196
|
// → 'tesla__model-s__2024.png'
|
|
197
|
+
|
|
198
|
+
// 트림 포함 파일명
|
|
199
|
+
generateImageFilename({
|
|
200
|
+
brand: 'porsche',
|
|
201
|
+
model: 'taycan',
|
|
202
|
+
year: 2025,
|
|
203
|
+
trim: 'turbo-gt'
|
|
204
|
+
});
|
|
205
|
+
// → 'porsche__taycan__2025__turbo-gt.png'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 📝 파일명 규칙
|
|
211
|
+
|
|
212
|
+
### 표준 패턴
|
|
213
|
+
```
|
|
214
|
+
{brandSlug}__{modelSlug}__{year}[__{trimSlug}].png
|
|
91
215
|
```
|
|
92
216
|
|
|
93
|
-
###
|
|
217
|
+
### 규칙
|
|
218
|
+
1. **전부 소문자**: `hyundai`, `ioniq-5`
|
|
219
|
+
2. **단어 구분**: 하이픈 (`-`)
|
|
220
|
+
3. **상위 구분**: 더블 언더바 (`__`)
|
|
221
|
+
4. **trim 없으면 생략**: `tesla__model-3__2024.png`
|
|
94
222
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
223
|
+
### 예시
|
|
224
|
+
```
|
|
225
|
+
✅ hyundai__ioniq-5__2024.png
|
|
226
|
+
✅ mini__cooper__2025__jcw.png
|
|
227
|
+
✅ tesla__model-3__2024__highland.png
|
|
228
|
+
✅ mercedes-benz__eqs__2024.png
|
|
229
|
+
|
|
230
|
+
❌ Hyundai_ioniq-5_2024.png (대문자 사용)
|
|
231
|
+
❌ hyundai-ioniq-5-2024.png (구분자 통일 안됨)
|
|
232
|
+
❌ hyundai_ioniq-5_2024.png (단일 언더바)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 🏗️ 프로젝트 구조
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
charzing-vehicle-utils/
|
|
241
|
+
├── src/
|
|
242
|
+
│ ├── index.ts # 메인 엔트리포인트
|
|
243
|
+
│ ├── brand.ts # 브랜드 매핑 함수
|
|
244
|
+
│ ├── model.ts # 모델 매핑 함수
|
|
245
|
+
│ ├── image.ts # 이미지 URL 생성
|
|
246
|
+
│ └── types.ts # TypeScript 타입 정의
|
|
247
|
+
├── dist/ # 빌드 결과물 (ESM + CJS)
|
|
248
|
+
├── package.json
|
|
249
|
+
├── tsconfig.json
|
|
250
|
+
└── tsup.config.ts # 빌드 설정
|
|
251
|
+
```
|
|
105
252
|
|
|
106
|
-
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 🔧 개발 가이드
|
|
256
|
+
|
|
257
|
+
### 빌드 명령어
|
|
107
258
|
|
|
108
259
|
```bash
|
|
109
260
|
# 의존성 설치
|
|
110
261
|
npm install
|
|
111
262
|
|
|
112
|
-
#
|
|
113
|
-
npm run build
|
|
114
|
-
|
|
115
|
-
# Watch 모드로 빌드
|
|
263
|
+
# 개발 모드 (Watch)
|
|
116
264
|
npm run dev
|
|
117
265
|
|
|
118
|
-
#
|
|
119
|
-
npm
|
|
266
|
+
# 프로덕션 빌드
|
|
267
|
+
npm run build
|
|
120
268
|
|
|
121
269
|
# 타입 검사
|
|
122
270
|
npm run type-check
|
|
123
271
|
|
|
124
272
|
# 린트
|
|
125
273
|
npm run lint
|
|
274
|
+
|
|
275
|
+
# 테스트
|
|
276
|
+
npm test
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 빌드 결과물
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
dist/
|
|
283
|
+
├── index.js # CommonJS (require)
|
|
284
|
+
├── index.mjs # ESM (import)
|
|
285
|
+
├── index.d.ts # TypeScript 타입 정의
|
|
286
|
+
└── index.d.mts # ESM 타입 정의
|
|
126
287
|
```
|
|
127
288
|
|
|
128
|
-
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## 🔄 업데이트 가이드
|
|
292
|
+
|
|
293
|
+
### 로컬 개발 시
|
|
294
|
+
```bash
|
|
295
|
+
# 1. vehicle-utils 수정 후 재빌드
|
|
296
|
+
cd /Users/sungmin/charzing-vehicle-utils
|
|
297
|
+
npm run build
|
|
298
|
+
|
|
299
|
+
# 2. 각 프로젝트는 자동 반영됨 (npm link로 연결되어 있음)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 프로덕션 배포 시
|
|
303
|
+
```bash
|
|
304
|
+
# 1. 버전 업데이트
|
|
305
|
+
npm version patch # 1.0.0 → 1.0.1
|
|
306
|
+
|
|
307
|
+
# 2. 빌드
|
|
308
|
+
npm run build
|
|
309
|
+
|
|
310
|
+
# 3. npm 배포
|
|
311
|
+
npm publish
|
|
312
|
+
|
|
313
|
+
# 4. 각 프로젝트에서 업데이트
|
|
314
|
+
cd /Users/sungmin/charzing-admin
|
|
315
|
+
npm update @charzing/vehicle-utils
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 🔗 관련 프로젝트
|
|
321
|
+
|
|
322
|
+
이 라이브러리를 사용하는 프로젝트들:
|
|
323
|
+
|
|
324
|
+
### 1. **charzing-admin**
|
|
325
|
+
- **위치**: `/Users/sungmin/charzing-admin`
|
|
326
|
+
- **사용**: 차량 데이터 CRUD, 이미지 URL 생성
|
|
327
|
+
- **문서**: `/Users/sungmin/charzing-admin/CLAUDE.md`
|
|
328
|
+
|
|
329
|
+
### 2. **CharzingApp-Expo**
|
|
330
|
+
- **위치**: `/Users/sungmin/CharzingApp-Expo`
|
|
331
|
+
- **사용**: 차량 선택, Firebase 데이터 조회
|
|
332
|
+
- **문서**: `/Users/sungmin/CharzingApp-Expo/CLAUDE.md`
|
|
333
|
+
|
|
334
|
+
### 3. **charzing** (웹 앱)
|
|
335
|
+
- **위치**: `/Users/sungmin/Desktop/project/react/charzing`
|
|
336
|
+
- **사용**: 예약 시스템, 차량 이미지 표시
|
|
337
|
+
- **문서**: `/Users/sungmin/Desktop/project/react/charzing/CLAUDE.md`
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 📚 TypeScript 타입
|
|
342
|
+
|
|
343
|
+
모든 함수는 완전한 TypeScript 타입 지원을 제공합니다.
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
// 브랜드 매핑
|
|
347
|
+
export function normalizeBrandId(brand: string): string;
|
|
348
|
+
export function getBrandNameKorean(brandId: string): string;
|
|
349
|
+
export function getBrandNameEnglish(brandId: string): string;
|
|
350
|
+
|
|
351
|
+
// 모델 매핑
|
|
352
|
+
export function normalizeModelId(model: string): string;
|
|
353
|
+
export function getModelNameKorean(modelId: string): string;
|
|
354
|
+
export function getModelNameEnglish(modelId: string): string;
|
|
355
|
+
|
|
356
|
+
// 이미지 URL 생성
|
|
357
|
+
export interface ImageParams {
|
|
358
|
+
brand: string;
|
|
359
|
+
model: string;
|
|
360
|
+
year: number;
|
|
361
|
+
trim?: string;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function generateVehicleImageUrl(params: ImageParams): string;
|
|
365
|
+
export function generateImageFilename(params: ImageParams): string;
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## ⚠️ 주의사항
|
|
371
|
+
|
|
372
|
+
1. **브랜드 대소문자**: BMW, MINI, PORSCHE는 Firestore에서 대문자 사용
|
|
373
|
+
2. **Storage URL**: `charzing-d1600.firebasestorage.app` (`.appspot.com` ❌)
|
|
374
|
+
3. **파일명 규칙**: 반드시 더블 언더바(`__`) 구분자 사용
|
|
375
|
+
4. **npm link**: 로컬 개발 시 빌드 후 변경사항 자동 반영됨
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 📄 라이선스
|
|
129
380
|
|
|
130
381
|
MIT
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
**마지막 업데이트**: 2025년 12월 12일
|
|
386
|
+
**버전**: 0.2.4
|
|
387
|
+
**관리자**: Charzing 개발팀
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Firestore } from 'firebase/firestore';
|
|
2
|
+
export { CELL_MAP_UNSUPPORTED_GROUPS, CELL_MAP_UNSUPPORTED_NOTICE, CELL_VOLTAGE_DELTA_THRESHOLDS, CellMapReportRef, CellMapUnsupportedGroup, CellVoltageVerdict, findCellMapUnsupportedGroup, isCellMapSupported, judgeCellVoltageByDelta } from './report/cellMap.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* 브랜드 관련 타입 정의
|
|
@@ -105,6 +106,15 @@ type TrimId = string;
|
|
|
105
106
|
* 구동 방식
|
|
106
107
|
*/
|
|
107
108
|
type DriveType = 'FWD' | 'RWD' | 'AWD' | '4WD';
|
|
109
|
+
/**
|
|
110
|
+
* 배터리 옵션 (복수 배터리 제조사 지원)
|
|
111
|
+
*/
|
|
112
|
+
interface BatteryOption {
|
|
113
|
+
/** 배터리 제조사 */
|
|
114
|
+
supplier: string;
|
|
115
|
+
/** VIN 패턴, 생산 시기 등 조건 (선택사항) */
|
|
116
|
+
condition?: string;
|
|
117
|
+
}
|
|
108
118
|
/**
|
|
109
119
|
* 차량 변형 (연식별 스펙)
|
|
110
120
|
*/
|
|
@@ -115,8 +125,10 @@ interface VehicleVariant {
|
|
|
115
125
|
batteryCapacity: number;
|
|
116
126
|
/** 주행거리 (km) */
|
|
117
127
|
range: number;
|
|
118
|
-
/** 배터리 공급사 */
|
|
128
|
+
/** 배터리 공급사 (단일, 기존 호환) */
|
|
119
129
|
supplier?: string;
|
|
130
|
+
/** 복수 배터리 공급사 (optional, supplier와 상호 배타적) */
|
|
131
|
+
batteryOptions?: BatteryOption[];
|
|
120
132
|
/** 배터리 타입 */
|
|
121
133
|
batteryType?: string;
|
|
122
134
|
/** 이미지 URL (트림별 디자인 차이가 있는 경우) */
|
package/dist/cjs/index.js
CHANGED
|
@@ -20,9 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
CELL_MAP_UNSUPPORTED_GROUPS: () => CELL_MAP_UNSUPPORTED_GROUPS,
|
|
24
|
+
CELL_MAP_UNSUPPORTED_NOTICE: () => CELL_MAP_UNSUPPORTED_NOTICE,
|
|
25
|
+
CELL_VOLTAGE_DELTA_THRESHOLDS: () => CELL_VOLTAGE_DELTA_THRESHOLDS,
|
|
23
26
|
SUPPORTED_BRANDS: () => SUPPORTED_BRANDS,
|
|
24
27
|
convertKoreanToEnglish: () => convertKoreanToEnglish,
|
|
25
28
|
findBestModelMatch: () => findBestModelMatch,
|
|
29
|
+
findCellMapUnsupportedGroup: () => findCellMapUnsupportedGroup,
|
|
26
30
|
generateImageFilename: () => generateImageFilename,
|
|
27
31
|
generateStoragePath: () => generateStoragePath,
|
|
28
32
|
generateVehicleImageUrl: () => generateVehicleImageUrl,
|
|
@@ -40,7 +44,9 @@ __export(index_exports, {
|
|
|
40
44
|
initializeBrandMappings: () => initializeBrandMappings,
|
|
41
45
|
initializeModelMappings: () => initializeModelMappings,
|
|
42
46
|
isBrandMappingInitialized: () => isInitialized,
|
|
47
|
+
isCellMapSupported: () => isCellMapSupported,
|
|
43
48
|
isModelMappingInitialized: () => isInitialized2,
|
|
49
|
+
judgeCellVoltageByDelta: () => judgeCellVoltageByDelta,
|
|
44
50
|
normalizeBrandId: () => normalizeBrandId,
|
|
45
51
|
normalizeModelId: () => normalizeModelId,
|
|
46
52
|
resetBrandCache: () => resetCache,
|
|
@@ -448,7 +454,8 @@ function generateImageFilename(params) {
|
|
|
448
454
|
const { brandId, modelId, year, trim } = params;
|
|
449
455
|
const brandLower = brandId.toLowerCase();
|
|
450
456
|
const modelLower = modelId.toLowerCase().replace(/[\s]/g, "-");
|
|
451
|
-
const
|
|
457
|
+
const normalizedTrim = trim ? normalizeStorageTrim(trim) : "";
|
|
458
|
+
const trimPart = normalizedTrim ? `__${normalizedTrim}` : "";
|
|
452
459
|
return `${brandLower}__${modelLower}__${year}${trimPart}.png`;
|
|
453
460
|
}
|
|
454
461
|
function generateStoragePath(params) {
|
|
@@ -472,11 +479,96 @@ function generateVehicleImageUrl(params) {
|
|
|
472
479
|
const encodedPath = encodeURIComponent(path);
|
|
473
480
|
return `${FIREBASE_STORAGE_BASE}/${encodedPath}?alt=media`;
|
|
474
481
|
}
|
|
482
|
+
|
|
483
|
+
// src/report/cellMap.ts
|
|
484
|
+
var CELL_MAP_UNSUPPORTED_GROUPS = [
|
|
485
|
+
{
|
|
486
|
+
label: "MINI \uCFE0\uD37C SE (2022~2023)",
|
|
487
|
+
templateIds: ["YsOQDxElF5P0thuUHKhE"],
|
|
488
|
+
// vehicles/mini/models/COOPER — name: cooper-se_2022_2023
|
|
489
|
+
years: [2022, 2023],
|
|
490
|
+
names: {
|
|
491
|
+
brand: ["\uBBF8\uB2C8", "MINI", "Mini"],
|
|
492
|
+
model: ["\uCFE0\uD37C", "COOPER", "Cooper", "Cooper SE", "\uCFE0\uD37C SE"],
|
|
493
|
+
trim: ["SE"]
|
|
494
|
+
},
|
|
495
|
+
reason: "\uC9C4\uB2E8\uAE30\uAC00 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uB0B4\uB824\uC8FC\uC9C0 \uC54A\uC74C (min/max\uB9CC \uC81C\uACF5)"
|
|
496
|
+
}
|
|
497
|
+
];
|
|
498
|
+
var CELL_MAP_UNSUPPORTED_NOTICE = {
|
|
499
|
+
/** 항상 노출 */
|
|
500
|
+
main: "\uC774 \uCC28\uB7C9\uC740 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
501
|
+
/** min/max가 있을 때만 덧붙인다 — 없는 값을 있다고 말하지 않기 위해 */
|
|
502
|
+
sub: "\uCD5C\uC18C\xB7\uCD5C\uB300 \uC804\uC555\uB9CC \uCE21\uC815\uB429\uB2C8\uB2E4",
|
|
503
|
+
/** 어드민 수동 입력 화면에서 셀 입력을 잠글 때 */
|
|
504
|
+
inputLocked: "\uC774 \uCC28\uB7C9\uC740 \uBAA8\uB4C8\uBCC4 \uC804\uC555\uC744 \uC81C\uACF5\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCD5C\uC18C\xB7\uCD5C\uB300 \uC804\uC555\uB9CC \uC785\uB825\uD558\uC138\uC694."
|
|
505
|
+
};
|
|
506
|
+
function normalizeName(value) {
|
|
507
|
+
return value.replace(/\s+/g, "").toLowerCase();
|
|
508
|
+
}
|
|
509
|
+
function matchesAnyName(value, candidates) {
|
|
510
|
+
if (!value) return false;
|
|
511
|
+
const target = normalizeName(value);
|
|
512
|
+
if (!target) return false;
|
|
513
|
+
return candidates.some((candidate) => normalizeName(candidate) === target);
|
|
514
|
+
}
|
|
515
|
+
function parseYear(value) {
|
|
516
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
517
|
+
if (typeof value === "string") {
|
|
518
|
+
const parsed = Number.parseInt(value, 10);
|
|
519
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
520
|
+
}
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
function readTemplateId(report) {
|
|
524
|
+
return report.marketplaceData?.vehicleRef?.templateId ?? report.vehicleRef?.templateId ?? null;
|
|
525
|
+
}
|
|
526
|
+
function findCellMapUnsupportedGroup(report) {
|
|
527
|
+
if (!report) return null;
|
|
528
|
+
const templateId = readTemplateId(report);
|
|
529
|
+
const year = parseYear(report.vehicleYear);
|
|
530
|
+
for (const group of CELL_MAP_UNSUPPORTED_GROUPS) {
|
|
531
|
+
if (templateId && group.templateIds.includes(templateId)) {
|
|
532
|
+
if (year === null || group.years.includes(year)) return group;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (!templateId) {
|
|
536
|
+
const brandHit = matchesAnyName(report.vehicleBrand, group.names.brand);
|
|
537
|
+
const modelHit = matchesAnyName(report.vehicleModel, group.names.model);
|
|
538
|
+
const trimHit = group.names.trim === void 0 || group.names.trim.length === 0 ? true : matchesAnyName(report.vehicleTrim, group.names.trim);
|
|
539
|
+
const yearHit = year === null ? false : group.years.includes(year);
|
|
540
|
+
if (brandHit && modelHit && trimHit && yearHit) return group;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
function isCellMapSupported(report) {
|
|
546
|
+
return findCellMapUnsupportedGroup(report) === null;
|
|
547
|
+
}
|
|
548
|
+
var CELL_VOLTAGE_DELTA_THRESHOLDS = {
|
|
549
|
+
warning: 0.03,
|
|
550
|
+
danger: 0.1
|
|
551
|
+
};
|
|
552
|
+
function round2(value) {
|
|
553
|
+
return Math.round(value * 100) / 100;
|
|
554
|
+
}
|
|
555
|
+
function judgeCellVoltageByDelta(minVoltage, maxVoltage) {
|
|
556
|
+
if (typeof minVoltage !== "number" || typeof maxVoltage !== "number") return null;
|
|
557
|
+
if (!Number.isFinite(minVoltage) || !Number.isFinite(maxVoltage)) return null;
|
|
558
|
+
const delta = round2(round2(maxVoltage) - round2(minVoltage));
|
|
559
|
+
if (delta >= CELL_VOLTAGE_DELTA_THRESHOLDS.danger) return "danger";
|
|
560
|
+
if (delta >= CELL_VOLTAGE_DELTA_THRESHOLDS.warning) return "warning";
|
|
561
|
+
return "normal";
|
|
562
|
+
}
|
|
475
563
|
// Annotate the CommonJS export names for ESM import in node:
|
|
476
564
|
0 && (module.exports = {
|
|
565
|
+
CELL_MAP_UNSUPPORTED_GROUPS,
|
|
566
|
+
CELL_MAP_UNSUPPORTED_NOTICE,
|
|
567
|
+
CELL_VOLTAGE_DELTA_THRESHOLDS,
|
|
477
568
|
SUPPORTED_BRANDS,
|
|
478
569
|
convertKoreanToEnglish,
|
|
479
570
|
findBestModelMatch,
|
|
571
|
+
findCellMapUnsupportedGroup,
|
|
480
572
|
generateImageFilename,
|
|
481
573
|
generateStoragePath,
|
|
482
574
|
generateVehicleImageUrl,
|
|
@@ -494,7 +586,9 @@ function generateVehicleImageUrl(params) {
|
|
|
494
586
|
initializeBrandMappings,
|
|
495
587
|
initializeModelMappings,
|
|
496
588
|
isBrandMappingInitialized,
|
|
589
|
+
isCellMapSupported,
|
|
497
590
|
isModelMappingInitialized,
|
|
591
|
+
judgeCellVoltageByDelta,
|
|
498
592
|
normalizeBrandId,
|
|
499
593
|
normalizeModelId,
|
|
500
594
|
resetBrandCache,
|