| | |
| | | <span>本月导入进度({{ period || '未选择报表期' }})</span> |
| | | <el-button type="text" icon="el-icon-refresh" @click="loadData">刷新</el-button> |
| | | </div> |
| | | <div v-if="period" class="side-danger"> |
| | | <el-button size="mini" type="danger" plain icon="el-icon-delete" |
| | | :disabled="clearing || importing" @click="openClearDialog">清空数据…</el-button> |
| | | <span class="side-danger-tip">按报表期清库,用于整月重导</span> |
| | | </div> |
| | | <div v-if="!period" class="tip">请先在上方选择报表期</div> |
| | | <div v-else class="overview-grid"> |
| | | <div class="ov-row" v-for="g in visibleGroups" :key="g.key"> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-dialog title="清空数据" :visible.sync="clearDialog" width="560px" append-to-body :close-on-click-modal="false"> |
| | | <div class="clear-dlg"> |
| | | <div class="clear-period">报表期:<b>{{ period }}</b></div> |
| | | <el-radio-group v-model="clearScope"> |
| | | <el-radio label="all">清空该报表期全部已导入数据</el-radio> |
| | | <el-radio label="types">只清空指定类型</el-radio> |
| | | </el-radio-group> |
| | | <div v-if="clearScope === 'types'" class="clear-types"> |
| | | <el-select v-model="clearTypes" multiple filterable collapse-tags placeholder="选择要清空的数据类型" style="width:100%"> |
| | | <el-option-group v-for="g in clearableGroups()" :key="g.key" :label="g.name"> |
| | | <el-option v-for="t in g.types" :key="t.value" :value="t.value" |
| | | :label="t.label + '(' + overviewState(t.value).text + ')'"></el-option> |
| | | </el-option-group> |
| | | </el-select> |
| | | <div class="tip" style="margin-top:6px">可多选;未导入的类型没有数据可删。</div> |
| | | </div> |
| | | <div class="clear-warn"> |
| | | 将删除所选范围内该报表期的数据库数据,并同步删除对应审核结果、已审核标记与导入批次记录(投资项目主档保留)。此操作不可撤销,请确认已有备份或准备重新导入。 |
| | | </div> |
| | | </div> |
| | | <span slot="footer"> |
| | | <el-button @click="clearDialog = false">取消</el-button> |
| | | <el-button type="danger" :loading="clearing" |
| | | :disabled="clearScope === 'types' && !clearTypes.length" @click="confirmClear">确认清空</el-button> |
| | | </span> |
| | | </el-dialog> |
| | | </el-main> |
| | | </el-container> |
| | | </el-container> |
| | |
| | | period: (() => { const d = new Date(); return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') })(), |
| | | cityDirLoading: false, |
| | | importing: false, |
| | | clearing: false, |
| | | clearDialog: false, |
| | | clearScope: 'all', |
| | | clearTypes: [], |
| | | sideOpen: false, |
| | | result: '', |
| | | error: '', |
| | |
| | | message: '' |
| | | } |
| | | this.importOne(row).then(() => { |
| | | this.showImportResult(row) |
| | | if ((row.type === 'investment' || row.type === 'investmentLogistics') && row.status === 'success') { |
| | | this.checkInvest(this.period) |
| | | } |
| | |
| | | }) |
| | | .finally(() => { this.cityDirLoading = false }) |
| | | }, |
| | | showImportResult(row) { |
| | | if (!row || !row.status) return |
| | | const msg = (row.message || '').toString() |
| | | if (row.status === 'success') { |
| | | const text = (msg && msg.indexOf('导入') !== -1) ? msg : '数据导入成功' |
| | | this.$message({ message: text, type: 'success', duration: 5000 }) |
| | | } else { |
| | | this.$alert((msg || '数据导入失败,详见下方失败记录').replace(/\n/g, '<br>'), '数据导入失败', { |
| | | dangerouslyUseHTMLString: true, |
| | | type: 'error', |
| | | confirmButtonText: '知道了' |
| | | }) |
| | | } |
| | | }, |
| | | importOne(row) { |
| | | if (!this.period) { this.$message.warning('请先选择报表期'); return Promise.resolve() } |
| | | row.status = 'uploading' |
| | |
| | | }) |
| | | .catch(e => { if (!e || !e._toast) this.$message.error('导入记录加载失败,请刷新重试') }) |
| | | .finally(() => { this.batchLoading = false }) |
| | | }, |
| | | openClearDialog() { |
| | | if (!this.period) { this.$message.warning('请先选择报表期'); return } |
| | | if (this.importing) { this.$message.warning('正在导入数据,请等待导入完成后再清空'); return } |
| | | this.clearScope = 'all' |
| | | this.clearTypes = [] |
| | | this.clearDialog = true |
| | | }, |
| | | clearableGroups() { |
| | | return this.groups.filter(g => !g.hidden) |
| | | }, |
| | | confirmClear() { |
| | | if (!this.period) { this.$message.warning('请先选择报表期'); return } |
| | | if (this.clearing) return |
| | | if (this.clearScope === 'types' && !this.clearTypes.length) { this.$message.warning('请选择要清空的数据类型'); return } |
| | | const scopeText = this.clearScope === 'all' |
| | | ? '该报表期全部已导入数据' |
| | | : '以下 ' + this.clearTypes.length + ' 个类型:' + this.clearTypes.map(t => this.typeLabel(t)).join('、') |
| | | this.$confirm('将清空 ' + this.period + ' 的' + scopeText + ',并同步删除对应审核结果、已审核标记与导入批次记录。此操作不可撤销,是否继续?', |
| | | '清空确认', { type: 'warning', confirmButtonText: '确认清空', cancelButtonText: '取消' }) |
| | | .then(() => { |
| | | this.clearing = true |
| | | const params = { period: this.period } |
| | | if (this.clearScope === 'types') params.types = this.clearTypes.join(',') |
| | | return api.post('/import/clear', null, { params, timeout: 600000 }) |
| | | .then(res => { |
| | | const d = (res && res.data) || {} |
| | | this.$message.success('已清空 ' + this.period + ' 数据:业务数据 ' + (d.dataRows || 0) + |
| | | ' 行、审核结果 ' + (d.auditRows || 0) + ' 行、导入批次 ' + (d.batchRows || 0) + ' 条,可以重新导入') |
| | | this.clearDialog = false |
| | | this.loadData() |
| | | }) |
| | | .catch(e => { |
| | | if (e && e._toast) return |
| | | this.$message.error((e.response && e.response.data && e.response.data.message) || '清空失败,请稍后重试') |
| | | }) |
| | | .finally(() => { this.clearing = false }) |
| | | }).catch(() => {}) |
| | | }, |
| | | batchKeyToType(k) { |
| | | if (BATCH_TYPE_MAP[k]) return BATCH_TYPE_MAP[k] |
| | |
| | | .import-side.side-open .side-toggle-text { writing-mode: horizontal-tb; letter-spacing: normal; margin-top: 0; } |
| | | .side-content { padding: 8px 12px 12px; max-height: calc(100vh - 220px); overflow-y: auto; overscroll-behavior: contain; } |
| | | .side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-weight: 600; margin-bottom: 6px; } |
| | | .side-danger { display: flex; align-items: center; gap: 8px; margin: 4px 0 10px; padding: 6px 8px; background: #FEF0F0; border: 1px solid #FDE2E2; border-radius: 4px; } |
| | | .side-danger-tip { font-size: 12px; color: #F56C6C; line-height: 1.3; } |
| | | .clear-dlg { line-height: 1.7; } |
| | | .clear-period { margin-bottom: 6px; } |
| | | .clear-types { margin-top: 10px; } |
| | | .clear-warn { margin-top: 12px; padding: 8px 10px; background: #FEF0F0; border: 1px solid #FDE2E2; border-radius: 4px; color: #F56C6C; font-size: 12px; line-height: 1.6; } |
| | | .import-side .overview-grid { display: block; } |
| | | .import-side .ov-row { display: block; margin-bottom: 6px; } |
| | | .import-side .ov-group { width: auto; } |