This commit is contained in:
李旭明 committed 2025-08-27 22:30:18 +08:00
1 parent 6c90a8e173
commit 64886ba214
26 files changed
+652 -198

No files matched your search

+10
View File
@@ -139,6 +139,11 @@ export interface StglActivityVO {
*/
needApproval?: number;
/**
* 活动面向群体(0-无限制 1-本组织成员)
*/
activityRange?: number;
/**
* 活动状态
*/
@@ -366,6 +371,11 @@ export interface StglActivityForm {
*/
needApproval?: number;
/**
* 活动面向群体(0-无限制 1-本组织成员)
*/
activityRange?: number;
/**
* 活动状态
*/
@@ -135,6 +135,11 @@ export interface StglActivityVo {
*/
needApproval: number;
/**
* 活动面向群体(0-无限制 1-本组织成员)
*/
activityRange: number;
/**
* 活动状态
*/
+10
View File
@@ -259,6 +259,16 @@ export interface ActivityDetailVO {
* 指导老师电话
*/
advisorPhone: string;
/**
* 报名类型
*/
registrationType: string;
/**
* 取得成绩
*/
score: string;
}
/**
@@ -212,6 +212,17 @@
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<div class="detail-item">
<label class="detail-label">报名范围</label>
<div class="detail-value">
<dict-tag :options="stgl_activity_range" :value="activity.activityRange" />
</div>
</div>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<div class="detail-item">
@@ -362,8 +373,8 @@ interface Props {
const props = defineProps<Props>();
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_registration_status, sys_yes_no } = toRefs<any>(
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'sys_yes_no')
const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_registration_status, stgl_activity_range, sys_yes_no } = toRefs<any>(
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'stgl_activity_range', 'sys_yes_no')
);
@@ -471,11 +482,13 @@ const downloadAttachment = (file: any) => {
}
};
// 监听props变化,重新加载附件信息
// 监听props变化,重新加载附件信息并重置activeTab
watch(
() => props.activity,
(newActivity) => {
if (newActivity && newActivity.id) {
// 重置为基本信息标签页,避免显示上次查看的标签页
activeTab.value = 'basic';
loadAttachments();
}
},
@@ -324,7 +324,7 @@
</template>
<script setup lang="ts">
import { getCurrentInstance, onMounted, reactive, ref, toRefs } from 'vue';
import { getCurrentInstance, onMounted, reactive, ref, toRefs, watch } from 'vue';
import {
listActivityRegister,
getActivityRegister,
@@ -500,9 +500,38 @@ const getList = async () => {
}
console.log('ActivityRegistrationView: getList 开始查询,参数:', queryData);
console.log('ActivityRegistrationView: props.activityId:', props.activityId);
const res = await listActivityRegister(queryData);
console.log('ActivityRegistrationView: 查询结果:', res);
console.log('ActivityRegistrationView: 查询结果完整对象:', res);
console.log('ActivityRegistrationView: res 的类型:', typeof res);
console.log('ActivityRegistrationView: res.data:', res.data);
console.log('ActivityRegistrationView: res.rows:', res.rows);
console.log('ActivityRegistrationView: res.rows 的类型:', typeof res.rows);
console.log('ActivityRegistrationView: res.total:', res.total);
console.log('ActivityRegistrationView: res 的所有属性:', Object.keys(res || {}));
// 检查 res.rows 是否存在且为数组
if (!res || !res.rows) {
console.error('ActivityRegistrationView: API返回数据异常 - res.rows 不存在');
console.error('ActivityRegistrationView: 完整响应:', JSON.stringify(res, null, 2));
proxy?.$modal.msgError('API返回数据格式异常,请检查控制台日志');
memberList.value = [];
total.value = 0;
return;
}
if (!Array.isArray(res.rows)) {
console.error('ActivityRegistrationView: API返回数据异常 - res.rows 不是数组');
console.error('ActivityRegistrationView: res.rows 实际值:', res.rows);
console.error('ActivityRegistrationView: res.rows 类型:', typeof res.rows);
proxy?.$modal.msgError('API返回数据格式异常 - rows字段不是数组');
memberList.value = [];
total.value = 0;
return;
}
console.log('ActivityRegistrationView: res.rows 数组长度:', res.rows.length);
// 为每个成员添加签到信息
const membersWithSignInfo = await Promise.all(
@@ -548,9 +577,36 @@ const getList = async () => {
memberList.value = membersWithSignInfo;
total.value = res.total;
} catch (error) {
} catch (error: any) {
console.error('ActivityRegistrationView: 查询成员列表失败:', error);
proxy?.$modal.msgError('查询成员列表失败');
console.error('ActivityRegistrationView: 错误详细信息:', {
message: error?.message,
stack: error?.stack,
response: error?.response,
request: error?.request,
config: error?.config
});
// 检查是否是网络错误
if (error?.code === 'NETWORK_ERROR' || error?.code === 'ECONNABORTED') {
proxy?.$modal.msgError('网络连接失败,请检查网络状态');
} else if (error?.response) {
// 服务器返回了错误响应
console.error('ActivityRegistrationView: 服务器响应错误:', error.response.data);
console.error('ActivityRegistrationView: HTTP状态码:', error.response.status);
proxy?.$modal.msgError(`服务器错误: ${error.response.status} - ${error.response.data?.msg || '未知错误'}`);
} else if (error?.request) {
// 请求发出但没有收到响应
console.error('ActivityRegistrationView: 请求超时或无响应');
proxy?.$modal.msgError('请求超时,请稍后重试');
} else {
// 其他错误(如代码逻辑错误)
proxy?.$modal.msgError(`查询成员列表失败: ${error?.message || '未知错误'}`);
}
// 确保在错误情况下清空数据
memberList.value = [];
total.value = 0;
} finally {
loading.value = false;
}
@@ -795,13 +851,31 @@ const handleFileSuccess = (response: any) => {
}
};
// 监听activityId变化,重新获取数据
watch(
() => props.activityId,
(newActivityId) => {
if (newActivityId) {
console.log('ActivityRegistrationView: activityId changed to:', newActivityId);
// 更新查询参数中的activityId
queryParams.value.activityId = newActivityId;
// 重新获取数据
getList();
}
},
{ immediate: true }
);
// 暴露给父组件的方法
defineExpose({
getList
});
onMounted(() => {
getList();
// 组件挂载时如果有activityId则获取数据(immediate: true的watch会处理这个情况)
if (props.activityId) {
getList();
}
});
</script>
@@ -85,12 +85,12 @@
<span>{{ parseTime(scope.row.registrationTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="成绩" align="center" prop="score" width="80">
<el-table-column label="成绩" align="center" prop="score" width="120" show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row.score || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width" fixed="right">
<el-table-column label="操作" align="center" width="220" class-name="small-padding fixed-width" fixed="right">
<template #default="scope">
<el-tooltip content="查看" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['stgl:activityRegister:query']"></el-button>
@@ -98,6 +98,20 @@
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['stgl:activityRegister:edit']"></el-button>
</el-tooltip>
<!-- 审核通过状态显示成绩录入按钮 -->
<template v-if="Number(scope.row.approvalStatus) === 1">
<el-tooltip content="录入成绩" placement="top">
<el-button
link
type="warning"
icon="Edit"
@click="handleRecordScore(scope.row)"
v-hasPermi="['stgl:activityRegister:recordScore']"
></el-button>
</el-tooltip>
</template>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['stgl:activityRegister:remove']"></el-button>
</el-tooltip>
@@ -247,6 +261,28 @@
</template>
</el-dialog>
<!-- 成绩录入对话框 -->
<el-dialog title="录入成绩" v-model="scoreDialog.visible" width="500px" append-to-body>
<el-form ref="scoreFormRef" :model="scoreForm" :rules="scoreRules" label-width="80px">
<!-- 根据报名类型显示不同的标签 -->
<el-form-item :label="scoreForm.registrationType === '2' ? '团队名称' : '学生姓名'">
<span>{{ scoreForm.registrationType === '2' ? scoreForm.teamName : scoreForm.studentName }}</span>
</el-form-item>
<el-form-item label="活动名称">
<span>{{ props.activityName }}</span>
</el-form-item>
<el-form-item label="成绩" prop="score">
<el-input v-model="scoreForm.score" placeholder="请输入成绩" clearable />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitScore" :loading="scoreButtonLoading">确 定</el-button>
<el-button @click="cancelScore">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 导入对话框 -->
<el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body>
<el-upload
@@ -292,7 +328,8 @@ import {
delActivityRegister,
addActivityRegister,
updateActivityRegister,
exportActivityRegister
exportActivityRegister,
recordActivityScore
} from '@/api/stgl/activityregister';
import { StglActivityRegistrationVo, StglActivityRegistrationForm, StglActivityRegistrationQuery } from '@/api/stgl/activityregister/types';
import { getTeamsByActivityId } from '@/api/stgl/activityteaminfo';
@@ -357,6 +394,7 @@ const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const memberFormRef = ref<ElFormInstance>();
const scoreFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
@@ -368,6 +406,11 @@ const viewDialog = reactive<DialogOption>({
title: ''
});
const scoreDialog = reactive<DialogOption>({
visible: false,
title: ''
});
const viewForm = reactive<ExtendedStglActivityRegistrationVo>({
id: undefined,
activityId: undefined,
@@ -402,6 +445,21 @@ const teamInfo = ref<StglActivityTeamInfoVo | null>(null);
const teamMembers = ref<TeamMemberInfo[]>([]);
const loadingTeamInfo = ref(false);
// 成绩录入相关数据
const scoreButtonLoading = ref(false);
const scoreForm = reactive({
id: undefined as string | number | undefined,
studentName: '',
activityName: '',
score: '',
registrationType: '',
teamName: ''
});
const scoreRules = {
score: [{ required: true, message: '请输入成绩', trigger: 'blur' }]
};
const initFormData: ExtendedActivityRegisterForm = {
id: undefined,
activityId: props.activityId,
@@ -955,6 +1013,48 @@ const handleFileSuccess = (response: any) => {
}
};
/** 录入成绩按钮操作 */
const handleRecordScore = (row: ExtendedStglActivityRegistrationVo) => {
scoreForm.id = row.id;
scoreForm.studentName = row.studentName;
scoreForm.activityName = props.activityName;
scoreForm.score = row.score || '';
scoreForm.registrationType = row.registrationType?.toString() || '';
scoreForm.teamName = row.teamName || '';
scoreDialog.visible = true;
};
/** 提交成绩录入 */
const submitScore = () => {
scoreFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
scoreButtonLoading.value = true;
try {
await recordActivityScore(scoreForm.id!, scoreForm.score);
proxy?.$modal.msgSuccess('成绩录入成功');
scoreDialog.visible = false;
await getList();
} catch (error) {
console.error('成绩录入失败:', error);
proxy?.$modal.msgError('成绩录入失败');
} finally {
scoreButtonLoading.value = false;
}
}
});
};
/** 取消成绩录入 */
const cancelScore = () => {
scoreDialog.visible = false;
scoreForm.id = undefined;
scoreForm.studentName = '';
scoreForm.activityName = '';
scoreForm.score = '';
scoreForm.registrationType = '';
scoreForm.teamName = '';
};
// 暴露给父组件的方法
defineExpose({
getList
+21 -4
View File
@@ -453,14 +453,17 @@ const getList = async () => {
loading.value = true;
try {
const res = await listRegistrableActivities(queryParams.value);
activityList.value = res.rows;
total.value = res.total;
activityList.value = res.rows || [];
total.value = res.total || 0;
// 批量检查用户报名状态
await checkUserRegistrationStatus();
} catch (error) {
console.error('查询活动列表失败:', error);
proxy?.$modal.msgError('查询活动列表失败');
// 发生错误时重置数据
activityList.value = [];
total.value = 0;
} finally {
loading.value = false;
}
@@ -468,13 +471,27 @@ const getList = async () => {
/** 批量检查用户报名状态 */
const checkUserRegistrationStatus = async () => {
// 防御性检查:确保activityList存在且为数组
if (!activityList.value || !Array.isArray(activityList.value) || activityList.value.length === 0) {
console.warn('活动列表为空或无效,跳过报名状态检查');
return;
}
const promises = activityList.value.map(async (activity) => {
try {
// 确保activity和activity.id存在
if (!activity || !activity.id) {
console.warn('活动数据不完整,跳过报名状态检查:', activity);
return;
}
const registered = await checkRegistration(activity.id as number);
userRegistrationStatus.value[activity.id as number] = registered.data;
} catch (error) {
console.error(`检查活动${activity.id}报名状态失败:`, error);
userRegistrationStatus.value[activity.id as number] = false;
console.error(`检查活动${activity?.id}报名状态失败:`, error);
if (activity?.id) {
userRegistrationStatus.value[activity.id as number] = false;
}
}
});
+124 -15
View File
@@ -166,6 +166,11 @@
<dict-tag :options="stgl_activity_status" :value="scope.row.activityStatus" />
</template>
</el-table-column>
<el-table-column label="报名范围" align="center" prop="activityRange" width="100">
<template #default="scope">
<dict-tag :options="stgl_activity_range" :value="scope.row.activityRange" />
</template>
</el-table-column>
<el-table-column label="报名状态" align="center" prop="registrationStatus" width="100">
<template #default="scope">
<dict-tag :options="stgl_registration_status" :value="scope.row.registrationStatus" />
@@ -308,12 +313,12 @@
<el-tab-pane label="基本信息" name="basic">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="活动名称" prop="activityName">
<el-form-item label="活动名称" prop="activityName" required>
<el-input v-model="form.activityName" placeholder="请输入活动名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="活动类型" prop="activityType">
<el-form-item label="活动类型" prop="activityType" required>
<el-select v-model="form.activityType" placeholder="请选择活动类型" style="width: 100%">
<el-option v-for="dict in stgl_activity_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
@@ -334,7 +339,7 @@
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="开始时间" prop="startTime">
<el-form-item label="开始时间" prop="startTime" required>
<el-date-picker
v-model="form.startTime"
type="datetime"
@@ -345,7 +350,7 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间" prop="endTime">
<el-form-item label="结束时间" prop="endTime" required>
<el-date-picker
v-model="form.endTime"
type="datetime"
@@ -376,7 +381,7 @@
</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="主办方名称" prop="organizerName">
<el-form-item label="主办方名称" prop="organizerName" required>
<el-input v-model="form.organizerName" placeholder="请输入主办方名称" />
</el-form-item>
</el-col>
@@ -415,7 +420,7 @@
<el-tab-pane label="报名设置" name="registration">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报名方式" prop="registrationType">
<el-form-item label="报名方式" prop="registrationType" required>
<el-select v-model="form.registrationType" placeholder="请选择报名方式" style="width: 100%" @change="handleRegistrationTypeChange">
<el-option v-for="dict in stgl_registration_type" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
@@ -430,6 +435,17 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报名范围" prop="activityRange" required>
<el-radio-group v-model="form.activityRange" style="width: 100%">
<el-radio v-for="dict in stgl_activity_range" :key="dict.value" :value="Number(dict.value)">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="报名开始时间" prop="registrationStart">
@@ -592,6 +608,7 @@
<script setup name="StglActivity" lang="ts">
import { nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { ElNotification } from 'element-plus';
import {
listStglActivity,
getStglActivity,
@@ -618,8 +635,8 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const route = useRoute();
const router = useRouter();
const userStore = useUserStore();
const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_registration_status, sys_yes_no } = toRefs<any>(
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'sys_yes_no')
const { stgl_activity_type, stgl_activity_status, stgl_registration_type, stgl_registration_status, stgl_activity_range, sys_yes_no } = toRefs<any>(
proxy?.useDict('stgl_activity_type', 'stgl_activity_status', 'stgl_registration_type', 'stgl_registration_status', 'stgl_activity_range', 'sys_yes_no')
);
const activityList = ref<StglActivityVO[]>([]);
@@ -719,6 +736,7 @@ const initFormData: StglActivityForm = {
teamSizeMin: undefined,
teamSizeMax: undefined,
needApproval: 1,
activityRange: 1, // 默认为1-本组织成员
activityStatus: '0',
isFinished: 0,
summary: undefined,
@@ -752,11 +770,19 @@ const data = reactive<PageData<StglActivityForm, StglActivityQuery & { relatedCl
params: {}
},
rules: {
activityName: [{ required: true, message: '活动名称不能为空', trigger: 'blur' }],
activityType: [{ required: true, message: '活动类型不能为空', trigger: 'change' }],
startTime: [{ required: true, message: '开始时间不能为空', trigger: 'blur' }],
endTime: [{ required: true, message: '结束时间不能为空', trigger: 'blur' }],
organizerName: [{ required: true, message: '主办方名称不能为空', trigger: 'blur' }]
activityName: [
{ required: true, message: '活动名称不能为空', trigger: 'blur' },
{ min: 2, max: 100, message: '活动名称长度在2到100个字符', trigger: 'blur' }
],
activityType: [{ required: true, message: '请选择活动类型', trigger: 'change' }],
startTime: [{ required: true, message: '请选择活动开始时间', trigger: 'change' }],
endTime: [{ required: true, message: '请选择活动结束时间', trigger: 'change' }],
organizerName: [
{ required: true, message: '主办方名称不能为空', trigger: 'blur' },
{ min: 2, max: 50, message: '主办方名称长度在2到50个字符', trigger: 'blur' }
],
registrationType: [{ required: true, message: '请选择报名方式', trigger: 'change' }],
activityRange: [{ required: true, message: '请选择报名范围', trigger: 'change' }]
}
});
@@ -1072,11 +1098,17 @@ const handleUpdate = async (row?: StglActivityVO) => {
Object.assign(form.value, res.data);
// 确保数据类型正确
if (form.value.registrationType !== undefined) {
form.value.registrationType = String(form.value.registrationType);
}
// 确保指导老师数据正确设置
console.log('修改活动 - 设置表单数据后的状态:', {
advisors: form.value.advisors,
instructorList: form.value.instructorList,
instructors: form.value.instructors
instructors: form.value.instructors,
registrationType: form.value.registrationType
});
// 更新formKey以强制重新渲染组件
@@ -1086,9 +1118,83 @@ const handleUpdate = async (row?: StglActivityVO) => {
dialog.title = '修改活动信息';
};
/** 显示验证错误提示 */
const showValidationErrors = (invalidFields: any) => {
if (!invalidFields) return;
const errorMessages: string[] = [];
const tabMapping = {
// 基本信息标签页字段
'activityName': { tab: 'basic', label: '活动名称' },
'activityType': { tab: 'basic', label: '活动类型' },
'startTime': { tab: 'basic', label: '开始时间' },
'endTime': { tab: 'basic', label: '结束时间' },
'organizerName': { tab: 'basic', label: '主办方名称' },
// 报名设置标签页字段
'registrationType': { tab: 'registration', label: '报名方式' },
'activityRange': { tab: 'registration', label: '报名范围' }
};
let needSwitchTab = '';
let currentTabErrors: string[] = [];
let otherTabErrors: string[] = [];
// 分类错误信息
Object.keys(invalidFields).forEach(fieldName => {
const fieldInfo = tabMapping[fieldName];
if (fieldInfo) {
const errorMsg = invalidFields[fieldName][0]?.message || '验证失败';
// 去掉重复的"不能为空"等文字,只保留核心提示
const cleanMessage = errorMsg.replace(/不能为空$/, '').replace(/^请选择/, '').replace(/^请输入/, '');
const errorMessage = cleanMessage ? `${fieldInfo.label}:${cleanMessage}` : `${fieldInfo.label}为必填项`;
if (fieldInfo.tab === activeTab.value) {
currentTabErrors.push(errorMessage);
} else {
otherTabErrors.push(errorMessage);
if (!needSwitchTab) {
needSwitchTab = fieldInfo.tab;
}
}
}
});
// 构建提示消息
if (currentTabErrors.length > 0) {
errorMessages.push(`【当前页面】${currentTabErrors.join(';')}`);
}
if (otherTabErrors.length > 0) {
const tabName = needSwitchTab === 'registration' ? '报名设置' : '基本信息';
errorMessages.push(`【${tabName}页面】${otherTabErrors.join(';')}`);
}
if (errorMessages.length > 0) {
// 使用Notification在浏览器顶部显示提示
ElNotification({
title: '表单验证失败',
message: errorMessages.join('\n'),
type: 'warning',
duration: 10000,
position: 'top-right',
showClose: true
});
// 如果其他标签页有错误,自动切换到第一个有错误的标签页
if (needSwitchTab && needSwitchTab !== activeTab.value) {
activeTab.value = needSwitchTab;
// 切换标签页后延迟一下再次验证,确保用户能看到错误字段
nextTick(() => {
activityFormRef.value?.validate(() => {});
});
}
}
};
/** 提交按钮 */
const submitForm = () => {
activityFormRef.value?.validate(async (valid: boolean) => {
activityFormRef.value?.validate(async (valid: boolean, invalidFields) => {
if (valid) {
buttonLoading.value = true;
@@ -1156,6 +1262,9 @@ const submitForm = () => {
} finally {
buttonLoading.value = false;
}
} else {
// 验证失败,显示必填项提示
showValidationErrors(invalidFields);
}
});
};
+16 -15
View File
@@ -41,7 +41,7 @@
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="View" @click="handleView" v-hasPermi="['stgl:stclass:query']">查看</el-button>
<el-button type="primary" plain icon="View" @click="() => handleView()" v-hasPermi="['stgl:stclass:query']">查看</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Download" @click="handleExport" v-hasPermi="['stgl:stclass:export']">导出</el-button>
@@ -53,15 +53,15 @@
<el-table v-loading="loading" border :data="studentList" @selection-change="handleSelectionChange" @row-dblclick="handleView">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="学生姓名" align="center" prop="studentName" width="120" />
<el-table-column label="学号" align="center" prop="studentNo" width="140" />
<el-table-column label="性别" align="center" prop="gender" width="80">
<el-table-column label="学生姓名" align="center" prop="studentName" min-width="40" />
<el-table-column label="学号" align="center" prop="studentNo" min-width="45" />
<el-table-column label="性别" align="center" prop="gender" width="70">
<template #default="scope">
<dict-tag :options="sys_user_sex" :value="scope.row.gender" />
</template>
</el-table-column>
<el-table-column label="联系电话" align="center" prop="phone" width="120" />
<el-table-column label="加入社团" align="center" width="100">
<el-table-column label="联系电话" align="center" prop="phone" min-width="55" />
<el-table-column label="加入社团" align="center" width="160">
<template #default="scope">
<el-button
v-if="scope.row.clubCount > 0"
@@ -75,7 +75,7 @@
<span v-else class="no-data">0</span>
</template>
</el-table-column>
<el-table-column label="加入志愿者队伍" align="center" width="120">
<el-table-column label="加入志愿者队伍" align="center" width="170">
<template #default="scope">
<el-button
v-if="scope.row.volunteerTeamCount > 0"
@@ -89,7 +89,7 @@
<span v-else class="no-data">0</span>
</template>
</el-table-column>
<el-table-column label="参与活动" align="center" width="100">
<el-table-column label="参与活动" align="center" width="160">
<template #default="scope">
<el-button
v-if="scope.row.activityCount > 0"
@@ -177,8 +177,9 @@
<el-descriptions-item label="活动时间">{{ activity.activityTime }}</el-descriptions-item>
<el-descriptions-item label="关联社团/队伍">{{ activity.relatedOrganization }}</el-descriptions-item>
<el-descriptions-item label="指导老师姓名">{{ activity.advisorName }}</el-descriptions-item>
<el-descriptions-item label="指导老师部门">{{ activity.advisorDept }}</el-descriptions-item>
<el-descriptions-item label="指导老师电话">{{ activity.advisorPhone }}</el-descriptions-item>
<el-descriptions-item label="报名类型">{{ activity.registrationType }}</el-descriptions-item>
<el-descriptions-item label="取得成绩">{{ activity.score }}</el-descriptions-item>
</el-descriptions>
</div>
</div>
@@ -249,7 +250,7 @@ const activityDetails = ref<ActivityDetailVO[]>([]);
const getTeacherClassList = async () => {
try {
const res = await getTeacherClasses();
if (res.code === 200 && res.data) {
if ((res.code === 200 || res.code === 0) && res.data) {
classList.value = res.data;
// 默认选择第一个班级
if (classList.value.length > 0) {
@@ -268,7 +269,7 @@ const getList = async () => {
loading.value = true;
try {
const res = await listStglClass(queryParams.value);
if (res.code === 200) {
if (res.code === 200 || res.code === 0) {
studentList.value = res.rows;
total.value = res.total;
}
@@ -313,14 +314,14 @@ const handleView = (row?: StglClassVO) => {
return;
}
// 这里可以跳转到学生详情页面或显示学生详细信息
proxy?.$modal.msgInfo(`查看学生:${_row.studentName}`);
proxy?.$modal.msg(`查看学生:${_row.studentName}`);
};
/** 查看社团详情 */
const handleViewClubs = async (row: StglClassVO) => {
try {
const res = await getStudentClubs(row.id);
if (res.code === 200) {
if (res.code === 200 || res.code === 0) {
clubDetails.value = res.data || [];
clubDialog.title = `${row.studentName} - 社团信息`;
clubDialog.visible = true;
@@ -335,7 +336,7 @@ const handleViewClubs = async (row: StglClassVO) => {
const handleViewVolunteerTeams = async (row: StglClassVO) => {
try {
const res = await getStudentVolunteerTeams(row.id);
if (res.code === 200) {
if (res.code === 200 || res.code === 0) {
volunteerTeamDetails.value = res.data || [];
volunteerTeamDialog.title = `${row.studentName} - 志愿者队伍信息`;
volunteerTeamDialog.visible = true;
@@ -350,7 +351,7 @@ const handleViewVolunteerTeams = async (row: StglClassVO) => {
const handleViewActivities = async (row: StglClassVO) => {
try {
const res = await getStudentActivities(row.id);
if (res.code === 200) {
if (res.code === 200 || res.code === 0) {
activityDetails.value = res.data || [];
activityDialog.title = `${row.studentName} - 活动信息`;
activityDialog.visible = true;
@@ -133,7 +133,8 @@ import { getCurrentInstance, onMounted, reactive, ref, toRefs } from 'vue';
import {
listVolunteerMember,
getVolunteerMember,
updateVolunteerMember
updateVolunteerMember,
approveVolunteerMember
} from '@/api/stgl/volunteermember';
import { VolunteerMemberVO, VolunteerMemberQuery } from '@/api/stgl/volunteermember/types';
import { parseTime } from '@/utils/ruoyi';
@@ -324,29 +325,7 @@ const handleApprove = async (row: VolunteerMemberVO) => {
await proxy?.$modal.confirm(`确认通过"${row.studentName}"的入队申请?`);
// 构建完整的更新数据,包含所有必要字段
const updateData = {
id: row.id,
userId: row.userId, // 添加用户ID字段
memberType: 2, // 志愿者成员类型(必需字段)
relationId: row.relationId || props.teamId, // 优先使用行数据中的relationId,否则使用props中的teamId
studentNo: row.studentNo,
studentName: row.studentName,
gender: row.gender,
department: row.department,
major: row.major,
className: row.className,
phone: row.phone,
email: row.email,
roleType: row.roleType || '队员', // 默认为队员
status: '2', // 设置为已加入状态
joinTime: new Date().toISOString().split('T')[0], // 设置加入时间为当前日期
remark: row.remark
};
console.log('审核通过 - 更新数据:', updateData);
await updateVolunteerMember(updateData as any);
await approveVolunteerMember(row.id, true);
proxy?.$modal.msgSuccess('审核通过成功');
await getList();
};
@@ -360,28 +339,7 @@ const handleReject = async (row: VolunteerMemberVO) => {
await proxy?.$modal.confirm(`确认拒绝"${row.studentName}"的入队申请?`);
// 构建完整的更新数据,包含所有必要字段
const updateData = {
id: row.id,
userId: row.userId, // 添加用户ID字段
memberType: 2, // 志愿者成员类型(必需字段)
relationId: row.relationId || props.teamId, // 优先使用行数据中的relationId,否则使用props中的teamId
studentNo: row.studentNo,
studentName: row.studentName,
gender: row.gender,
department: row.department,
major: row.major,
className: row.className,
phone: row.phone,
email: row.email,
roleType: '', // 拒绝审核后没有角色
status: '3', // 设置为已驳回状态
remark: row.remark
};
console.log('审核拒绝 - 更新数据:', updateData);
await updateVolunteerMember(updateData as any);
await approveVolunteerMember(row.id, false);
proxy?.$modal.msgSuccess('审核拒绝成功');
await getList();
};
@@ -396,7 +354,7 @@ const handleBatchApprove = async () => {
await proxy?.$modal.confirm(`确认批量通过所选成员的入队申请?`);
const promises = ids.value.map(id => {
// 根据ID找到对应的成员记录,获取relationId
// 根据ID找到对应的成员记录,进行数据验证
const member = memberList.value.find(m => m.id === id);
if (!member) {
proxy?.$modal.msgError(`未找到ID为${id}的成员记录`);
@@ -408,29 +366,7 @@ const handleBatchApprove = async () => {
return Promise.reject(new Error(`成员${member.studentName}数据不完整`));
}
// 构建完整的更新数据,包含所有必要字段
const updateData = {
id: id,
userId: member.userId, // 添加用户ID字段
memberType: 2, // 志愿者成员类型(必需字段)
relationId: member.relationId || props.teamId, // 优先使用行数据中的relationId,否则使用props中的teamId
studentNo: member.studentNo,
studentName: member.studentName,
gender: member.gender,
department: member.department,
major: member.major,
className: member.className,
phone: member.phone,
email: member.email,
roleType: member.roleType || '队员', // 默认为队员
status: '2', // 设置为已加入状态
joinTime: new Date().toISOString().split('T')[0],
remark: member.remark
};
console.log(`批量审核通过 - ID ${id} 更新数据:`, updateData);
return updateVolunteerMember(updateData as any);
return approveVolunteerMember(id, true);
});
await Promise.all(promises);
@@ -448,7 +384,7 @@ const handleBatchReject = async () => {
await proxy?.$modal.confirm(`确认批量拒绝所选成员的入队申请?`);
const promises = ids.value.map(id => {
// 根据ID找到对应的成员记录,获取relationId
// 根据ID找到对应的成员记录,进行数据验证
const member = memberList.value.find(m => m.id === id);
if (!member) {
proxy?.$modal.msgError(`未找到ID为${id}的成员记录`);
@@ -460,28 +396,7 @@ const handleBatchReject = async () => {
return Promise.reject(new Error(`成员${member.studentName}数据不完整`));
}
// 构建完整的更新数据,包含所有必要字段
const updateData = {
id: id,
userId: member.userId, // 添加用户ID字段
memberType: 2, // 志愿者成员类型(必需字段)
relationId: member.relationId || props.teamId, // 优先使用行数据中的relationId,否则使用props中的teamId
studentNo: member.studentNo,
studentName: member.studentName,
gender: member.gender,
department: member.department,
major: member.major,
className: member.className,
phone: member.phone,
email: member.email,
roleType: '', // 拒绝审核后没有角色
status: '3', // 设置为已驳回状态
remark: member.remark
};
console.log(`批量审核拒绝 - ID ${id} 更新数据:`, updateData);
return updateVolunteerMember(updateData as any);
return approveVolunteerMember(id, false);
});
await Promise.all(promises);