forked from liweijie/education
教学大纲新增导出模板和导入按钮
This commit is contained in:
@@ -66,3 +66,25 @@ export function exportSyllabus(query) {
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 下载教学大纲导入模板(数据 sheet + 填写说明 sheet)
|
||||
export function downloadSyllabusTemplate() {
|
||||
return request({
|
||||
url: '/zyjxjhb/template',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
// 导入教学大纲 Excel,返回 { insertCount, skipCount, failCount, skipList, failList, message }
|
||||
export function importSyllabus(file) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
return request({
|
||||
url: '/zyjxjhb/import',
|
||||
method: 'post',
|
||||
data: formData,
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
timeout: 60000
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
@click="handleBatchDelete"
|
||||
>停用所选</el-button>
|
||||
<el-button icon="el-icon-download" @click="handleDownload">下载</el-button>
|
||||
<el-button icon="el-icon-download" @click="handleDownloadTemplate">下载模板</el-button>
|
||||
<el-button icon="el-icon-upload2" @click="openImportDialog">导入</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="pagedData" border stripe highlight-current-row
|
||||
@@ -287,6 +289,52 @@
|
||||
<el-button type="primary" :loading="dialog.submitting" @click="submitDialog">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 模板导入弹窗 -->
|
||||
<el-dialog title="教学大纲导入" :visible.sync="importDialog.visible" width="660px" append-to-body
|
||||
:close-on-click-modal="false">
|
||||
<el-alert type="info" :closable="false" show-icon class="import-tip"
|
||||
title="请先下载导入模板,按「专业教学计划」sheet 列填写后再上传;「专业代号+课编号+学期第次」已存在的行将跳过。" />
|
||||
<el-form label-width="110px" class="import-form">
|
||||
<el-form-item label="导入模板">
|
||||
<el-button icon="el-icon-download" :loading="importDialog.downloading" @click="handleDownloadTemplate">
|
||||
下载导入模板
|
||||
</el-button>
|
||||
<span class="tip-text">红色表头列为必填,详见模板「填写说明」sheet</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="数据文件">
|
||||
<div class="file-input">
|
||||
<input ref="importFileInput" type="file" accept=".xls,.xlsx" style="display: none"
|
||||
@change="handleImportFileChange" />
|
||||
<el-button icon="el-icon-folder-opened" @click="handleChooseFile">选择文件</el-button>
|
||||
<span class="file-name">{{ importDialog.fileName || '未选择任何文件' }}</span>
|
||||
<el-button v-if="importDialog.file" type="text" class="danger-text-btn" @click="clearImportFile">
|
||||
清除
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="导入结果" v-if="importDialog.result">
|
||||
<div class="import-result">
|
||||
共导入 <span class="num">{{ importDialog.result.insertCount }}</span> 条<template
|
||||
v-if="importDialog.result.skipCount > 0">,跳过 <span
|
||||
class="num warn">{{ importDialog.result.skipCount }}</span> 条(数据已存在)</template><template
|
||||
v-if="importDialog.result.failCount > 0">,失败 <span
|
||||
class="num warn">{{ importDialog.result.failCount }}</span> 条</template>。
|
||||
<div v-if="importDialog.result.failList.length" class="skip-detail">
|
||||
<div v-for="(item, idx) in importDialog.result.failList" :key="'f' + idx">{{ item }}</div>
|
||||
</div>
|
||||
<div v-if="importDialog.result.skipList.length" class="skip-detail">
|
||||
<div v-for="(item, idx) in importDialog.result.skipList" :key="'s' + idx">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="importDialog.visible = false">关 闭</el-button>
|
||||
<el-button type="primary" :loading="importDialog.importing" :disabled="!importDialog.file"
|
||||
@click="handleImport">开始导入</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -297,7 +345,9 @@ import {
|
||||
batchDeleteSyllabus,
|
||||
updateSyllabus,
|
||||
listByZydhAndTy,
|
||||
exportSyllabus
|
||||
exportSyllabus,
|
||||
downloadSyllabusTemplate,
|
||||
importSyllabus
|
||||
} from '@/api/teachBusiness/syllabus'
|
||||
import { listMajor } from '@/api/subjectMajor/major'
|
||||
import { listKb } from '@/api/teachOffice/kb'
|
||||
@@ -334,6 +384,14 @@ export default {
|
||||
submitting: false,
|
||||
form: this.createEmptyForm()
|
||||
},
|
||||
importDialog: {
|
||||
visible: false,
|
||||
downloading: false,
|
||||
importing: false,
|
||||
file: null,
|
||||
fileName: '',
|
||||
result: null
|
||||
},
|
||||
rules: {
|
||||
zydh: [{ required: true, message: '请选择专业', trigger: 'change' }],
|
||||
kbh: [{ required: true, message: '请选择课程', trigger: 'change' }],
|
||||
@@ -524,6 +582,76 @@ export default {
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
/* ---------- 模板导入 ---------- */
|
||||
openImportDialog() {
|
||||
this.importDialog.file = null
|
||||
this.importDialog.fileName = ''
|
||||
this.importDialog.result = null
|
||||
this.importDialog.visible = true
|
||||
if (this.$refs.importFileInput) this.$refs.importFileInput.value = ''
|
||||
},
|
||||
handleDownloadTemplate() {
|
||||
this.importDialog.downloading = true
|
||||
downloadSyllabusTemplate().then(blob => {
|
||||
saveAs(blob, '教学大纲导入模板.xlsx')
|
||||
this.$message.success('模板下载成功')
|
||||
}).catch(() => {}).finally(() => {
|
||||
this.importDialog.downloading = false
|
||||
})
|
||||
},
|
||||
handleChooseFile() {
|
||||
if (this.$refs.importFileInput) this.$refs.importFileInput.click()
|
||||
},
|
||||
handleImportFileChange(e) {
|
||||
const input = e.target
|
||||
this.importDialog.result = null
|
||||
if (!input.files || input.files.length === 0) {
|
||||
this.importDialog.file = null
|
||||
this.importDialog.fileName = ''
|
||||
return
|
||||
}
|
||||
const file = input.files[0]
|
||||
const name = (file.name || '').toLowerCase()
|
||||
if (!name.endsWith('.xls') && !name.endsWith('.xlsx')) {
|
||||
this.$message.warning('仅支持 .xls / .xlsx 格式的 Excel 文件')
|
||||
this.clearImportFile()
|
||||
input.value = ''
|
||||
return
|
||||
}
|
||||
this.importDialog.file = file
|
||||
this.importDialog.fileName = file.name
|
||||
},
|
||||
clearImportFile() {
|
||||
this.importDialog.file = null
|
||||
this.importDialog.fileName = ''
|
||||
this.importDialog.result = null
|
||||
if (this.$refs.importFileInput) this.$refs.importFileInput.value = ''
|
||||
},
|
||||
handleImport() {
|
||||
if (!this.importDialog.file) {
|
||||
this.$message.warning('请先选择文件')
|
||||
return
|
||||
}
|
||||
this.importDialog.importing = true
|
||||
importSyllabus(this.importDialog.file).then(response => {
|
||||
const data = (response && response.data) || {}
|
||||
this.importDialog.file = null
|
||||
this.importDialog.fileName = ''
|
||||
if (this.$refs.importFileInput) this.$refs.importFileInput.value = ''
|
||||
this.importDialog.result = {
|
||||
insertCount: data.insertCount || 0,
|
||||
skipCount: data.skipCount || 0,
|
||||
failCount: data.failCount || 0,
|
||||
skipList: data.skipList || [],
|
||||
failList: data.failList || []
|
||||
}
|
||||
this.$message.success(data.message || '导入完成')
|
||||
this.fetchList()
|
||||
}).catch(() => {}).finally(() => {
|
||||
this.importDialog.importing = false
|
||||
})
|
||||
},
|
||||
|
||||
/* ---------- 分页 ---------- */
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size
|
||||
@@ -629,4 +757,51 @@ export default {
|
||||
color: #f78989;
|
||||
}
|
||||
}
|
||||
|
||||
.import-tip {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
margin-left: 10px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.file-name {
|
||||
margin-left: 10px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
}
|
||||
|
||||
.import-result {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
|
||||
.num {
|
||||
font-weight: 600;
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.num.warn {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.skip-detail {
|
||||
margin-top: 8px;
|
||||
max-height: 180px;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
line-height: 1.8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user