批量上传人脸:只上传头像、下发到人脸服务;不授权门锁;

This commit is contained in:
buliping committed 2026-11-13 13:50:57 +08:00
1 parent 6d2ad20723
commit e683d4da59
29 files changed
+4257 -101

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
import request from '@/utils/request'
// 批量上传头像压缩包(内部文件名:手机号.png),按手机号匹配本班人员写入 avatar
export function uploadAvatarZip(planId, data) {
return request({
url: '/train/batch-auth/avatar-zip',
method: 'post',
params: { planId },
data: data,
headers: { 'Content-Type': 'multipart/form-data' },
timeout: 120000
})
}
// 查询本班「已有头像但门锁未授权」的候选人员
export function listAuthCandidates(planId) {
return request({
url: '/train/batch-auth/candidates',
method: 'get',
params: { planId }
})
}
// 提交批量授权任务(后台异步执行,逐人通过门禁入住 checkin 接口下发,接口立即返回受理结果)
export function authorizeBatch(planId, studentIds) {
return request({
url: '/train/batch-auth/authorize',
method: 'post',
data: { planId: planId, studentIds: studentIds }
})
}
+24
View File
@@ -30,6 +30,30 @@ export function importPlanEnrollments(planId, data) {
})
}
// 3.3.1 学员批量导入预检(10 列学员模板,仅解析校验不落库)
export function precheckEnrollmentImport(planId, data) {
return request({
url: `/train/plans/${planId}/enrollments/import/precheck`,
method: 'post',
data: data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 3.3.2 学员批量导入(10 列学员模板,逐行独立事务)
export function importEnrollmentsV2(planId, data) {
return request({
url: `/train/plans/${planId}/enrollments/import`,
method: 'post',
data: data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 3.4 获取参训档案详情 【P0】
export function getEnrollmentDetail(enrollmentId) {
return request({
+9
View File
@@ -35,6 +35,15 @@ export function updateStudent(data) {
})
}
// 仅修改学员头像(avatar 传空串表示移除头像,仅更新 train_student.avatar)
export function updateStudentAvatar(sId, avatar) {
return request({
url: '/train/student/' + sId + '/avatar',
method: 'put',
data: { avatar: avatar || '' }
})
}
// 生成唯一学号(AA + 6位数字)
export function genPersonNo() {
return request({
File diff suppressed because it is too large. Load diff
+24 -2
View File
@@ -253,6 +253,13 @@
<div class="avatar-edit-actions">
<el-button size="mini" type="primary" icon="el-icon-picture" @click="handleSelectAvatar">选择图片</el-button>
<el-button size="mini" icon="el-icon-camera" :loading="cameraStarting" @click="openCamera">拍照</el-button>
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
:disabled="!createForm.avatar"
@click="handleRemoveAvatar"
>移除头像</el-button>
</div>
</div>
</el-form-item>
@@ -627,7 +634,7 @@
<script>
import request from '@/utils/request'
import { addStudent, getStudent, listStudent, delStudent, getStudentBindableUsers, bindStudentUser, unbindStudentUser, updateStudent, genPersonNo, importStudentData } from '@/api/train/student'
import { addStudent, getStudent, listStudent, delStudent, getStudentBindableUsers, bindStudentUser, unbindStudentUser, updateStudent, updateStudentAvatar, genPersonNo, importStudentData } from '@/api/train/student'
import {deptTreeSelect} from "@/api/system/user";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
@@ -1419,6 +1426,18 @@ export default {
this.$refs.createForm.clearValidate('avatar')
}
},
/**
* 移除头像:表单与预览同时置空,头像组件回落默认占位图。
* 修改模式下提交时会单独调用「仅更新头像」接口清空库内 avatar
* (通用更新接口会把空串归一为 null 而跳过该字段)。
*/
handleRemoveAvatar() {
this.$set(this.createForm, 'avatar', '')
this.user = { avatar: '' }
if (this.$refs.createForm) {
this.$refs.createForm.clearValidate('avatar')
}
},
// 头像地址解析:补全 baseApi,空值使用专业学员工装默认头像
avatarUrl(avatar) {
return getStudentAvatar(avatar)
@@ -1452,8 +1471,11 @@ export default {
}
this.submitting = true
const payload = Object.assign({}, this.createForm)
// 修改模式下头像已被移除:通用更新接口会把空串归一为 null 并跳过 avatar,
// 故在更新成功后调用「仅更新头像」接口显式清空(与班级名单页移除头像行为一致)
const avatarRemoved = payload.sId != null && !payload.avatar
const submitReq = payload.sId != null
? updateStudent(payload)
? updateStudent(payload).then(res => (avatarRemoved ? updateStudentAvatar(payload.sId, '') : res))
: addStudent(payload)
submitReq.then(() => {
this.$modal.msgSuccess(payload.sId != null ? '修改成功' : '新增成功')
@@ -289,6 +289,13 @@
<div class="avatar-edit-actions">
<el-button size="mini" type="primary" icon="el-icon-picture" @click="handleSelectAvatar">选择图片</el-button>
<el-button size="mini" icon="el-icon-camera" :loading="cameraStarting" @click="openCamera">拍照</el-button>
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
:disabled="!form.avatar"
@click="handleRemoveAvatar"
>移除头像</el-button>
</div>
</div>
</el-form-item>
@@ -1027,6 +1034,19 @@ export default {
this.$refs.form.clearValidate('avatar')
}
},
/**
* 移除头像:表单与预览同时置空,头像组件回落默认占位图。
* 提交时 form.avatar 传空串,教师更新接口的动态 SQL 对空串会写入 avatar = ''(对 null 才跳过),
* 因此无需额外接口即可完成清空。
*/
handleRemoveAvatar() {
this.$set(this.form, 'avatar', '')
// 替换对象以触发头像组件的 watch,预览回落默认占位图
this.user = Object.assign({}, this.user, { avatar: '' })
if (this.$refs.form) {
this.$refs.form.clearValidate('avatar')
}
},
/** 头像地址解析:补全 baseApi,空值使用专业讲师默认头像 */
avatarUrl(avatar) {
return getTeacherAvatar(avatar)