| | |
| | | <el-input v-model="form.phone" placeholder="请输入联系电话" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="密码" prop="password"> |
| | | <div style="display: flex; align-items: center; gap: 10px;"> |
| | | <el-input |
| | | v-model="form.password" |
| | | type="password" |
| | | :placeholder="isEdit ? '请输入新密码(6-20位,包含字母和数字)' : '请输入登录密码(6-20位,包含字母和数字)'" |
| | | maxlength="20" |
| | | @focus="handlePasswordFocus" |
| | | @input="handlePasswordInput" |
| | | style="flex: 1;" |
| | | /> |
| | | <el-button |
| | | v-if="isEdit" |
| | | type="primary" |
| | | size="small" |
| | | @click="handleResetPassword" |
| | | > |
| | | 重置密码 |
| | | </el-button> |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="性别" prop="gender"> |
| | | <el-radio-group v-model="form.gender"> |
| | | <el-radio :value="1">男</el-radio> |
| | |
| | | import { getMediasByTarget, deleteMedia, uploadFile } from '@/api/media' |
| | | import type { Judge, JudgeInput, Tag } from '@/api/graphql' |
| | | import type { Media } from '@/api/media' |
| | | import { MediaTargetType } from '@/constants/mediaTargetType' |
| | | |
| | | interface Props { |
| | | modelValue: boolean |
| | |
| | | // 是否为编辑模式 |
| | | const isEdit = computed(() => !!props.judgeData?.id) |
| | | |
| | | |
| | | |
| | | // 表单数据 |
| | | const form = reactive<JudgeInput & { |
| | | avatarUrl?: string; |
| | |
| | | id: undefined, |
| | | name: '', |
| | | phone: '', |
| | | password: '', |
| | | gender: undefined, |
| | | description: '', |
| | | specialtyIds: [], |
| | |
| | | // 可选的专业标签(从后端获取) |
| | | const availableTags = ref<Tag[]>([]) |
| | | |
| | | // 跟踪密码是否被修改 |
| | | const isPasswordModified = ref(false) |
| | | |
| | | // 表单验证规则 |
| | | const rules = { |
| | | name: [ |
| | |
| | | phone: [ |
| | | { required: true, message: '请输入联系电话', trigger: 'blur' }, |
| | | { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' } |
| | | ], |
| | | password: [ |
| | | { |
| | | validator: (rule: any, value: string, callback: any) => { |
| | | // 编辑模式下,如果是占位符密码且未修改,则跳过验证 |
| | | if (isEdit.value && value === '••••••••' && !isPasswordModified.value) { |
| | | callback() |
| | | return |
| | | } |
| | | |
| | | if (!value || value.trim() === '') { |
| | | callback(new Error('请输入登录密码')) |
| | | } else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*?&]{6,}$/.test(value)) { |
| | | callback(new Error('密码至少6个字符,必须包含字母和数字')) |
| | | } else { |
| | | callback() |
| | | } |
| | | }, |
| | | trigger: 'blur' |
| | | } |
| | | ] |
| | | } |
| | | |
| | | // 监听评委数据变化,填充表单 |
| | | watch(() => props.judgeData, (data) => { |
| | | console.log('🔍 Watch triggered, judgeData:', data) |
| | | console.log('🔍 isEdit computed:', isEdit.value) |
| | | nextTick(async () => { |
| | | if (data && data.id) { |
| | | // 编辑模式:填充表单数据 |
| | | form.id = data.id |
| | | form.name = data.name || '' |
| | | form.phone = data.phone || '' |
| | | form.password = '' // 编辑模式下清空密码字段,用户需要输入新密码或点击重置密码 |
| | | isPasswordModified.value = false |
| | | form.gender = data.gender |
| | | form.description = data.description || '' |
| | | form.specialtyIds = data.specialties?.map(tag => tag.id) || [] |
| | |
| | | |
| | | // 加载评委头像/媒体(targetType=1 表示评委) |
| | | try { |
| | | console.log('=== 加载评委媒体 ==='); |
| | | console.log('评委ID:', data.id); |
| | | const medias = await getMediasByTarget(1, parseInt(data.id)) |
| | | console.log('获取到的媒体列表:', medias); |
| | | const medias = await getMediasByTarget(MediaTargetType.JUDGE_AVATAR, parseInt(data.id)) |
| | | |
| | | // 只取第一个图片作为头像(评委只能有一个头像) |
| | | const firstImage = (medias || []).find((m: Media) => { |
| | |
| | | url: firstImage.fullUrl |
| | | }; |
| | | form.avatarUrl = firstImage.fullUrl; |
| | | console.log('设置当前头像:', form.currentAvatar); |
| | | } else { |
| | | form.currentAvatar = null; |
| | | } |
| | |
| | | form.id = undefined |
| | | form.name = '' |
| | | form.phone = '' |
| | | form.password = '' |
| | | form.gender = undefined |
| | | form.description = '' |
| | | form.specialtyIds = [] |
| | | form.avatarUrl = '' |
| | | form.avatarMediaId = undefined |
| | | form.currentAvatar = null |
| | | isPasswordModified.value = false |
| | | |
| | | nextTick(() => { |
| | | formRef.value?.clearValidate() |
| | | }) |
| | | } |
| | | |
| | | // 处理密码字段焦点事件 |
| | | const handlePasswordFocus = () => { |
| | | if (isEdit.value && form.password === '••••••••') { |
| | | form.password = '' |
| | | } |
| | | } |
| | | |
| | | // 处理密码输入事件 |
| | | const handlePasswordInput = (value: string) => { |
| | | if (isEdit.value) { |
| | | isPasswordModified.value = value !== '' && value !== '••••••••' |
| | | } |
| | | } |
| | | |
| | | // 处理重置密码 |
| | | const handleResetPassword = () => { |
| | | form.password = '' |
| | | isPasswordModified.value = true |
| | | ElMessage.success('密码已清空,请输入新密码') |
| | | } |
| | | |
| | | // 处理头像上传 |
| | |
| | | return; // 没有新头像需要上传 |
| | | } |
| | | |
| | | console.log('=== 开始上传头像文件 ==='); |
| | | console.log('评委ID:', judgeId); |
| | | console.log('待上传的头像:', form.currentAvatar.name); |
| | | |
| | | try { |
| | | // 上传文件 |
| | | const uploadResult = await uploadFile(form.currentAvatar.file!); |
| | | console.log('上传结果:', uploadResult); |
| | | |
| | | if (uploadResult.success) { |
| | | // 保存媒体信息到数据库 |
| | |
| | | fileSize: uploadResult.fileSize, |
| | | fileExt: uploadResult.fileName.split('.').pop() || 'jpg', |
| | | mediaType: 1, // 1表示图片 |
| | | targetType: 1, // 1表示评委 |
| | | targetType: MediaTargetType.JUDGE_AVATAR, // 评委头像 |
| | | targetId: parseInt(judgeId) |
| | | }); |
| | | |
| | |
| | | form.currentAvatar.uploaded = true; |
| | | form.currentAvatar.url = uploadResult.fullUrl; |
| | | form.avatarUrl = uploadResult.fullUrl; |
| | | console.log('头像上传并保存成功:', form.currentAvatar.name); |
| | | } |
| | | } catch (error) { |
| | | console.error('头像上传失败:', error); |
| | |
| | | |
| | | if (form.currentAvatar.isExisting && form.currentAvatar.id) { |
| | | // 删除已存在的头像文件 |
| | | console.log('删除已存在的头像文件:', form.currentAvatar.id); |
| | | const result = await deleteMedia(form.currentAvatar.id); |
| | | console.log('删除结果:', result); |
| | | |
| | | if (result) { |
| | | form.currentAvatar = null; |
| | |
| | | majorIds: form.specialtyIds?.length ? form.specialtyIds.map(id => parseInt(id)) : undefined |
| | | } |
| | | |
| | | // 只有在新建或密码被修改时才包含密码字段 |
| | | if (!isEdit.value || isPasswordModified.value) { |
| | | submitData.password = form.password |
| | | } |
| | | |
| | | const savedJudge = await JudgeApi.saveJudge(submitData) |
| | | console.log('评委保存成功:', savedJudge); |
| | | |
| | | // 2. 上传新选择的头像文件 |
| | | if (savedJudge.id) { |
| | |
| | | if (form.currentAvatar?.isExisting && form.currentAvatar.id) { |
| | | try { |
| | | await deleteMedia(form.currentAvatar.id); |
| | | console.log('已删除旧头像'); |
| | | } catch (error) { |
| | | console.warn('删除旧头像失败,继续上传新头像:', error); |
| | | } |