|
|
@@ -9,36 +9,39 @@
|
|
9
|
9
|
<el-card class="combined-import-card" shadow="never">
|
|
10
|
10
|
<div class="combined-inner">
|
|
11
|
11
|
<div class="combined-info">
|
|
12
|
|
- <el-icon class="combined-icon"><Files /></el-icon>
|
|
|
12
|
+ <el-icon class="combined-icon">
|
|
|
13
|
+ <Files />
|
|
|
14
|
+ </el-icon>
|
|
13
|
15
|
<div>
|
|
14
|
16
|
<div class="combined-title">一键全量导入</div>
|
|
15
|
17
|
<div class="combined-desc">上传「旅检三部"三三"数字管理平台.xlsx」,系统将自动识别20个Sheet并分别导入对应台账表</div>
|
|
16
|
18
|
</div>
|
|
17
|
19
|
</div>
|
|
18
|
20
|
<div class="combined-btns">
|
|
19
|
|
- <el-upload
|
|
20
|
|
- :action="''"
|
|
21
|
|
- :auto-upload="false"
|
|
22
|
|
- :show-file-list="false"
|
|
23
|
|
- :on-change="handleCombinedChange"
|
|
24
|
|
- accept=".xlsx,.xls"
|
|
25
|
|
- >
|
|
|
21
|
+ <el-button v-hasPermi="['ledger:sync:all']" type="primary" size="large" :loading="syncing"
|
|
|
22
|
+ class="combined-btn" @click="handleSync">
|
|
|
23
|
+ 同步台账
|
|
|
24
|
+ </el-button>
|
|
|
25
|
+
|
|
|
26
|
+ <el-upload :action="''" :auto-upload="false" :show-file-list="false" :on-change="handleCombinedChange"
|
|
|
27
|
+ accept=".xlsx,.xls">
|
|
26
|
28
|
<el-button type="primary" size="large" :loading="combinedLoading" class="combined-btn">
|
|
27
|
|
- <el-icon><Upload /></el-icon> 选择文件并全量导入
|
|
|
29
|
+ <el-icon>
|
|
|
30
|
+ <Upload />
|
|
|
31
|
+ </el-icon> 选择文件并全量导入
|
|
28
|
32
|
</el-button>
|
|
29
|
33
|
</el-upload>
|
|
30
|
34
|
<el-button size="large" class="combined-tpl-btn" @click="downloadCombinedTemplate">
|
|
31
|
|
- <el-icon><Download /></el-icon> 下载合并模板
|
|
|
35
|
+ <el-icon>
|
|
|
36
|
+ <Download />
|
|
|
37
|
+ </el-icon> 下载合并模板
|
|
32
|
38
|
</el-button>
|
|
33
|
39
|
</div>
|
|
34
|
40
|
</div>
|
|
35
|
41
|
<div v-if="combinedResult" class="combined-result">
|
|
36
|
42
|
<div class="result-title">导入结果:</div>
|
|
37
|
|
- <el-tag
|
|
38
|
|
- v-for="(msg, sheet) in combinedResult" :key="sheet"
|
|
39
|
|
- :type="msg.includes('失败') || msg.includes('错误') ? 'danger' : 'success'"
|
|
40
|
|
- class="result-tag"
|
|
41
|
|
- >
|
|
|
43
|
+ <el-tag v-for="(msg, sheet) in combinedResult" :key="sheet"
|
|
|
44
|
+ :type="msg.includes('失败') || msg.includes('错误') ? 'danger' : 'success'" class="result-tag">
|
|
42
|
45
|
{{ sheet }}:{{ msg }}
|
|
43
|
46
|
</el-tag>
|
|
44
|
47
|
</div>
|
|
|
@@ -48,31 +51,25 @@
|
|
48
|
51
|
<el-card class="clear-card" shadow="never">
|
|
49
|
52
|
<div class="clear-inner">
|
|
50
|
53
|
<div class="clear-info">
|
|
51
|
|
- <el-icon class="clear-icon"><DeleteFilled /></el-icon>
|
|
|
54
|
+ <el-icon class="clear-icon">
|
|
|
55
|
+ <DeleteFilled />
|
|
|
56
|
+ </el-icon>
|
|
52
|
57
|
<div>
|
|
53
|
58
|
<div class="clear-title">清理台账数据</div>
|
|
54
|
59
|
<div class="clear-desc">按导入时间范围删除全部20张台账表数据,同步清除台账来源的配分事项(手动录入不受影响)</div>
|
|
55
|
60
|
</div>
|
|
56
|
61
|
</div>
|
|
57
|
62
|
<div class="clear-actions">
|
|
58
|
|
- <el-date-picker
|
|
59
|
|
- v-model="clearBeginDate"
|
|
60
|
|
- type="date"
|
|
61
|
|
- value-format="YYYY-MM-DD"
|
|
62
|
|
- placeholder="开始日期"
|
|
63
|
|
- style="width: 150px"
|
|
64
|
|
- />
|
|
|
63
|
+ <el-date-picker v-model="clearBeginDate" type="date" value-format="YYYY-MM-DD" placeholder="开始日期"
|
|
|
64
|
+ style="width: 150px" />
|
|
65
|
65
|
<span style="margin: 0 6px; color: #909399;">至</span>
|
|
66
|
|
- <el-date-picker
|
|
67
|
|
- v-model="clearEndDate"
|
|
68
|
|
- type="date"
|
|
69
|
|
- value-format="YYYY-MM-DD"
|
|
70
|
|
- placeholder="结束日期"
|
|
71
|
|
- :disabled-date="(d) => clearBeginDate && d < new Date(clearBeginDate)"
|
|
72
|
|
- style="width: 150px"
|
|
73
|
|
- />
|
|
74
|
|
- <el-button type="danger" :loading="clearLoading" :disabled="!clearBeginDate || !clearEndDate" @click="handleClear">
|
|
75
|
|
- <el-icon><Delete /></el-icon> 清理
|
|
|
66
|
+ <el-date-picker v-model="clearEndDate" type="date" value-format="YYYY-MM-DD" placeholder="结束日期"
|
|
|
67
|
+ :disabled-date="(d) => clearBeginDate && d <= new Date(new Date(clearBeginDate).getTime() - 24 * 60 * 60 * 1000)" style="width: 150px" />
|
|
|
68
|
+ <el-button type="danger" :loading="clearLoading" :disabled="!clearBeginDate || !clearEndDate"
|
|
|
69
|
+ @click="handleClear">
|
|
|
70
|
+ <el-icon>
|
|
|
71
|
+ <Delete />
|
|
|
72
|
+ </el-icon> 清理
|
|
76
|
73
|
</el-button>
|
|
77
|
74
|
</div>
|
|
78
|
75
|
</div>
|
|
|
@@ -92,30 +89,32 @@
|
|
92
|
89
|
<div v-for="item in importItems" :key="item.key" class="import-card">
|
|
93
|
90
|
<el-card shadow="hover" :class="['ledger-card', item.status]">
|
|
94
|
91
|
<div class="card-header">
|
|
95
|
|
- <el-icon class="card-icon"><component :is="item.icon" /></el-icon>
|
|
|
92
|
+ <el-icon class="card-icon">
|
|
|
93
|
+ <component :is="item.icon" />
|
|
|
94
|
+ </el-icon>
|
|
96
|
95
|
<div class="card-title">{{ item.title }}</div>
|
|
97
|
96
|
</div>
|
|
98
|
97
|
<div class="card-desc">{{ item.desc }}</div>
|
|
99
|
98
|
<div class="card-actions">
|
|
100
|
|
- <el-upload
|
|
101
|
|
- ref="uploadRefs"
|
|
102
|
|
- :action="''"
|
|
103
|
|
- :auto-upload="false"
|
|
104
|
|
- :show-file-list="false"
|
|
105
|
|
- :before-upload="(file) => beforeUpload(file, item)"
|
|
106
|
|
- :on-change="(file) => handleFileChange(file, item)"
|
|
107
|
|
- accept=".xlsx,.xls"
|
|
108
|
|
- >
|
|
|
99
|
+ <el-upload ref="uploadRefs" :action="''" :auto-upload="false" :show-file-list="false"
|
|
|
100
|
+ :before-upload="(file) => beforeUpload(file, item)" :on-change="(file) => handleFileChange(file, item)"
|
|
|
101
|
+ accept=".xlsx,.xls">
|
|
109
|
102
|
<el-button type="primary" size="small" :loading="item.loading">
|
|
110
|
|
- <el-icon><Upload /></el-icon> 选择文件上传
|
|
|
103
|
+ <el-icon>
|
|
|
104
|
+ <Upload />
|
|
|
105
|
+ </el-icon> 选择文件上传
|
|
111
|
106
|
</el-button>
|
|
112
|
107
|
</el-upload>
|
|
113
|
108
|
<el-button size="small" text @click="downloadTemplate(item)">
|
|
114
|
|
- <el-icon><Download /></el-icon> 下载模板
|
|
|
109
|
+ <el-icon>
|
|
|
110
|
+ <Download />
|
|
|
111
|
+ </el-icon> 下载模板
|
|
115
|
112
|
</el-button>
|
|
116
|
113
|
</div>
|
|
117
|
114
|
<div v-if="item.lastResult" class="last-result" :class="item.lastResult.success ? 'success' : 'error'">
|
|
118
|
|
- <el-icon><component :is="item.lastResult.success ? 'CircleCheck' : 'CircleClose'" /></el-icon>
|
|
|
115
|
+ <el-icon>
|
|
|
116
|
+ <component :is="item.lastResult.success ? 'CircleCheck' : 'CircleClose'" />
|
|
|
117
|
+ </el-icon>
|
|
119
|
118
|
{{ item.lastResult.msg }}
|
|
120
|
119
|
</div>
|
|
121
|
120
|
</el-card>
|
|
|
@@ -129,6 +128,7 @@ import { ref, reactive } from 'vue'
|
|
129
|
128
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
130
|
129
|
import { Upload, Download, Document, DocumentChecked, Warning, Trophy, UserFilled, Ticket, DataAnalysis, Histogram, Medal, Memo, Money, Calendar, Flag, Files, Reading, Management, FirstAidKit, House, Bell, Delete, DeleteFilled } from '@element-plus/icons-vue'
|
|
131
|
130
|
import { importCombinedLedger, clearLedgerByTimeRange, downloadLedgerTemplate } from '@/api/ledger/index'
|
|
|
131
|
+import { syncLedgerAll } from '@/api/score/index'
|
|
132
|
132
|
import {
|
|
133
|
133
|
importSupervisionProblem,
|
|
134
|
134
|
importPatrolInspection,
|
|
|
@@ -155,6 +155,22 @@ defineOptions({ name: 'LedgerImport' })
|
|
155
|
155
|
const combinedLoading = ref(false)
|
|
156
|
156
|
const combinedResult = ref(null)
|
|
157
|
157
|
|
|
|
158
|
+// ── 台账同步 ──────────────────────────────────────────
|
|
|
159
|
+const syncing = ref(false)
|
|
|
160
|
+
|
|
|
161
|
+async function handleSync() {
|
|
|
162
|
+ syncing.value = true
|
|
|
163
|
+ try {
|
|
|
164
|
+ const r = await syncLedgerAll()
|
|
|
165
|
+ const d = r.data || {}
|
|
|
166
|
+ ElMessage.success(`同步完成:新增 ${d.inserted ?? 0} 条,跳过 ${d.skipped ?? 0} 条`)
|
|
|
167
|
+ } catch (e) {
|
|
|
168
|
+ ElMessage.error('同步失败,请查看后端日志')
|
|
|
169
|
+ } finally {
|
|
|
170
|
+ syncing.value = false
|
|
|
171
|
+ }
|
|
|
172
|
+}
|
|
|
173
|
+
|
|
158
|
174
|
// ── 台账数据清理 ──────────────────────────────────────
|
|
159
|
175
|
const clearBeginDate = ref('')
|
|
160
|
176
|
const clearEndDate = ref('')
|
|
|
@@ -466,12 +482,14 @@ function triggerDownload(blob, fileName) {
|
|
466
|
482
|
|
|
467
|
483
|
.page-header-card {
|
|
468
|
484
|
margin-bottom: 20px;
|
|
|
485
|
+
|
|
469
|
486
|
.page-title {
|
|
470
|
487
|
font-size: 20px;
|
|
471
|
488
|
font-weight: 600;
|
|
472
|
489
|
color: #303133;
|
|
473
|
490
|
margin-bottom: 6px;
|
|
474
|
491
|
}
|
|
|
492
|
+
|
|
475
|
493
|
.page-desc {
|
|
476
|
494
|
font-size: 13px;
|
|
477
|
495
|
color: #909399;
|
|
|
@@ -533,6 +551,11 @@ function triggerDownload(blob, fileName) {
|
|
533
|
551
|
font-size: 14px;
|
|
534
|
552
|
}
|
|
535
|
553
|
|
|
|
554
|
+ .sync-btn {
|
|
|
555
|
+ border-color: #409eff;
|
|
|
556
|
+ color: #409eff;
|
|
|
557
|
+ }
|
|
|
558
|
+
|
|
536
|
559
|
.combined-result {
|
|
537
|
560
|
margin-top: 14px;
|
|
538
|
561
|
padding-top: 14px;
|
|
|
@@ -678,6 +701,7 @@ function triggerDownload(blob, fileName) {
|
|
678
|
701
|
background: #f0f9eb;
|
|
679
|
702
|
color: #67c23a;
|
|
680
|
703
|
}
|
|
|
704
|
+
|
|
681
|
705
|
&.error {
|
|
682
|
706
|
background: #fef0f0;
|
|
683
|
707
|
color: #f56c6c;
|