haiwei-ui 1.0.97 → 1.0.99

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haiwei-ui",
3
- "version": "1.0.97",
3
+ "version": "1.0.99",
4
4
  "description": "HaiWei前端组件库",
5
5
  "author": "Eric",
6
6
  "license": "ISC",
@@ -2,68 +2,62 @@
2
2
  <component v-bind:is="`nm-${options.showMode || 'drawer'}`" header footer draggable :padding="20" :title="title" :icon="icon" :width="width" :height="height" :visible.sync="visible_">
3
3
  <div class="import-container">
4
4
  <!-- 步骤指示器 -->
5
- <el-steps :active="currentStep" align-center class="import-steps">
6
- <el-step title="选择文件" description="上传Excel文件" />
7
- <el-step title="配置选项" description="设置解析参数" />
8
- <el-step title="数据映射" description="配置字段映射" />
9
- <el-step title="导入数据" description="执行数据导入" />
5
+ <el-steps :active="currentStep" align-center class="import-steps" simple>
6
+ <el-step title="选择文件" />
7
+ <el-step title="配置选项" />
8
+ <el-step title="数据映射" />
9
+ <el-step title="确认导入" />
10
10
  </el-steps>
11
11
 
12
12
  <!-- 步骤1:选择文件 -->
13
13
  <div v-if="currentStep === 1" class="step-content">
14
14
  <el-card shadow="never" class="step-card">
15
15
  <div slot="header" class="step-header">
16
- <span class="step-title">选择Excel文件</span>
17
- <span class="step-subtitle">支持 .xlsx 和 .xls 格式,最大10MB</span>
16
+ <div class="header-left">
17
+ <span class="step-title">选择Excel文件</span>
18
+ <span class="step-subtitle">支持 .xlsx 和 .xls 格式,最大10MB</span>
19
+ </div>
20
+ <div class="header-right">
21
+ <el-upload
22
+ ref="upload"
23
+ :action="uploadUrl"
24
+ :headers="headers"
25
+ :before-upload="beforeUpload"
26
+ :on-success="onUploadSuccess"
27
+ :on-error="onUploadError"
28
+ :on-remove="onFileRemove"
29
+ :file-list="fileList"
30
+ :limit="1"
31
+ accept=".xlsx,.xls"
32
+ :show-file-list="false"
33
+ >
34
+ <el-button type="primary" size="medium" icon="el-icon-upload">
35
+ 选择文件
36
+ </el-button>
37
+ </el-upload>
38
+ </div>
18
39
  </div>
19
40
 
20
- <el-upload
21
- ref="upload"
22
- class="upload-area"
23
- drag
24
- :action="uploadUrl"
25
- :headers="headers"
26
- :before-upload="beforeUpload"
27
- :on-success="onUploadSuccess"
28
- :on-error="onUploadError"
29
- :on-remove="onFileRemove"
30
- :file-list="fileList"
31
- :limit="1"
32
- accept=".xlsx,.xls"
33
- >
34
- <div class="upload-content">
35
- <i class="el-icon-upload upload-icon"></i>
36
- <div class="upload-text">
37
- <div class="upload-main-text">将文件拖到此处,或</div>
38
- <div class="upload-sub-text">点击上传</div>
39
- </div>
40
- <div class="upload-tip">只能上传Excel文件,且不超过10MB</div>
41
- </div>
42
- </el-upload>
43
-
44
- <div v-if="fileInfo" class="file-info-card">
45
- <el-descriptions :column="2" border size="medium" class="file-info">
41
+ <div v-if="fileInfo" class="file-info">
42
+ <el-descriptions :column="2" border size="small">
46
43
  <el-descriptions-item label="文件名">
47
- <el-tag type="success">{{ fileInfo.fileName }}</el-tag>
44
+ <el-tag type="success" size="small">{{ fileInfo.fileName }}</el-tag>
48
45
  </el-descriptions-item>
49
46
  <el-descriptions-item label="文件大小">
50
- <el-tag type="info">{{ formatFileSize(fileInfo.fileSize) }}</el-tag>
47
+ <el-tag type="info" size="small">{{ formatFileSize(fileInfo.fileSize) }}</el-tag>
51
48
  </el-descriptions-item>
52
49
  <el-descriptions-item label="工作表数量">
53
- <el-tag>{{ fileInfo.sheets.length }}个</el-tag>
54
- </el-descriptions-item>
55
- <el-descriptions-item label="解析时间">
56
- <el-tag type="warning">{{ fileInfo.parseTime }}</el-tag>
50
+ <el-tag size="small">{{ fileInfo.sheets.length }}个</el-tag>
57
51
  </el-descriptions-item>
58
52
  </el-descriptions>
59
53
 
60
54
  <div v-if="fileInfo.sheets && fileInfo.sheets.length > 0" class="sheet-select">
61
- <el-form :model="model" label-width="120px" size="medium">
62
- <el-form-item label="选择工作表:" prop="selectedSheet">
55
+ <el-form :model="model" label-width="100px" size="small">
56
+ <el-form-item label="选择工作表:">
63
57
  <el-select v-model="model.selectedSheet" placeholder="请选择要导入的工作表" style="width: 100%">
64
58
  <el-option v-for="sheet in fileInfo.sheets" :key="sheet.index" :label="sheet.name" :value="sheet.index">
65
59
  <span style="float: left">{{ sheet.name }}</span>
66
- <span style="float: right; color: #8492a6; font-size: 13px">
60
+ <span style="float: right; color: #8492a6; font-size: 12px">
67
61
  {{ sheet.rowCount }}行 × {{ sheet.columnCount }}列
68
62
  </span>
69
63
  </el-option>
@@ -72,6 +66,13 @@
72
66
  </el-form>
73
67
  </div>
74
68
  </div>
69
+
70
+ <div v-else class="upload-placeholder">
71
+ <div class="placeholder-content">
72
+ <i class="el-icon-document placeholder-icon"></i>
73
+ <div class="placeholder-text">请选择要导入的Excel文件</div>
74
+ </div>
75
+ </div>
75
76
  </el-card>
76
77
  </div>
77
78
 
@@ -79,83 +80,52 @@
79
80
  <div v-if="currentStep === 2" class="step-content">
80
81
  <el-card shadow="never" class="step-card">
81
82
  <div slot="header" class="step-header">
82
- <span class="step-title">配置解析选项</span>
83
- <span class="step-subtitle">设置Excel解析参数</span>
83
+ <div class="header-left">
84
+ <span class="step-title">配置解析选项</span>
85
+ </div>
84
86
  </div>
85
87
 
86
- <el-form ref="optionsForm" :model="model" :rules="rules" label-width="140px" size="medium">
87
- <el-row :gutter="30">
88
- <el-col :span="12">
89
- <el-form-item label="是否包含表头:" prop="hasHeader">
90
- <el-switch
91
- v-model="model.hasHeader"
92
- active-text=""
93
- inactive-text="否"
94
- active-color="#13ce66"
95
- inactive-color="#ff4949"
96
- />
97
- </el-form-item>
98
- </el-col>
99
- <el-col :span="12">
100
- <el-form-item label="跳过空行:" prop="skipEmptyRows">
101
- <el-switch
102
- v-model="model.skipEmptyRows"
103
- active-text="是"
104
- inactive-text="否"
105
- active-color="#13ce66"
106
- inactive-color="#ff4949"
107
- />
108
- </el-form-item>
109
- </el-col>
110
- </el-row>
111
-
112
- <el-row :gutter="30">
113
- <el-col :span="12">
114
- <el-form-item label="表头行行号:" prop="headerRowIndex">
115
- <el-input-number
116
- v-model="model.headerRowIndex"
117
- :min="0"
118
- :max="100"
119
- controls-position="right"
120
- style="width: 100%"
121
- placeholder="表头所在行号(从0开始)"
122
- />
123
- </el-form-item>
124
- </el-col>
125
- <el-col :span="12">
126
- <el-form-item label="最大预览行数:" prop="maxPreviewRows">
127
- <el-input-number
128
- v-model="model.maxPreviewRows"
129
- :min="1"
130
- :max="1000"
131
- controls-position="right"
132
- style="width: 100%"
133
- placeholder="最多预览多少行数据"
134
- />
135
- </el-form-item>
136
- </el-col>
137
- </el-row>
138
-
139
- <el-row :gutter="30">
140
- <el-col :span="12">
141
- <el-form-item label="数据去重:" prop="deduplicate">
142
- <el-switch
143
- v-model="model.deduplicate"
144
- active-text="是"
145
- inactive-text="否"
146
- active-color="#13ce66"
147
- inactive-color="#ff4949"
148
- />
149
- </el-form-item>
150
- </el-col>
151
- </el-row>
88
+ <el-form ref="optionsForm" :model="model" label-width="120px" size="small">
89
+ <el-form-item label="是否包含表头:">
90
+ <el-switch v-model="model.hasHeader" />
91
+ </el-form-item>
92
+
93
+ <el-form-item label="跳过空行:">
94
+ <el-switch v-model="model.skipEmptyRows" />
95
+ </el-form-item>
96
+
97
+ <el-form-item label="表头行行号:">
98
+ <el-input-number
99
+ v-model="model.headerRowIndex"
100
+ :min="0"
101
+ :max="100"
102
+ controls-position="right"
103
+ style="width: 100%"
104
+ size="small"
105
+ />
106
+ </el-form-item>
107
+
108
+ <el-form-item label="最大预览行数:">
109
+ <el-input-number
110
+ v-model="model.maxPreviewRows"
111
+ :min="1"
112
+ :max="1000"
113
+ controls-position="right"
114
+ style="width: 100%"
115
+ size="small"
116
+ />
117
+ </el-form-item>
118
+
119
+ <el-form-item label="数据去重:">
120
+ <el-switch v-model="model.deduplicate" />
121
+ </el-form-item>
152
122
 
153
123
  <div class="form-actions">
154
124
  <el-button type="primary" :loading="parsing" @click="onParse" style="width: 200px;">
155
- <i class="el-icon-search"></i> 解析文件
125
+ 解析文件
156
126
  </el-button>
157
127
  <el-button @click="currentStep = 1" style="margin-left: 20px;">
158
- <i class="el-icon-back"></i> 返回上一步
128
+ 返回上一步
159
129
  </el-button>
160
130
  </div>
161
131
  </el-form>
@@ -166,12 +136,12 @@
166
136
  <div v-if="currentStep === 3" class="step-content">
167
137
  <el-card shadow="never" class="step-card">
168
138
  <div slot="header" class="step-header">
169
- <span class="step-title">配置字段映射</span>
170
- <span class="step-subtitle">将Excel列映射到目标字段</span>
139
+ <div class="header-left">
140
+ <span class="step-title">配置字段映射</span>
141
+ </div>
171
142
  </div>
172
143
 
173
144
  <div v-if="parseResult" class="mapping-container">
174
- <!-- 数据预览 -->
175
145
  <div class="preview-section">
176
146
  <el-alert
177
147
  :title="`已解析 ${parseResult.basicInfo.rowCount} 行数据,${parseResult.basicInfo.columnCount} 列`"
@@ -185,8 +155,8 @@
185
155
  :data="parseResult.previewData"
186
156
  border
187
157
  stripe
188
- size="mini"
189
- max-height="300"
158
+ size="small"
159
+ max-height="200"
190
160
  v-loading="parsing"
191
161
  class="preview-table"
192
162
  >
@@ -197,33 +167,20 @@
197
167
  :label="col.label"
198
168
  :width="col.width"
199
169
  show-overflow-tooltip
200
- >
201
- <template v-slot:header>
202
- <div class="column-header">
203
- <div class="column-label">{{ col.label }}</div>
204
- <div class="column-name">({{ col.name }})</div>
205
- </div>
206
- </template>
207
- </el-table-column>
170
+ />
208
171
  </el-table>
209
-
210
- <div v-if="parseResult.basicInfo && parseResult.basicInfo.totalRows > parseResult.basicInfo.rowCount" class="preview-tip">
211
- 仅显示前{{ parseResult.basicInfo.rowCount }}行,共{{ parseResult.basicInfo.totalRows }}行数据
212
- </div>
213
172
  </div>
214
173
 
215
- <!-- 列映射配置 -->
216
174
  <div class="mapping-section">
217
- <el-table :data="columnMapping" border stripe size="mini" max-height="300" class="mapping-table">
218
- <el-table-column prop="excelColumn" label="Excel列" width="180" fixed>
175
+ <el-table :data="columnMapping" border stripe size="small" max-height="200" class="mapping-table">
176
+ <el-table-column prop="excelColumn" label="Excel列" width="150">
219
177
  <template v-slot="{ row }">
220
178
  <div class="excel-column">
221
179
  <div class="column-label">{{ row.excelColumn.label }}</div>
222
- <div class="column-name">{{ row.excelColumn.name }}</div>
223
180
  </div>
224
181
  </template>
225
182
  </el-table-column>
226
- <el-table-column prop="targetColumn" label="目标字段" width="220">
183
+ <el-table-column prop="targetColumn" label="目标字段" width="180">
227
184
  <template v-slot="{ row }">
228
185
  <el-select
229
186
  v-model="row.targetColumn"
@@ -231,6 +188,7 @@
231
188
  style="width: 100%"
232
189
  clearable
233
190
  filterable
191
+ size="small"
234
192
  >
235
193
  <el-option label="不导入此列" :value="null"></el-option>
236
194
  <el-option
@@ -238,26 +196,13 @@
238
196
  :key="col.name"
239
197
  :label="col.label"
240
198
  :value="col.name"
241
- >
242
- <span style="float: left">{{ col.label }}</span>
243
- <span style="float: right; color: #8492a6; font-size: 13px">{{ col.name }}</span>
244
- </el-option>
199
+ />
245
200
  </el-select>
246
201
  </template>
247
202
  </el-table-column>
248
- <el-table-column prop="required" label="必填" width="80" align="center">
249
- <template v-slot="{ row }">
250
- <el-checkbox v-model="row.required" :disabled="!row.targetColumn"></el-checkbox>
251
- </template>
252
- </el-table-column>
253
- <el-table-column prop="defaultValue" label="默认值" min-width="150">
203
+ <el-table-column prop="required" label="必填" width="60" align="center">
254
204
  <template v-slot="{ row }">
255
- <el-input
256
- v-model="row.defaultValue"
257
- :disabled="!row.targetColumn"
258
- placeholder="当Excel为空时使用此默认值"
259
- size="mini"
260
- />
205
+ <el-checkbox v-model="row.required" :disabled="!row.targetColumn" size="small" />
261
206
  </template>
262
207
  </el-table-column>
263
208
  </el-table>
@@ -265,25 +210,26 @@
265
210
 
266
211
  <div class="form-actions">
267
212
  <el-button type="primary" @click="currentStep = 4" style="width: 200px;">
268
- <i class="el-icon-arrow-right"></i> 下一步:导入设置
213
+ 下一步:确认导入
269
214
  </el-button>
270
215
  <el-button @click="currentStep = 2" style="margin-left: 20px;">
271
- <i class="el-icon-back"></i> 返回上一步
216
+ 返回上一步
272
217
  </el-button>
273
218
  <el-button type="info" @click="onParse" :loading="parsing" style="margin-left: 20px;">
274
- <i class="el-icon-refresh"></i> 重新解析
219
+ 重新解析
275
220
  </el-button>
276
221
  </div>
277
222
  </div>
278
223
  </el-card>
279
224
  </div>
280
225
 
281
- <!-- 步骤4:导入数据 -->
226
+ <!-- 步骤4:确认导入 -->
282
227
  <div v-if="currentStep === 4" class="step-content">
283
228
  <el-card shadow="never" class="step-card">
284
229
  <div slot="header" class="step-header">
285
- <span class="step-title">确认导入</span>
286
- <span class="step-subtitle">确认数据映射并执行导入</span>
230
+ <div class="header-left">
231
+ <span class="step-title">确认导入</span>
232
+ </div>
287
233
  </div>
288
234
 
289
235
  <div class="import-summary">
@@ -295,25 +241,18 @@
295
241
  />
296
242
 
297
243
  <div class="mapping-summary">
298
- <el-descriptions :column="2" border size="medium" class="summary-info">
244
+ <el-descriptions :column="2" border size="small">
299
245
  <el-descriptions-item label="Excel文件">
300
- <el-tag type="success">{{ fileInfo.fileName }}</el-tag>
246
+ <el-tag type="success" size="small">{{ fileInfo.fileName }}</el-tag>
301
247
  </el-descriptions-item>
302
248
  <el-descriptions-item label="工作表">
303
- <el-tag>{{ getSelectedSheetName() }}</el-tag>
249
+ <el-tag size="small">{{ getSelectedSheetName() }}</el-tag>
304
250
  </el-descriptions-item>
305
251
  <el-descriptions-item label="总行数">
306
- <el-tag type="info">{{ parseResult.basicInfo.totalRows }}</el-tag>
307
- </el-descriptions-item>
308
- <el-descriptions-item label="总列数">
309
- <el-tag type="info">{{ parseResult.basicInfo.totalColumns }}</el-tag>
252
+ <el-tag type="info" size="small">{{ parseResult.basicInfo.totalRows }}</el-tag>
310
253
  </el-descriptions-item>
311
254
  <el-descriptions-item label="已配置映射">
312
- <el-tag type="success">{{ getMappedColumnsCount() }}列</el-tag>
313
- </el-descriptions-item>
314
- <el-descriptions-item label="未配置映射">
315
- <el-tag v-if="getUnmappedColumnsCount() > 0" type="danger">{{ getUnmappedColumnsCount() }}列</el-tag>
316
- <el-tag v-else type="success">全部已配置</el-tag>
255
+ <el-tag type="success" size="small">{{ getMappedColumnsCount() }}列</el-tag>
317
256
  </el-descriptions-item>
318
257
  </el-descriptions>
319
258
  </div>
@@ -321,10 +260,10 @@
321
260
 
322
261
  <div class="form-actions">
323
262
  <el-button type="success" :loading="importing" @click="onImport" style="width: 200px;">
324
- <i class="el-icon-upload2"></i> 开始导入
263
+ 开始导入
325
264
  </el-button>
326
265
  <el-button @click="currentStep = 3" style="margin-left: 20px;">
327
- <i class="el-icon-back"></i> 返回上一步
266
+ 返回上一步
328
267
  </el-button>
329
268
  </div>
330
269
  </el-card>
@@ -335,13 +274,13 @@
335
274
  <template v-slot:footer>
336
275
  <el-button-group>
337
276
  <el-button v-if="currentStep > 1" @click="currentStep--">
338
- <i class="el-icon-arrow-left"></i> 上一步
277
+ 上一步
339
278
  </el-button>
340
279
  <el-button v-if="currentStep < 4 && fileInfo" type="primary" @click="currentStep++">
341
- 下一步 <i class="el-icon-arrow-right"></i>
280
+ 下一步
342
281
  </el-button>
343
282
  <el-button type="info" @click="hide">
344
- <i class="el-icon-close"></i> 取消
283
+ 取消
345
284
  </el-button>
346
285
  </el-button-group>
347
286
  </template>
@@ -359,8 +298,8 @@ export default {
359
298
  return {
360
299
  title: '数据导入',
361
300
  icon: 'import',
362
- width: '1000px',
363
- height: '750px',
301
+ width: '900px',
302
+ height: '650px',
364
303
  currentStep: 1,
365
304
  model: {
366
305
  file: null,
@@ -369,13 +308,7 @@ export default {
369
308
  skipEmptyRows: false,
370
309
  headerRowIndex: 0,
371
310
  maxPreviewRows: 100,
372
- deduplicate: true,
373
- deduplicateFields: []
374
- },
375
- rules: {
376
- selectedSheet: [{ required: true, message: '请选择工作表', trigger: 'change' }],
377
- headerRowIndex: [{ required: true, message: '请输入表头行行号', trigger: 'blur' }],
378
- maxPreviewRows: [{ required: true, message: '请输入最大预览行数', trigger: 'blur' }]
311
+ deduplicate: true
379
312
  },
380
313
  fileList: [],
381
314
  fileInfo: null,
@@ -496,26 +429,11 @@ export default {
496
429
  const selectedSheet = this.fileInfo.sheets.find(sheet => sheet.index === this.model.selectedSheet)
497
430
  const sheetName = selectedSheet ? selectedSheet.name : null
498
431
 
499
- // 添加解析参数
500
- formData.append('hasHeader', this.model.hasHeader)
501
- formData.append('skipEmptyRows', this.model.skipEmptyRows)
502
- formData.append('headerRowIndex', this.model.headerRowIndex)
503
- formData.append('maxPreviewRows', this.model.maxPreviewRows)
504
- if (sheetName) {
505
- formData.append('sheetName', sheetName)
506
- }
507
-
508
432
  // 从token模块获取token
509
433
  const t = token.get()
510
434
  const accessToken = t && t.accessToken ? t.accessToken : ''
511
- const config = {
512
- headers: {
513
- 'Content-Type': 'multipart/form-data',
514
- 'Authorization': `Bearer ${accessToken}`
515
- }
516
- }
517
435
 
518
- // 构建解析URL
436
+ // 构建解析URL - 使用与uploadUrl相同的方式
519
437
  let baseURL = this.$http?.axios?.defaults?.baseURL || window.__HAIWEI_API_BASE_URL__ || '/api'
520
438
  if (!baseURL.endsWith('/')) {
521
439
  baseURL += '/'
@@ -535,38 +453,47 @@ export default {
535
453
 
536
454
  const fullUrl = `${parseUrl}?${queryParams.toString()}`
537
455
 
538
- this.$http.post(fullUrl, formData, config)
539
- .then(response => {
540
- if (response.data && response.data.code === 1) {
541
- this.fileInfo = response.data.data.basicInfo
542
- this.parseResult = {
543
- basicInfo: response.data.data.basicInfo,
544
- columns: response.data.data.headers.map((header, index) => ({
545
- name: `col${index}`,
546
- label: header.name,
547
- width: 120
548
- })),
549
- previewData: response.data.data.data.map(row => {
550
- const obj = {}
551
- response.data.data.headers.forEach((header, colIndex) => {
552
- obj[`col${colIndex}`] = row[colIndex]
553
- })
554
- return obj
456
+ // 使用fetch API发送请求,避免axios依赖问题
457
+ fetch(fullUrl, {
458
+ method: 'POST',
459
+ body: formData,
460
+ headers: {
461
+ 'Authorization': `Bearer ${accessToken}`
462
+ // 注意:不要设置Content-Type,让浏览器自动设置multipart/form-data的boundary
463
+ }
464
+ })
465
+ .then(response => response.json())
466
+ .then(data => {
467
+ if (data && data.code === 1) {
468
+ this.fileInfo = data.data.basicInfo
469
+ this.parseResult = {
470
+ basicInfo: data.data.basicInfo,
471
+ columns: data.data.headers.map((header, index) => ({
472
+ name: `col${index}`,
473
+ label: header.name,
474
+ width: 120
475
+ })),
476
+ previewData: data.data.data.map(row => {
477
+ const obj = {}
478
+ data.data.headers.forEach((header, colIndex) => {
479
+ obj[`col${colIndex}`] = row[colIndex]
555
480
  })
556
- }
557
- this.initColumnMapping()
558
- this.currentStep = 3
559
- this._success('文件解析成功')
560
- } else {
561
- this._error(response.data.msg || '文件解析失败')
481
+ return obj
482
+ })
562
483
  }
563
- })
564
- .catch(error => {
565
- this._error('文件解析失败:' + (error.message || '未知错误'))
566
- })
567
- .finally(() => {
568
- this.parsing = false
569
- })
484
+ this.initColumnMapping()
485
+ this.currentStep = 3
486
+ this._success('文件解析成功')
487
+ } else {
488
+ this._error(data.msg || '文件解析失败')
489
+ }
490
+ })
491
+ .catch(error => {
492
+ this._error('文件解析失败:' + (error.message || '未知错误'))
493
+ })
494
+ .finally(() => {
495
+ this.parsing = false
496
+ })
570
497
  },
571
498
 
572
499
  initColumnMapping() {
@@ -575,8 +502,7 @@ export default {
575
502
  this.columnMapping = this.parseResult.columns.map(col => ({
576
503
  excelColumn: col,
577
504
  targetColumn: this.findBestMatch(col),
578
- required: false,
579
- defaultValue: ''
505
+ required: false
580
506
  }))
581
507
  },
582
508
 
@@ -584,17 +510,12 @@ export default {
584
510
  if (!this.targetColumns || this.targetColumns.length === 0) return null
585
511
 
586
512
  const excelLabel = excelColumn.label.toLowerCase()
587
- const excelName = excelColumn.name.toLowerCase()
588
513
 
589
- // 1. 尝试完全匹配标签
514
+ // 尝试完全匹配标签
590
515
  let match = this.targetColumns.find(col => col.label.toLowerCase() === excelLabel)
591
516
  if (match) return match.name
592
517
 
593
- // 2. 尝试完全匹配名称
594
- match = this.targetColumns.find(col => col.name.toLowerCase() === excelName)
595
- if (match) return match.name
596
-
597
- // 3. 尝试包含匹配
518
+ // 尝试包含匹配
598
519
  match = this.targetColumns.find(col =>
599
520
  excelLabel.includes(col.label.toLowerCase()) ||
600
521
  col.label.toLowerCase().includes(excelLabel)
@@ -674,11 +595,6 @@ export default {
674
595
  const targetColumn = mapping.targetColumn
675
596
  let value = row[excelColumnName]
676
597
 
677
- // 如果值为空且设置了默认值,使用默认值
678
- if ((value === null || value === undefined || value === '') && mapping.defaultValue) {
679
- value = mapping.defaultValue
680
- }
681
-
682
598
  // 设置到AddModel中
683
599
  addModel[targetColumn] = value
684
600
  })
@@ -709,8 +625,7 @@ export default {
709
625
  return addModels
710
626
  }
711
627
 
712
- // 使用第一个目标字段作为去重依据(通常是最重要的字段,如员工号、工具编码等)
713
- // 在实际应用中,可能需要更复杂的去重逻辑,比如多个字段组合
628
+ // 使用第一个目标字段作为去重依据
714
629
  const deduplicateField = targetFields[0]
715
630
 
716
631
  // 使用Map进行去重,保留第一次出现的数据
@@ -730,9 +645,6 @@ export default {
730
645
  if (!uniqueMap.has(key)) {
731
646
  uniqueMap.set(key, true)
732
647
  deduplicatedModels.push(model)
733
- } else {
734
- // 重复数据,记录日志(可选)
735
- console.log(`发现重复数据,字段 ${deduplicateField} = ${key},已跳过`)
736
648
  }
737
649
  }
738
650
 
@@ -765,11 +677,6 @@ export default {
765
677
  getMappedColumnsCount() {
766
678
  if (!this.columnMapping) return 0
767
679
  return this.columnMapping.filter(mapping => mapping.targetColumn).length
768
- },
769
-
770
- getUnmappedColumnsCount() {
771
- if (!this.columnMapping) return 0
772
- return this.columnMapping.filter(mapping => !mapping.targetColumn).length
773
680
  }
774
681
  },
775
682
  created() {
@@ -781,126 +688,100 @@ export default {
781
688
  <style lang="scss" scoped>
782
689
  .import-container {
783
690
  .import-steps {
784
- margin-bottom: 30px;
691
+ margin-bottom: 20px;
785
692
  }
786
693
 
787
694
  .step-content {
788
695
  .step-card {
789
- border: 1px solid #ebeef5;
790
- border-radius: 8px;
696
+ border: 1px solid #dcdfe6;
697
+ border-radius: 4px;
791
698
 
792
699
  .step-header {
793
700
  display: flex;
794
- flex-direction: column;
795
- padding: 15px 20px;
796
- border-bottom: 1px solid #ebeef5;
701
+ justify-content: space-between;
702
+ align-items: center;
703
+ padding: 12px 16px;
704
+ border-bottom: 1px solid #dcdfe6;
705
+ background-color: #f5f7fa;
797
706
 
798
- .step-title {
799
- font-size: 16px;
800
- font-weight: 600;
801
- color: #303133;
802
- margin-bottom: 5px;
707
+ .header-left {
708
+ display: flex;
709
+ flex-direction: column;
710
+
711
+ .step-title {
712
+ font-size: 14px;
713
+ font-weight: 600;
714
+ color: #303133;
715
+ margin-bottom: 4px;
716
+ }
717
+
718
+ .step-subtitle {
719
+ font-size: 12px;
720
+ color: #909399;
721
+ }
803
722
  }
804
723
 
805
- .step-subtitle {
806
- font-size: 13px;
807
- color: #909399;
724
+ .header-right {
725
+ display: flex;
726
+ align-items: center;
808
727
  }
809
728
  }
810
729
  }
811
730
  }
812
731
 
813
- .upload-area {
814
- .upload-content {
815
- display: flex;
816
- flex-direction: column;
817
- align-items: center;
818
- justify-content: center;
819
- padding: 40px 20px;
820
-
821
- .upload-icon {
822
- font-size: 48px;
732
+ .upload-placeholder {
733
+ display: flex;
734
+ flex-direction: column;
735
+ align-items: center;
736
+ justify-content: center;
737
+ padding: 40px 16px;
738
+ text-align: center;
739
+
740
+ .placeholder-content {
741
+ .placeholder-icon {
742
+ font-size: 36px;
823
743
  color: #c0c4cc;
824
- margin-bottom: 20px;
744
+ margin-bottom: 16px;
825
745
  }
826
746
 
827
- .upload-text {
828
- text-align: center;
829
- margin-bottom: 15px;
830
-
831
- .upload-main-text {
832
- font-size: 14px;
833
- color: #606266;
834
- margin-bottom: 5px;
835
- }
836
-
837
- .upload-sub-text {
838
- font-size: 16px;
839
- color: #409eff;
840
- font-weight: 500;
841
- }
842
- }
843
-
844
- .upload-tip {
845
- font-size: 12px;
846
- color: #909399;
747
+ .placeholder-text {
748
+ font-size: 14px;
749
+ color: #606266;
750
+ margin-bottom: 8px;
751
+ font-weight: 500;
847
752
  }
848
753
  }
849
754
  }
850
755
 
851
- .file-info-card {
852
- margin-top: 20px;
853
- padding: 20px;
756
+ .file-info {
757
+ margin-top: 16px;
758
+ padding: 16px;
854
759
  background-color: #f8f9fa;
855
- border-radius: 6px;
856
-
857
- .file-info {
858
- margin-bottom: 20px;
859
- }
760
+ border-radius: 4px;
860
761
 
861
762
  .sheet-select {
862
- margin-top: 20px;
763
+ margin-top: 16px;
863
764
  }
864
765
  }
865
766
 
866
767
  .form-actions {
867
768
  display: flex;
868
769
  justify-content: center;
869
- margin-top: 30px;
870
- padding-top: 20px;
871
- border-top: 1px solid #ebeef5;
770
+ margin-top: 24px;
771
+ padding-top: 16px;
772
+ border-top: 1px solid #dcdfe6;
872
773
  }
873
774
 
874
775
  .mapping-container {
875
776
  .preview-section {
876
- margin-bottom: 30px;
777
+ margin-bottom: 24px;
877
778
 
878
779
  .preview-alert {
879
- margin-bottom: 15px;
780
+ margin-bottom: 12px;
880
781
  }
881
782
 
882
783
  .preview-table {
883
- margin-bottom: 10px;
884
-
885
- .column-header {
886
- text-align: center;
887
-
888
- .column-label {
889
- font-weight: 500;
890
- }
891
-
892
- .column-name {
893
- font-size: 11px;
894
- color: #909399;
895
- }
896
- }
897
- }
898
-
899
- .preview-tip {
900
- text-align: center;
901
- font-size: 12px;
902
- color: #909399;
903
- margin-top: 10px;
784
+ margin-bottom: 8px;
904
785
  }
905
786
  }
906
787
 
@@ -909,12 +790,6 @@ export default {
909
790
  .excel-column {
910
791
  .column-label {
911
792
  font-weight: 500;
912
- margin-bottom: 3px;
913
- }
914
-
915
- .column-name {
916
- font-size: 11px;
917
- color: #909399;
918
793
  }
919
794
  }
920
795
  }
@@ -922,7 +797,7 @@ export default {
922
797
  }
923
798
 
924
799
  .import-summary {
925
- margin: 20px 0;
800
+ margin: 16px 0;
926
801
  }
927
802
  }
928
803
  </style>