pda-kit-mcp-server 2.0.1
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 +107 -0
- package/bin/pda-kit-mcp.js +35 -0
- package/dist/file-reader.d.ts +83 -0
- package/dist/file-reader.d.ts.map +1 -0
- package/dist/file-reader.js +170 -0
- package/dist/file-reader.js.map +1 -0
- package/dist/http-entry.d.ts +12 -0
- package/dist/http-entry.d.ts.map +1 -0
- package/dist/http-entry.js +149 -0
- package/dist/http-entry.js.map +1 -0
- package/dist/http-server.d.ts +5 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +114 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +90 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +37 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +52 -0
- package/dist/paths.js.map +1 -0
- package/dist/server.d.ts +12 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +308 -0
- package/dist/server.js.map +1 -0
- package/dist/stdio-server.d.ts +8 -0
- package/dist/stdio-server.d.ts.map +1 -0
- package/dist/stdio-server.js +83 -0
- package/dist/stdio-server.js.map +1 -0
- package/dist/tools/generate-component.d.ts +54 -0
- package/dist/tools/generate-component.d.ts.map +1 -0
- package/dist/tools/generate-component.js +80 -0
- package/dist/tools/generate-component.js.map +1 -0
- package/dist/tools/get-component-spec.d.ts +70 -0
- package/dist/tools/get-component-spec.d.ts.map +1 -0
- package/dist/tools/get-component-spec.js +95 -0
- package/dist/tools/get-component-spec.js.map +1 -0
- package/dist/tools/get-global-rules.d.ts +42 -0
- package/dist/tools/get-global-rules.d.ts.map +1 -0
- package/dist/tools/get-global-rules.js +83 -0
- package/dist/tools/get-global-rules.js.map +1 -0
- package/dist/tools/list-components.d.ts +52 -0
- package/dist/tools/list-components.d.ts.map +1 -0
- package/dist/tools/list-components.js +104 -0
- package/dist/tools/list-components.js.map +1 -0
- package/dist/tools/search-components.d.ts +54 -0
- package/dist/tools/search-components.d.ts.map +1 -0
- package/dist/tools/search-components.js +124 -0
- package/dist/tools/search-components.js.map +1 -0
- package/dist/tools/validate-html.d.ts +43 -0
- package/dist/tools/validate-html.d.ts.map +1 -0
- package/dist/tools/validate-html.js +116 -0
- package/dist/tools/validate-html.js.map +1 -0
- package/package.json +59 -0
- package/spec-data/badge.md +461 -0
- package/spec-data/button.md +148 -0
- package/spec-data/camera.md +622 -0
- package/spec-data/dialog.md +419 -0
- package/spec-data/divider.md +208 -0
- package/spec-data/drawer.md +301 -0
- package/spec-data/empty-state.md +336 -0
- package/spec-data/home-page.md +352 -0
- package/spec-data/input-row.md +346 -0
- package/spec-data/layout-page.md +317 -0
- package/spec-data/list-item.md +128 -0
- package/spec-data/location-selector.md +630 -0
- package/spec-data/more-actions.md +427 -0
- package/spec-data/navbar.md +482 -0
- package/spec-data/photo-list.md +461 -0
- package/spec-data/picker-single.md +199 -0
- package/spec-data/picker.md +586 -0
- package/spec-data/scan-input.md +304 -0
- package/spec-data/section-heading.md +268 -0
- package/spec-data/selectable-list.md +331 -0
- package/spec-data/stepper.md +247 -0
- package/spec-data/tab-bar.md +254 -0
- package/spec-data/tab.md +349 -0
- package/spec-data/tag.md +363 -0
- package/spec-data/tooltip.md +202 -0
- package/spec-data/waybill-number.md +257 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: photo-list
|
|
3
|
+
name: 拍照列表
|
|
4
|
+
category: "媒体/Media"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
source: PDAKit-业务组件
|
|
7
|
+
source_url: https://mastergo.ky-tech.com.cn/goto/U4gdKtzv
|
|
8
|
+
source_doc_id: 103417331857122
|
|
9
|
+
component_count: 2
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# 拍照列表 Photo List
|
|
13
|
+
|
|
14
|
+
货物拍照入口列表组件,每个货物类型独立一行。未拍时右侧展示示例图,点击可放大预览(样式与相机预览一致);已拍后示例图隐藏,显示已拍摄照片缩略图(98×98px),超出宽度自动折行,点击缩略图支持删除。
|
|
15
|
+
|
|
16
|
+
> **核心规则**:每行一个拍照类型。拍摄按钮始终在左侧,右侧根据状态切换示例图 / 已拍照片列表。
|
|
17
|
+
> **颜色规则**:全部使用 Token(`--color-{色系}-{色阶}`),禁止 Hex。
|
|
18
|
+
> **字体**:PingFang SC。
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 组件总览
|
|
23
|
+
|
|
24
|
+
| 组件 | 用途 |
|
|
25
|
+
|------|------|
|
|
26
|
+
| 拍照入口行(未拍) | 拍摄按钮 + 类型名称 + 示例图(可点击放大预览) |
|
|
27
|
+
| 拍照入口行(已拍) | 拍摄按钮 + 类型名称 + 已拍照片列表(折行、可删除) |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. 布局结构
|
|
32
|
+
|
|
33
|
+
### 未拍态
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
┌── 480px ────────────────────────────────────┐
|
|
37
|
+
│ ┌──────────┐ ┌───────────────────────────┐ │
|
|
38
|
+
│ │ 📷 图标 │ │ ┌──────┐ │ │
|
|
39
|
+
│ │ 货物完整 │ │ │ 示例图 │ │ │ ← 示例图(角标左上)
|
|
40
|
+
│ │ │ │ │(角标) │ │ │
|
|
41
|
+
│ └──────────┘ │ └──────┘ │ │
|
|
42
|
+
│ └───────────────────────────┘ │
|
|
43
|
+
└─────────────────────────────────────────────┘
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 已拍态
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
┌── 480px ────────────────────────────────────┐
|
|
50
|
+
│ ┌──────────┐ ┌───────────────────────────┐ │
|
|
51
|
+
│ │ 📷 图标 │ │ ┌────┐┌────┐┌────┐┌────┐ │ │
|
|
52
|
+
│ │ 货物完整 │ │ │照片││照片││照片││照片│ │ │ ← 已拍照片(折行)
|
|
53
|
+
│ │ │ │ └────┘└────┘└────┘└────┘ │ │
|
|
54
|
+
│ └──────────┘ │ │ │
|
|
55
|
+
│ └───────────────────────────┘ │
|
|
56
|
+
└─────────────────────────────────────────────┘
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. 整体规格
|
|
62
|
+
|
|
63
|
+
| 属性 | 值 |
|
|
64
|
+
|------|------|
|
|
65
|
+
| 宽度 | `480px`,内边距 `12px` |
|
|
66
|
+
| 每行布局 | `display: flex; flex-wrap: wrap; gap: 16px; align-items: start` |
|
|
67
|
+
| 行间距 | `12px` |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 3. 拍摄按钮
|
|
72
|
+
|
|
73
|
+
| 属性 | 值 |
|
|
74
|
+
|------|------|
|
|
75
|
+
| 标签 | `<button>` |
|
|
76
|
+
| 尺寸 | `98×98px` |
|
|
77
|
+
| 布局 | `display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0; gap: 6px` |
|
|
78
|
+
| 圆角 | `4px` |
|
|
79
|
+
| 背景 | `#EEEEEE`(Black/NO.1) |
|
|
80
|
+
| 图标 | `icons/assets/common_ic_camera.svg`,尺寸 `40×40px`,颜色 Black/NO.3 |
|
|
81
|
+
| 文字 | 拍照类型名称(如「货物完整」),PingFang SC,`16px`,`font-weight: normal`,居中,颜色 `#333333`(Black/NO.6) |
|
|
82
|
+
| 交互 | 点击跳转至拍照页面([camera.md](camera.md)),以 `?types=类型1,类型2&entryIndex=0` URL 参数传入当前列表所有拍照类型 |
|
|
83
|
+
| 动效 | 缩放反馈 `150ms` |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 示例图(未拍态)
|
|
88
|
+
|
|
89
|
+
| 属性 | 值 |
|
|
90
|
+
|------|------|
|
|
91
|
+
| 容器 | `position: relative; width: 98px; height: 98px` |
|
|
92
|
+
| 图片 | `98×98px`,圆角 `4px`,`object-fit: cover`,无描边 |
|
|
93
|
+
| 背景 | `--color-grey-2`(`#F3F4F6`) |
|
|
94
|
+
| 角标 | `拍照示例图/角标.svg`,`36×36px`,绝对定位左上角 `top: 0; left: 0`,`pointer-events: none` |
|
|
95
|
+
| 交互 | 点击容器弹出全屏预览(与 camera.md 示例图预览一致) |
|
|
96
|
+
|
|
97
|
+
### 已拍照片列表(已拍态)
|
|
98
|
+
|
|
99
|
+
| 属性 | 值 |
|
|
100
|
+
|------|------|
|
|
101
|
+
| 布局 | `.photo-item-wrap` 作为 `.photo-list-row` 直接子元素,与按钮同级 flex,自然折行 |
|
|
102
|
+
| 缩略图尺寸 | `98×98px`,圆角 `4px`,与示例图尺寸一致,无描边 |
|
|
103
|
+
| 背景 | `--color-grey-2`(`#F3F4F6`) |
|
|
104
|
+
| 排列 | 自动折行,最新拍照在最右侧展示,一行最多 4 组 |
|
|
105
|
+
| 关闭按钮 | `assets/关闭按钮.svg`,`28×28px`,绝对定位右上角 `top: 0; right: 0` |
|
|
106
|
+
| 点击交互 | 点击右上角关闭按钮直接删除,Toast 提示「已删除」 |
|
|
107
|
+
| 空列表 | 已拍照片全部删除后自动切换回未拍态(显示示例图) |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 5. 照片排列规则
|
|
112
|
+
|
|
113
|
+
| 规则 | 说明 |
|
|
114
|
+
|------|------|
|
|
115
|
+
| 首行 | 按钮 + 最多 3 张照片(98×3 + 16×3 gap = 342px,总计 98 + 342 = 440px < 480px),超出 3 张则第 4 张折行 |
|
|
116
|
+
| 第二行 | 第二行折行后自然从 `.photo-list-row` 左缘开始,即与拍摄按钮左侧对齐,一行最多 4 组 |
|
|
117
|
+
| 方向 | 最新拍照在最右侧展示(数组反转渲染) |
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 6. 示例图放大预览
|
|
122
|
+
|
|
123
|
+
| 属性 | 值 |
|
|
124
|
+
|------|------|
|
|
125
|
+
| 触发 | 点击右侧示例图 |
|
|
126
|
+
| 展示 | 全屏黑色遮罩(`rgba(0,0,0,0.9)`),图片居中,上层叠加类型名称 |
|
|
127
|
+
| 类型名称样式 | `font-size: 100px; font-weight: 600; color: rgba(0, 0, 0, 0.5);` 绝对定位居中 |
|
|
128
|
+
| 关闭 | 点击遮罩任意位置关闭 |
|
|
129
|
+
| z-index | `950` |
|
|
130
|
+
| **强制一致** | 此预览样式与 [camera.md](camera.md) 示例图放大预览完全一致 |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## CSS 示例
|
|
135
|
+
|
|
136
|
+
```css
|
|
137
|
+
/* ===== 拍照入口行 ===== */
|
|
138
|
+
.photo-list-row {
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
gap: 16px;
|
|
142
|
+
align-items: start;
|
|
143
|
+
padding: 12px;
|
|
144
|
+
background: var(--color-grey-1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* 拍摄按钮 */
|
|
148
|
+
.photo-shutter {
|
|
149
|
+
width: 98px; height: 98px;
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
align-items: center;
|
|
154
|
+
padding: 0;
|
|
155
|
+
gap: 6px;
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
background: #EEEEEE;
|
|
158
|
+
border: none;
|
|
159
|
+
cursor: pointer;
|
|
160
|
+
flex-shrink: 0;
|
|
161
|
+
transition: transform 0.15s;
|
|
162
|
+
}
|
|
163
|
+
.photo-shutter:active { transform: scale(0.92); }
|
|
164
|
+
.photo-shutter-icon {
|
|
165
|
+
width: 40px; height: 40px;
|
|
166
|
+
flex-shrink: 0;
|
|
167
|
+
}
|
|
168
|
+
.photo-shutter-text {
|
|
169
|
+
font-family: PingFang SC;
|
|
170
|
+
font-size: 16px;
|
|
171
|
+
font-weight: normal;
|
|
172
|
+
line-height: normal;
|
|
173
|
+
text-align: center;
|
|
174
|
+
letter-spacing: normal;
|
|
175
|
+
color: #333333;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* 示例图(未拍态) */
|
|
179
|
+
.photo-sample-wrap {
|
|
180
|
+
position: relative;
|
|
181
|
+
width: 98px; height: 98px;
|
|
182
|
+
flex-shrink: 0;
|
|
183
|
+
cursor: pointer;
|
|
184
|
+
}
|
|
185
|
+
.photo-sample {
|
|
186
|
+
width: 98px; height: 98px;
|
|
187
|
+
border-radius: 4px;
|
|
188
|
+
border: none;
|
|
189
|
+
background: var(--color-grey-2);
|
|
190
|
+
object-fit: cover;
|
|
191
|
+
display: block;
|
|
192
|
+
}
|
|
193
|
+
.photo-sample-badge {
|
|
194
|
+
position: absolute;
|
|
195
|
+
top: 0; left: 0;
|
|
196
|
+
width: 36px; height: 36px;
|
|
197
|
+
pointer-events: none;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* 已拍照片 */
|
|
201
|
+
.photo-item-wrap {
|
|
202
|
+
position: relative;
|
|
203
|
+
width: 98px; height: 98px;
|
|
204
|
+
flex-shrink: 0;
|
|
205
|
+
}
|
|
206
|
+
.photo-item {
|
|
207
|
+
width: 98px; height: 98px;
|
|
208
|
+
border-radius: 4px;
|
|
209
|
+
border: none;
|
|
210
|
+
object-fit: cover;
|
|
211
|
+
display: block;
|
|
212
|
+
background: var(--color-grey-2);
|
|
213
|
+
}
|
|
214
|
+
.photo-item-close {
|
|
215
|
+
position: absolute;
|
|
216
|
+
top: 0; right: 0;
|
|
217
|
+
width: 28px; height: 28px;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
z-index: 1;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* ===== 示例图放大预览(与 camera.md 一致) ===== */
|
|
223
|
+
.photo-preview-overlay {
|
|
224
|
+
position: fixed; top: 0; left: 0;
|
|
225
|
+
width: 100vw; height: 100vh;
|
|
226
|
+
background: rgba(0,0,0,0.9);
|
|
227
|
+
z-index: 950;
|
|
228
|
+
display: none;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
align-items: center;
|
|
231
|
+
cursor: pointer;
|
|
232
|
+
overflow: hidden;
|
|
233
|
+
}
|
|
234
|
+
.photo-preview-overlay.show { display: flex; }
|
|
235
|
+
.photo-preview-overlay img {
|
|
236
|
+
max-width: 90vw;
|
|
237
|
+
max-height: 80vh;
|
|
238
|
+
object-fit: contain;
|
|
239
|
+
border-radius: 4px;
|
|
240
|
+
}
|
|
241
|
+
.photo-preview-title {
|
|
242
|
+
position: absolute;
|
|
243
|
+
top: 50%;
|
|
244
|
+
left: 50%;
|
|
245
|
+
transform: translate(-50%, -50%);
|
|
246
|
+
font-size: 100px;
|
|
247
|
+
font-weight: 600;
|
|
248
|
+
line-height: 1;
|
|
249
|
+
color: rgba(0, 0, 0, 0.5);
|
|
250
|
+
text-align: center;
|
|
251
|
+
font-family: PingFang SC;
|
|
252
|
+
white-space: nowrap;
|
|
253
|
+
pointer-events: none;
|
|
254
|
+
z-index: 1;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* ===== 删除确认弹窗 ===== */
|
|
258
|
+
.photo-delete-toast {
|
|
259
|
+
position: fixed;
|
|
260
|
+
top: 50%; left: 50%;
|
|
261
|
+
transform: translate(-50%, -50%);
|
|
262
|
+
background: rgba(0,0,0,0.85);
|
|
263
|
+
color: #fff;
|
|
264
|
+
padding: 16px 32px;
|
|
265
|
+
border-radius: 8px;
|
|
266
|
+
font-size: 16px;
|
|
267
|
+
font-family: PingFang SC;
|
|
268
|
+
z-index: 999;
|
|
269
|
+
opacity: 0;
|
|
270
|
+
transition: opacity 0.2s;
|
|
271
|
+
pointer-events: none;
|
|
272
|
+
text-align: center;
|
|
273
|
+
white-space: nowrap;
|
|
274
|
+
}
|
|
275
|
+
.photo-delete-toast.show { opacity: 1; }
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 资源引用说明
|
|
281
|
+
|
|
282
|
+
### 示例图路径
|
|
283
|
+
|
|
284
|
+
示例图统一存放在 `拍照示例图/` 目录下,引用路径:
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
拍照示例图/
|
|
288
|
+
├── 角标.svg # 示例图左上角角标
|
|
289
|
+
├── 货物完整@8x.png # 货物完整拍照示例
|
|
290
|
+
├── 外包装全貌照@8x.png # 外包装全貌拍照示例
|
|
291
|
+
├── 开箱点数@8x.png # 开箱点数拍照示例
|
|
292
|
+
├── 破损近景图@8x.png # 破损近景拍照示例
|
|
293
|
+
└── ... # 其他拍照类型示例图
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**引用方式**:
|
|
297
|
+
- 如果 HTML 文件在 `demos/` 目录:`../拍照示例图/货物完整@8x.png`
|
|
298
|
+
- 如果 HTML 文件在根目录:`./拍照示例图/货物完整@8x.png`
|
|
299
|
+
|
|
300
|
+
### 图标引用
|
|
301
|
+
|
|
302
|
+
| 图标 | 路径 | 用途 |
|
|
303
|
+
|------|------|------|
|
|
304
|
+
| 相机图标 | `icons/assets/common_ic_camera.svg` | 拍摄按钮图标 |
|
|
305
|
+
| 角标 | `拍照示例图/角标.svg` | 示例图左上角标记 |
|
|
306
|
+
| 关闭按钮 | `assets/关闭按钮.svg` | 已拍照片删除按钮 |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## HTML 骨架
|
|
311
|
+
|
|
312
|
+
```html
|
|
313
|
+
<!-- 拍照列表完整结构示例 -->
|
|
314
|
+
<!-- 假设 HTML 文件位于 demos/ 目录 -->
|
|
315
|
+
|
|
316
|
+
<div class="photo-list-section">
|
|
317
|
+
<!-- 标题(可选) -->
|
|
318
|
+
<div class="section-heading">
|
|
319
|
+
<span class="section-title">货物照片</span>
|
|
320
|
+
<span class="section-subtitle">(选填)</span>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<!-- 拍照列表 -->
|
|
324
|
+
<div class="photo-list">
|
|
325
|
+
<!-- 拍照入口行 -->
|
|
326
|
+
<div class="photo-list-row" data-type="货物完整">
|
|
327
|
+
<!-- 拍摄按钮 -->
|
|
328
|
+
<button class="photo-shutter" onclick="goToCamera('货物完整')">
|
|
329
|
+
<img class="photo-shutter-icon" src="../icons/assets/common_ic_camera.svg" alt="拍照" />
|
|
330
|
+
<span class="photo-shutter-text">货物完整</span>
|
|
331
|
+
</button>
|
|
332
|
+
|
|
333
|
+
<!-- 未拍态:示例图 -->
|
|
334
|
+
<div class="photo-sample-wrap" onclick="openPhotoPreview('货物完整', '../拍照示例图/货物完整@8x.png')">
|
|
335
|
+
<img class="photo-sample" src="../拍照示例图/货物完整@8x.png" alt="示例图" />
|
|
336
|
+
<img class="photo-sample-badge" src="../拍照示例图/角标.svg" alt="" />
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<!-- 已拍态:照片列表(JS 动态渲染) -->
|
|
340
|
+
<!-- <div class="photo-item-wrap">
|
|
341
|
+
<img class="photo-item" src="..." />
|
|
342
|
+
<img class="photo-item-close" src="../assets/关闭按钮.svg" onclick="deletePhoto(...)" />
|
|
343
|
+
</div> -->
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
|
|
348
|
+
<!-- 示例图放大预览 -->
|
|
349
|
+
<div class="photo-preview-overlay" id="photoPreviewOverlay"
|
|
350
|
+
onclick="closePhotoPreview()">
|
|
351
|
+
<p class="photo-preview-title" id="photoPreviewTitle"></p>
|
|
352
|
+
<img id="photoPreviewImage" src="" alt="预览" />
|
|
353
|
+
</div>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## JS 交互示例
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
// 拍照类型数据
|
|
362
|
+
// 注意:路径根据 HTML 文件位置调整
|
|
363
|
+
// 如果 HTML 在 demos/ 目录,使用 ../拍照示例图/
|
|
364
|
+
// 如果 HTML 在根目录,使用 ./拍照示例图/
|
|
365
|
+
const photoEntries = [
|
|
366
|
+
{ name: '货物完整', sample: '../拍照示例图/货物完整@8x.png', photos: [] },
|
|
367
|
+
{ name: '外包装全貌照', sample: '../拍照示例图/外包装全貌照@8x.png', photos: [] },
|
|
368
|
+
{ name: '开箱点数', sample: '../拍照示例图/开箱点数@8x.png', photos: [] },
|
|
369
|
+
];
|
|
370
|
+
|
|
371
|
+
// 渲染某行的内容区
|
|
372
|
+
function renderPhotoContent(index) {
|
|
373
|
+
const entry = photoEntries[index];
|
|
374
|
+
const rowEl = document.querySelectorAll('.photo-list-row')[index];
|
|
375
|
+
|
|
376
|
+
if (entry.photos.length === 0) {
|
|
377
|
+
// 未拍态:显示示例图
|
|
378
|
+
rowEl.querySelector('.photo-sample-wrap').style.display = 'block';
|
|
379
|
+
rowEl.querySelectorAll('.photo-item-wrap').forEach(el => el.remove());
|
|
380
|
+
} else {
|
|
381
|
+
// 已拍态:隐藏示例图,photo-item-wrap 直接作为 rowEl 子元素(按钮 + 最多3张首行,超出折行)
|
|
382
|
+
rowEl.querySelector('.photo-sample-wrap').style.display = 'none';
|
|
383
|
+
rowEl.querySelectorAll('.photo-item-wrap').forEach(el => el.remove());
|
|
384
|
+
// 反转数组使最新照片在右侧
|
|
385
|
+
[...entry.photos].reverse().forEach((src, pi) => {
|
|
386
|
+
const realIndex = entry.photos.length - 1 - pi;
|
|
387
|
+
const wrap = document.createElement('div');
|
|
388
|
+
wrap.className = 'photo-item-wrap';
|
|
389
|
+
wrap.innerHTML = `<img class="photo-item" src="${src}" alt="照片" />
|
|
390
|
+
<img class="photo-item-close" src="assets/关闭按钮.svg" alt="删除" onclick="deletePhoto(${index}, ${realIndex})" />`;
|
|
391
|
+
rowEl.appendChild(wrap);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// 删除照片(直接删除,Toast 提示)
|
|
397
|
+
function deletePhoto(entryIndex, photoIndex) {
|
|
398
|
+
photoEntries[entryIndex].photos.splice(photoIndex, 1);
|
|
399
|
+
renderPhotoContent(entryIndex);
|
|
400
|
+
showToast('已删除');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// 打开拍照组件(传入所有类型)
|
|
404
|
+
function goToCamera(entryIndex) {
|
|
405
|
+
const typeNames = photoEntries.map(e => encodeURIComponent(e.name)).join(',');
|
|
406
|
+
window.location.href = `camera.html?types=${typeNames}&entryIndex=${entryIndex}`;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// 页面初始化时检查 camera 组件回传数据
|
|
410
|
+
(function init() {
|
|
411
|
+
const cameraResult = sessionStorage.getItem('cameraResult');
|
|
412
|
+
if (cameraResult) {
|
|
413
|
+
sessionStorage.removeItem('cameraResult');
|
|
414
|
+
const result = JSON.parse(cameraResult);
|
|
415
|
+
result.types.forEach(t => {
|
|
416
|
+
if (t.count > 0) {
|
|
417
|
+
const entry = photoEntries.find(e => e.name === t.name);
|
|
418
|
+
if (entry) {
|
|
419
|
+
for (let i = 0; i < t.count; i++) entry.photos.push(t.sample);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
renderAll(); // 渲染整个列表
|
|
425
|
+
})();
|
|
426
|
+
|
|
427
|
+
// 示例图预览
|
|
428
|
+
function openPhotoPreview(name, src) {
|
|
429
|
+
document.getElementById('photoPreviewTitle').textContent = name;
|
|
430
|
+
document.getElementById('photoPreviewImage').src = src;
|
|
431
|
+
document.getElementById('photoPreviewOverlay').classList.add('show');
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function closePhotoPreview() {
|
|
435
|
+
document.getElementById('photoPreviewOverlay').classList.remove('show');
|
|
436
|
+
document.getElementById('photoPreviewTitle').textContent = '';
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 颜色 Token
|
|
443
|
+
|
|
444
|
+
| Token | 色值 | 使用场景 |
|
|
445
|
+
|-------|------|---------|
|
|
446
|
+
| `--color-grey-1` | `#FFFFFF` | 页面背景、拍摄按钮 |
|
|
447
|
+
| `--color-grey-2` | `#F3F4F6` | 示例图背景 |
|
|
448
|
+
| `--color-black-7` | `#000000` | 类型名称文字 |
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## 使用规则(AI 必读)
|
|
453
|
+
|
|
454
|
+
1. **每行一个拍照类型**:每种货物类型独立一行,各行的照片互不干扰
|
|
455
|
+
2. **双态切换**:未拍时显示示例图,拍照后示例图隐藏、显示已拍照片列表。已拍照片全部删除后自动切回未拍态
|
|
456
|
+
3. **照片折行**:`.photo-item-wrap` 直接作为 `.photo-list-row` 子元素,按钮始终在第一行,首行按钮 + 最多 3 张照片,第 4 张折行至第二行并与按钮左缘对齐
|
|
457
|
+
4. **点击删除**:点击已拍缩略图右上角关闭按钮直接删除,Toast 提示「已删除」,无需二次确认
|
|
458
|
+
5. **示例图预览与相机一致**(⚠️ 强制一致):点击示例图弹出全屏预览,文字样式(100px/600/50%透明黑居中)必须与 [camera.md](camera.md) 完全一致
|
|
459
|
+
6. **拍摄按钮样式**:`<button>` 标签 `98×98px`,`flex-direction: column`,`gap: 6px`,上方 `common_ic_camera` 图标(40×40、Black/NO.3),下方拍照类型名称(16px/normal、Black/NO.6),背景 `#EEEEEE`,圆角 `4px`
|
|
460
|
+
7. **颜色用 Token**:禁止裸 Hex,全部用 `--color-*` 引用
|
|
461
|
+
8. **拍摄按钮交互**:点击打开 [camera.md](camera.md),通过 URL 参数 `?types=货物完整,开箱点数&entryIndex=0` 传入列表所有类型。camera 组件完成拍摄后通过 `sessionStorage.setItem('cameraResult', ...)` 回传 `{ types: [{ name, count, sample }] }`,列表页在初始化时读取 `sessionStorage` 并回显照片
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: picker-single
|
|
3
|
+
name: 选择器-单选
|
|
4
|
+
category: "表单/Form"
|
|
5
|
+
version: "1.0.0"
|
|
6
|
+
source: PDAKit-业务组件
|
|
7
|
+
source_url: https://mastergo.ky-tech.com.cn/goto/TZDl2lv0
|
|
8
|
+
source_doc_id: 103417331857122
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# 选择器-单选 Picker Single
|
|
12
|
+
|
|
13
|
+
单列选择器,**纯文本选项 + 底部取消关闭**,选中态为灰底高亮,无图标指示器。用于单一项选择场景。
|
|
14
|
+
|
|
15
|
+
> **核心规则**:单列列表,单选互斥,选中项背景变灰。底部仅取消按钮,点击选项即确认/切换。
|
|
16
|
+
> **选项上限**:最多 **7 个**。
|
|
17
|
+
> **颜色规则**:全部使用 Token(`--color-{色系}-{色阶}`),禁止 Hex。
|
|
18
|
+
> **字体**:PingFang SC。
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Props
|
|
23
|
+
|
|
24
|
+
### 父组件 Props
|
|
25
|
+
|
|
26
|
+
| Prop | 类型 | 值 | 默认 |
|
|
27
|
+
|------|------|-----|------|
|
|
28
|
+
| 标题 | string | 头部标题文字 | `标题文本` |
|
|
29
|
+
| 显示关闭 | boolean | 是否显示右上角关闭按钮 | `true` |
|
|
30
|
+
| 显示描述 | boolean | 标题下方是否显示描述文字 | `false` |
|
|
31
|
+
| 描述文字 | string | 描述内容 | `描述信息位置展示` |
|
|
32
|
+
| 选项列表 | array | 选项数据(最多 7 项) | `[]` |
|
|
33
|
+
| 已选项 ID | string | 当前已选中的选项 ID | `null` |
|
|
34
|
+
|
|
35
|
+
### 选项行 Props
|
|
36
|
+
|
|
37
|
+
| Prop | 类型 | 说明 |
|
|
38
|
+
|------|------|------|
|
|
39
|
+
| 选中状态 | enum | `选中` / `默认` |
|
|
40
|
+
| 文本 | string | 选项文字 |
|
|
41
|
+
|
|
42
|
+
### 底部按钮 Props
|
|
43
|
+
|
|
44
|
+
| Prop | 类型 | 值 |
|
|
45
|
+
|------|------|------|
|
|
46
|
+
| 按钮文字 | string | `取消` |
|
|
47
|
+
| 交互 | — | 点击取消 → 关闭面板;若有已选项则带出选中值 |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 整体容器规格
|
|
52
|
+
|
|
53
|
+
| 属性 | 值 |
|
|
54
|
+
|------|------|
|
|
55
|
+
| 宽度 | `480px` |
|
|
56
|
+
| 高度 | 自适应(选项数动态),`max-height: 740px` |
|
|
57
|
+
| 布局 | `flex-column` |
|
|
58
|
+
| 圆角(顶部) | `16px` |
|
|
59
|
+
| 弹窗类型 | Bottom Sheet |
|
|
60
|
+
| 遮罩 | `rgba(0,0,0,0.4)` |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 1. 头部
|
|
65
|
+
|
|
66
|
+
| 属性 | 值 |
|
|
67
|
+
|------|------|
|
|
68
|
+
| 背景 | `--color-grey-1` |
|
|
69
|
+
| 内边距 | `24px 16px 8px` |
|
|
70
|
+
| 子元素间距 | `gap: 4px` |
|
|
71
|
+
|
|
72
|
+
| 元素 | 样式 |
|
|
73
|
+
|------|------|
|
|
74
|
+
| 标题 | `24px / 36px`, font-weight: `600`, `--color-black-6`, text-align: `center` |
|
|
75
|
+
| 描述 | `16px / 22px`, `#666666`, text-align: `center`(可选) |
|
|
76
|
+
| 关闭按钮 | `24×24`, absolute, `right: 16px, top: 24px` |
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 2. 选项列表
|
|
81
|
+
|
|
82
|
+
| 属性 | 值 |
|
|
83
|
+
|------|------|
|
|
84
|
+
| 最大数量 | **7 个** |
|
|
85
|
+
| 布局 | `flex-column` |
|
|
86
|
+
| 溢出 | `overflow-y: auto` |
|
|
87
|
+
|
|
88
|
+
### 选项行
|
|
89
|
+
|
|
90
|
+
| 属性 | 值 |
|
|
91
|
+
|------|------|
|
|
92
|
+
| 内边距 | `16px` |
|
|
93
|
+
| 文字 | `20px / 28px`, `--color-black-6`, text-align: `center`, 宽 `440px` |
|
|
94
|
+
| 默认背景 | `--color-grey-1`(`#FFFFFF`) |
|
|
95
|
+
| **选中背景** | **`--color-grey-2`**(`#F3F4F6`) |
|
|
96
|
+
| 交互 | `:active` → `--color-grey-2` |
|
|
97
|
+
|
|
98
|
+
### 行间分割线
|
|
99
|
+
|
|
100
|
+
| 属性 | 值 |
|
|
101
|
+
|------|------|
|
|
102
|
+
| 颜色 | `--color-black-2`(`#DDDDDD`) |
|
|
103
|
+
| 高度 | `1px` |
|
|
104
|
+
| 宽度 | `448px`,居中 |
|
|
105
|
+
| 规则 | 除最后一项外,每项下方显示 |
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 3. 底部取消按钮
|
|
110
|
+
|
|
111
|
+
| 属性 | 值 |
|
|
112
|
+
|------|------|
|
|
113
|
+
| 顶部分割线 | `4px solid --color-black-2`(粗线) |
|
|
114
|
+
| 按钮背景 | `--color-grey-1` |
|
|
115
|
+
| 按钮文字 | `取消`, `20px / 28px`, `--color-black-6`, 居中 |
|
|
116
|
+
| 按钮内边距 | `16px` |
|
|
117
|
+
| 交互 | `:active` → `--color-grey-2` |
|
|
118
|
+
| 行为 | 点击关闭面板;有已选项时带出选中值 |
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## HTML 骨架
|
|
123
|
+
|
|
124
|
+
```html
|
|
125
|
+
<div class="picker-single-panel">
|
|
126
|
+
<div class="picker-single-header">
|
|
127
|
+
<p class="picker-single-header-title">标题文本</p>
|
|
128
|
+
<p class="picker-single-header-desc">描述信息位置展示</p>
|
|
129
|
+
<div class="picker-single-header-close">×</div>
|
|
130
|
+
</div>
|
|
131
|
+
<div class="picker-single-list">
|
|
132
|
+
<!-- 选项循环,选中项追加 .selected -->
|
|
133
|
+
<div class="picker-single-option selected">
|
|
134
|
+
<span class="picker-single-option-text">点击</span>
|
|
135
|
+
</div>
|
|
136
|
+
<div class="picker-single-divider"></div>
|
|
137
|
+
<div class="picker-single-option">
|
|
138
|
+
<span class="picker-single-option-text">选项</span>
|
|
139
|
+
</div>
|
|
140
|
+
<!-- ...最多7项 -->
|
|
141
|
+
</div>
|
|
142
|
+
<div class="picker-single-bottom">
|
|
143
|
+
<div class="picker-single-bottom-divider"></div>
|
|
144
|
+
<button class="picker-single-btn-cancel">
|
|
145
|
+
<span class="picker-single-btn-text">取消</span>
|
|
146
|
+
</button>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## JS 交互逻辑
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
const options = [
|
|
157
|
+
{ id: '1', name: '选项一' },
|
|
158
|
+
{ id: '2', name: '选项二' },
|
|
159
|
+
// ... 最多 7 项
|
|
160
|
+
];
|
|
161
|
+
let selectedId = null;
|
|
162
|
+
|
|
163
|
+
function selectOption(id) {
|
|
164
|
+
selectedId = (selectedId === id) ? null : id;
|
|
165
|
+
renderList();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function closePicker() {
|
|
169
|
+
// 关闭面板;若有已选项则带出
|
|
170
|
+
if (selectedId) {
|
|
171
|
+
const opt = options.find(o => o.id === selectedId);
|
|
172
|
+
// 回调外传 opt
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## ⚙️ PDA 硬性约束
|
|
180
|
+
|
|
181
|
+
| # | 约束 | 值 | 原因 |
|
|
182
|
+
|---|------|-----|------|
|
|
183
|
+
| 1 | 选项上限 | **7 个** | 超过则需滚动或换组件 |
|
|
184
|
+
| 2 | 最小触控热区 | 选项行高度 ≥ **60px**(16+28+16) | 仓储手套操作 |
|
|
185
|
+
| 3 | 选中反馈 | 背景变色(`--color-grey-2`),无额外图标 | 极简设计 |
|
|
186
|
+
| 4 | 底部粗分割线 | `4px` | 视觉区分选项区与取消区 |
|
|
187
|
+
| 5 | 字体下界 | 选项文字 ≥ 20px | 小屏可读性底线 |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 🔴 常见 AI 错误
|
|
192
|
+
|
|
193
|
+
| # | ❌ 错误 | ✅ 正确 |
|
|
194
|
+
|---|--------|--------|
|
|
195
|
+
| 1 | 选项超过 7 个 | 最多 7 个,超出需分页或改用搜索选择器 |
|
|
196
|
+
| 2 | 选中态加勾选图标 | 仅灰底变色,无任何图标 |
|
|
197
|
+
| 3 | 底部加确定按钮 | 仅取消按钮 |
|
|
198
|
+
| 4 | 行间用 gap 间距 | 必须用 `1px` 分割线,最后一项无 |
|
|
199
|
+
| 5 | 底部用 `1px` 线分隔 | 必须用 `4px` 粗线 |
|