From 8ff1eb1a834142e3afa71016eb875f5ba4478823 Mon Sep 17 00:00:00 2001 From: lion <120344285@qq.com> Date: Thu, 21 May 2026 15:25:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=B4=E5=83=8F=E6=89=B9=E9=87=8F=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../student/components/batchHeadimgImport.vue | 291 +++++++++++++----- src/views/student/components/editDetail.vue | 10 +- 2 files changed, 214 insertions(+), 87 deletions(-) diff --git a/src/views/student/components/batchHeadimgImport.vue b/src/views/student/components/batchHeadimgImport.vue index d435a48..4e64810 100644 --- a/src/views/student/components/batchHeadimgImport.vue +++ b/src/views/student/components/batchHeadimgImport.vue @@ -4,76 +4,92 @@ title="批量上传头像" width="900px" top="5vh" + custom-class="batch-headimg-dialog" @close="handleClose" > -
-

1. 请先选择目标课程,仅会匹配该课程下的学员。

-

2. 图片文件名需与学员姓名完全一致,如 张三.jpg

-

3. 仅「可更新」状态的记录会被导入;未匹配、重名、无效文件会自动跳过。

-
+
+
+

1. 请先选择目标课程,仅会匹配该课程下的学员。

+

2. 图片文件名需与学员姓名完全一致,如 张三.jpg

+

3. 预览后可勾选需要导入的学员;未匹配、重名、无效文件不可选。

+
+ + + + + + + + - - - +
+ + + +
+
支持 jpg/png 等图片,单张不超过 1MB
+
+ +
+ - - - - - - - -
将图片拖到此处,或点击选择
-
支持 jpg/png 等图片,单张不超过 500KB
-
- -
- + + 可更新 {{ stats.ready }} 条, + 未匹配 {{ stats.unmatched }} 条, + 重名 {{ stats.duplicate }} 条, + 无效 {{ stats.invalid }} 条, + 已选 {{ selectedReadyItems.length }} 条 + +
+ + - 预览匹配 -
- - 可更新 {{ stats.ready }} 条, - 未匹配 {{ stats.unmatched }} 条, - 重名 {{ stats.duplicate }} 条, - 无效 {{ stats.invalid }} 条 - -
- - + @@ -108,16 +124,17 @@ + 取消 - 确认导入({{ readyItems.length }}) + 确认导入({{ selectedReadyItems.length }}) @@ -139,6 +156,7 @@ export default { fileList: [], rawFiles: [], previewList: [], + selectedRows: [], stats: { ready: 0, unmatched: 0, @@ -150,8 +168,8 @@ export default { } }, computed: { - readyItems() { - return this.previewList.filter(item => item.status === 'ready') + selectedReadyItems() { + return this.selectedRows.filter(item => item.status === 'ready') } }, methods: { @@ -169,6 +187,7 @@ export default { this.fileList = [] this.rawFiles = [] this.previewList = [] + this.selectedRows = [] this.stats = { ready: 0, unmatched: 0, duplicate: 0, invalid: 0 } this.previewLoading = false this.importLoading = false @@ -191,20 +210,56 @@ export default { }, handleCourseChange() { this.previewList = [] + this.selectedRows = [] this.stats = { ready: 0, unmatched: 0, duplicate: 0, invalid: 0 } }, handleFileChange(file, fileList) { this.fileList = fileList this.rawFiles = fileList.map(item => item.raw).filter(Boolean) this.previewList = [] + this.selectedRows = [] this.stats = { ready: 0, unmatched: 0, duplicate: 0, invalid: 0 } }, handleFileRemove(file, fileList) { this.fileList = fileList this.rawFiles = fileList.map(item => item.raw).filter(Boolean) this.previewList = [] + this.selectedRows = [] this.stats = { ready: 0, unmatched: 0, duplicate: 0, invalid: 0 } }, + getRowKey(row) { + return `${row.index}_${row.filename}` + }, + rowSelectable(row) { + return row.status === 'ready' + }, + handleSelectionChange(selection) { + this.selectedRows = selection + }, + getSortWeight(item) { + if (item.status === 'unmatched') return 0 + if (item.current_headimgurl) return 1 + if (item.status === 'ready') return 2 + if (item.status === 'duplicate') return 3 + return 4 + }, + sortPreviewList(list) { + return [...list].sort((a, b) => { + const weightDiff = this.getSortWeight(a) - this.getSortWeight(b) + if (weightDiff !== 0) return weightDiff + return String(a.filename).localeCompare(String(b.filename), 'zh-CN') + }) + }, + selectDefaultRows() { + const table = this.$refs.previewTable + if (!table) return + table.clearSelection() + this.previewList.forEach(row => { + if (this.rowSelectable(row)) { + table.toggleRowSelection(row, true) + } + }) + }, statusTagType(status) { const map = { ready: 'success', @@ -224,16 +279,17 @@ export default { return } - const formData = new FormData() - formData.append('course_id', this.courseId) - this.rawFiles.forEach(file => { - formData.append('files[]', file) - }) - this.previewLoading = true try { - const res = await batchHeadimgPreview(formData) - this.previewList = res.list || [] + const res = await batchHeadimgPreview({ + course_id: this.courseId, + files: this.rawFiles.map(file => ({ + filename: file.name, + size: file.size + })) + }) + this.previewList = this.sortPreviewList(res.list || []) + this.selectedRows = [] this.stats = Object.assign({ ready: 0, unmatched: 0, @@ -246,7 +302,12 @@ export default { return } - this.$message.success(`预览完成,可更新 ${this.stats.ready} 条`) + this.$nextTick(() => { + this.selectDefaultRows() + }) + + const total = res.file_total || this.previewList.length + this.$message.success(`预览完成,共 ${total} 张,可更新 ${this.stats.ready} 条,已默认全选可导入项`) } catch (error) { console.error(error) } finally { @@ -275,8 +336,8 @@ export default { return data.url }, async handleImport() { - if (!this.readyItems.length) { - this.$message.warning('没有可导入的数据') + if (!this.selectedReadyItems.length) { + this.$message.warning('请先勾选需要导入的学员') return } @@ -285,7 +346,7 @@ export default { const failedUploads = [] try { - for (const item of this.readyItems) { + for (const item of this.selectedReadyItems) { const file = this.findRawFile(item.filename) if (!file) { failedUploads.push(`${item.filename}:找不到本地文件`) @@ -334,8 +395,14 @@ export default { + + diff --git a/src/views/student/components/editDetail.vue b/src/views/student/components/editDetail.vue index de746dc..1c1f5b1 100644 --- a/src/views/student/components/editDetail.vue +++ b/src/views/student/components/editDetail.vue @@ -33,7 +33,7 @@ :on-remove="uploadHeadimgRemove"> -
支持 jpg/png 格式,大小不超过 500KB
+
支持 jpg/png 格式,大小不超过 1MB
@@ -446,14 +446,14 @@ methods: { beforeHeadimgUpload(file) { const isImage = file.type.includes('image') - const isLt500K = file.size / 1024 <= 500 + const isLt1M = file.size / 1024 / 1024 <= 1 if (!isImage) { this.$message.error('请上传正确的图片格式文件') } - if (!isLt500K) { - this.$message.error('上传文件大小不能超过 500KB') + if (!isLt1M) { + this.$message.error('上传文件大小不能超过 1MB') } - return isImage && isLt500K + return isImage && isLt1M }, onHeadimgExceed() { this.$Message.warning('头像只能上传一张')