wuzhen update

This commit is contained in:
wuzhen committed 2025-08-24 14:55:36 +08:00
1 parent d257e70a00
commit c992f192b2
10 files changed
+1419 -906

No files matched your search

@@ -295,4 +295,13 @@ public class JcbtScholarshipTypeController extends BaseController {
return R.ok(compatibleTypes);
}
/**
* 获取奖学金类型的互斥关系显示文本
*/
@SaCheckPermission("jcbt:scholarshipType:query")
@GetMapping("/{id}/exclusiveRelationDisplay")
public R<String> getExclusiveRelationDisplay(@NotNull(message = "主键不能为空") @PathVariable Long id) {
return R.ok(scholarshipTypeService.getExclusiveRelationDisplay(id));
}
}
@@ -91,4 +91,12 @@ public interface IJcbtScholarshipTypeService {
*/
List<JcbtScholarshipTypeVo> queryOptions();
/**
* 获取奖学金类型的互斥关系显示文本
*
* @param scholarshipTypeId 奖学金类型ID
* @return 互斥关系显示文本
*/
String getExclusiveRelationDisplay(Long scholarshipTypeId);
}
@@ -14,10 +14,12 @@ import org.dromara.jcbt.domain.vo.JcbtScholarshipTypeVo;
import org.dromara.jcbt.domain.JcbtScholarshipType;
import org.dromara.jcbt.mapper.JcbtScholarshipTypeMapper;
import org.dromara.jcbt.service.IJcbtScholarshipTypeService;
import org.dromara.jcbt.service.IJcbtScholarshipCompatibilityService;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
/**
* 奖学金类型Service业务层处理
@@ -30,6 +32,7 @@ import java.util.Collection;
public class JcbtScholarshipTypeServiceImpl implements IJcbtScholarshipTypeService {
private final JcbtScholarshipTypeMapper baseMapper;
private final IJcbtScholarshipCompatibilityService compatibilityService;
/**
* 查询奖学金类型
@@ -231,4 +234,48 @@ public class JcbtScholarshipTypeServiceImpl implements IJcbtScholarshipTypeServi
JcbtScholarshipType::getTypeCategory, JcbtScholarshipType::getAwardAmount);
return baseMapper.selectVoList(lqw);
}
/**
* 获取奖学金类型的互斥关系显示文本
*/
@Override
public String getExclusiveRelationDisplay(Long scholarshipTypeId) {
// 1. 获取当前奖学金类型信息
JcbtScholarshipTypeVo currentType = queryById(scholarshipTypeId);
if (currentType == null) {
return "互斥(无)";
}
// 2. 如果是EXCLUSIVE类型,显示"互斥(与全部其他奖学金类型)"
if ("EXCLUSIVE".equals(currentType.getCompatibilityType())) {
return "互斥(与全部其他奖学金类型)";
}
// 3. 如果是CUSTOM类型,查询具体的互斥关系
if ("CUSTOM".equals(currentType.getCompatibilityType())) {
List<Long> exclusiveTypeIds = compatibilityService.getExclusiveTypeIds(scholarshipTypeId);
if (exclusiveTypeIds == null || exclusiveTypeIds.isEmpty()) {
return "互斥(无)";
}
// 查询互斥的奖学金类型名称
List<String> exclusiveTypeNames = new ArrayList<>();
for (Long exclusiveTypeId : exclusiveTypeIds) {
JcbtScholarshipTypeVo exclusiveType = queryById(exclusiveTypeId);
if (exclusiveType != null) {
exclusiveTypeNames.add(exclusiveType.getTypeName());
}
}
if (exclusiveTypeNames.isEmpty()) {
return "互斥(无)";
}
return "互斥(与" + String.join("、", exclusiveTypeNames) + ")";
}
// 4. 其他情况(如COMPATIBLE),显示"互斥(无)"
return "互斥(无)";
}
}
+11
View File
@@ -329,3 +329,14 @@ export const getCompatibleTypes = (id: string | number): AxiosPromise<Scholarshi
method: 'get'
});
};
/**
* 获取奖学金类型的互斥关系显示文本
* @param id 奖学金类型ID
*/
export const getExclusiveRelationDisplay = (id: string | number): AxiosPromise<string> => {
return request({
url: `/jcbt/scholarshipType/${id}/exclusiveRelationDisplay`,
method: 'get'
});
};
+74 -4
View File
@@ -155,11 +155,16 @@
<span class="amount-text">¥{{ parseFloat(scope.row.awardAmount || '0').toLocaleString() }}</span>
</template>
</el-table-column>
<el-table-column label="兼得类型" prop="compatibilityType" width="120" align="center">
<el-table-column label="兼得类型" prop="compatibilityType" width="200" align="center">
<template #default="scope">
<el-tag :type="getCompatibilityTagType(scope.row.compatibilityType)">
{{ getCompatibilityText(scope.row.compatibilityType) }}
</el-tag>
<div>
<el-tag :type="getCompatibilityTagType(scope.row.compatibilityType)">
{{ getCompatibilityText(scope.row.compatibilityType) }}
</el-tag>
<div v-if="scope.row.compatibilityType === 'CUSTOM'" class="compatibility-detail">
<span class="exclusive-relation-text">{{ getExclusiveRelationText(scope.row.id) }}</span>
</div>
</div>
</template>
</el-table-column>
<el-table-column label="排序" prop="sortOrder" width="80" align="center" />
@@ -473,6 +478,7 @@ import {
checkScholarshipTypeNameUnique,
getCompatibilityConfig,
saveCompatibilityConfig,
getExclusiveRelationDisplay,
type ScholarshipTypeVO,
type ScholarshipTypeForm,
type ScholarshipTypeQuery,
@@ -526,6 +532,9 @@ const availableScholarshipTypes = ref<ScholarshipTypeVO[]>([]);
// 当前奖学金的兼容性配置(用于编辑时显示原来的配置)
const currentCompatibilityConfig = ref<CompatibilityConfig | null>(null);
// 互斥关系显示文本缓存
const exclusiveRelationCache = ref<Map<string | number, string>>(new Map());
const dataRules = reactive<FormRules>({
typeCode: [
{ required: true, message: '奖学金类型编码不能为空', trigger: 'blur' },
@@ -626,6 +635,44 @@ const getCompatibilityTagType = (value: string) => {
return typeMap[value] || 'warning'; // 未知类型用橙色警告标签
};
/** 获取互斥关系显示文本 */
const getExclusiveRelationText = (scholarshipTypeId: string | number): string => {
if (!scholarshipTypeId) return '';
// 先从缓存中获取
const cached = exclusiveRelationCache.value.get(scholarshipTypeId);
if (cached !== undefined) {
return cached;
}
// 异步获取并缓存
getExclusiveRelationDisplay(scholarshipTypeId).then(response => {
exclusiveRelationCache.value.set(scholarshipTypeId, response.data);
}).catch(error => {
console.warn('获取互斥关系显示文本失败:', error);
exclusiveRelationCache.value.set(scholarshipTypeId, '互斥(无)');
});
return '加载中...';
};
/** 预加载互斥关系显示文本 */
const preloadExclusiveRelations = async () => {
const customTypes = scholarshipTypeList.value.filter(item => item.compatibilityType === 'CUSTOM');
for (const type of customTypes) {
if (type.id && !exclusiveRelationCache.value.has(type.id)) {
try {
const response = await getExclusiveRelationDisplay(type.id);
exclusiveRelationCache.value.set(type.id, response.data);
} catch (error) {
console.warn(`获取奖学金类型 ${type.id} 的互斥关系失败:`, error);
exclusiveRelationCache.value.set(type.id, '互斥(无)');
}
}
}
};
/** 查询奖学金类型列表 */
const getList = async () => {
loading.value = true;
@@ -659,6 +706,9 @@ const getList = async () => {
scholarshipTypeList.value = response.rows;
total.value = response.total;
// 预加载CUSTOM类型的互斥关系显示文本
preloadExclusiveRelations();
// 计算统计数据
calculateStatistics();
} finally {
@@ -688,6 +738,8 @@ const resetQuery = () => {
daterangeCreateTime.value = ['', ''];
queryFormRef.value?.resetFields();
queryParams.value.pageNum = 1;
// 清空缓存
exclusiveRelationCache.value.clear();
handleQuery();
};
@@ -769,6 +821,8 @@ const handleDelete = async (row?: ScholarshipTypeVO) => {
try {
await proxy?.$modal.confirm(`是否确认删除奖学金类型"${typeNames.join('、')}"?`);
await delScholarshipType(typeIds);
// 清空缓存以便重新加载
exclusiveRelationCache.value.clear();
await getList();
proxy?.$modal.msgSuccess('删除成功');
} catch (error) {
@@ -790,6 +844,8 @@ const handleStatusChange = async (row: ScholarshipTypeVO) => {
await proxy?.$modal.confirm(`确认要${text}"${row.typeName}"吗?`);
await changeScholarshipTypeStatus(row.id!, row.status!);
proxy?.$modal.msgSuccess(`${text}成功`);
// 清空缓存以便重新加载
exclusiveRelationCache.value.clear();
await getList();
} catch (error) {
if (error !== 'cancel') {
@@ -824,6 +880,8 @@ const dialogSubmit = () => {
}
dialogOpen.value = false;
// 清空缓存以便重新加载
exclusiveRelationCache.value.clear();
await getList();
} catch (error) {
proxy?.$modal.msgError(form.value.id ? '修改失败' : '新增失败');
@@ -1057,4 +1115,16 @@ onMounted(() => {
margin-bottom: 0 !important;
}
}
/* 兼容性详情样式 */
.compatibility-detail {
margin-top: 4px;
font-size: 12px;
}
.exclusive-relation-text {
color: #909399;
line-height: 1.2;
word-break: break-word;
}
</style>
+347 -232
View File
@@ -2,125 +2,133 @@
<div class="page-container">
<!-- 搜索区域 -->
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<el-card v-show="showSearch" class="search-card">
<el-form :model="queryParams" ref="queryFormRef" label-width="80px">
<el-row :gutter="20">
<!-- 第一行:4个条件 -->
<el-col :span="6">
<el-form-item label="姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="queryParams.idCard" placeholder="请输入身份证号" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="准考证号" prop="examNumber">
<el-input v-model="queryParams.examNumber" placeholder="请输入准考证号" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="性别" prop="gender">
<el-select v-model="queryParams.gender" placeholder="请选择性别" clearable class="w-100">
<el-option v-for="dict in zsjy_gender" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
<!-- 第一行:4个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="姓名" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入姓名" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="queryParams.idCard" placeholder="请输入身份证号" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="准考证号" prop="examNumber">
<el-input v-model="queryParams.examNumber" placeholder="请输入准考证号" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="性别" prop="gender">
<el-select v-model="queryParams.gender" placeholder="请选择性别" clearable style="width: 100%">
<el-option v-for="dict in zsjy_gender" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 第二行:4个条件 -->
<el-col :span="6">
<el-form-item label="所属学院" prop="collegeId">
<el-select v-model="queryParams.collegeId" placeholder="请选择学院" clearable class="w-100" @change="onSearchCollegeChange">
<el-option v-for="college in collegeOptions" :key="college.deptId" :label="college.deptName" :value="college.deptCategory" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="报考专业" prop="appliedMajor">
<el-select v-model="queryParams.appliedMajor" placeholder="请选择报考专业" clearable class="w-100">
<el-option v-for="major in searchMajorOptions" :key="major.value" :label="major.label" :value="major.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="联系电话" prop="phone1">
<el-input v-model="queryParams.phone1" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="中考地区" prop="examRegion">
<el-input v-model="queryParams.examRegion" placeholder="请输入中考地区" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
</el-row>
<!-- 第二行:4个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="所属学院" prop="collegeId">
<el-select v-model="queryParams.collegeId" placeholder="请选择学院" clearable style="width: 100%" @change="onSearchCollegeChange">
<el-option v-for="college in collegeOptions" :key="college.deptId" :label="college.deptName" :value="college.deptCategory" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="报考专业" prop="appliedMajor">
<el-select v-model="queryParams.appliedMajor" placeholder="请选择报考专业" clearable style="width: 100%">
<el-option v-for="major in searchMajorOptions" :key="major.value" :label="major.label" :value="major.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="联系电话" prop="phone1">
<el-input v-model="queryParams.phone1" placeholder="请输入联系电话" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="中考地区" prop="examRegion">
<el-input v-model="queryParams.examRegion" placeholder="请输入中考地区" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<!-- 第三行:1个条件 + 操作按钮 -->
<el-col :span="6">
<el-form-item label="报名状态" prop="enrollmentStatus">
<el-select v-model="queryParams.enrollmentStatus" placeholder="请选择报名状态" clearable class="w-100">
<el-option :value="ENROLLMENT_STATUS.PENDING" label="待审核" />
<el-option :value="ENROLLMENT_STATUS.AUDITING" label="信息审核中" />
<el-option :value="ENROLLMENT_STATUS.PROCESSING" label="录取处理中" />
<el-option :value="ENROLLMENT_STATUS.CONFIRMING" label="待最终确认" />
<el-option :value="ENROLLMENT_STATUS.COMPLETED" label="录取完成" />
<el-option :value="ENROLLMENT_STATUS.REJECTED" label="已驳回" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="18" class="search-btn-container">
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 第三行:1个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="报名状态" prop="enrollmentStatus">
<el-select v-model="queryParams.enrollmentStatus" placeholder="请选择报名状态" clearable style="width: 100%">
<el-option :value="ENROLLMENT_STATUS.PENDING" label="待审核" />
<el-option :value="ENROLLMENT_STATUS.AUDITING" label="信息审核中" />
<el-option :value="ENROLLMENT_STATUS.PROCESSING" label="录取处理中" />
<el-option :value="ENROLLMENT_STATUS.CONFIRMING" label="待最终确认" />
<el-option :value="ENROLLMENT_STATUS.COMPLETED" label="录取完成" />
<el-option :value="ENROLLMENT_STATUS.REJECTED" label="已驳回" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 操作按钮行 -->
<el-row :gutter="10" class="mb8">
<el-col :span="24" class="search-btn-container">
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
</div>
</transition>
<!-- 操作按钮区域 -->
<el-card class="button-card">
<!-- 表格数据 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<div class="card-header-vertical">
<span class="toolbar-title">招生信息管理</span>
<div class="search-toggle">
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</div>
</div>
<el-row ref="toolbarRef" :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:enrollment:info:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:enrollment:info:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:enrollment:info:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:enrollment:info:export']">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Check" :disabled="multiple" @click="handleBatchAudit()" v-hasPermi="['zsjy:enrollment:info:edit']">批量审核</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<div class="button-group">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:enrollment:info:add']">新增</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:enrollment:info:edit']"
>修改</el-button
>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:enrollment:info:remove']"
>删除</el-button
>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:enrollment:info:export']">导出</el-button>
<el-button type="success" plain icon="Check" :disabled="multiple" @click="handleBatchAudit()" v-hasPermi="['zsjy:enrollment:info:edit']"
>批量审核</el-button
>
</div>
</el-card>
<!-- 表格区域 -->
<el-card class="table-card">
<div class="table-container">
<el-table v-loading="loading" :data="enrollmentInfoList" class="scroll-table" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键ID" align="center" prop="id" v-if="false" />
<el-table-column label="姓名" align="center" prop="name" :show-overflow-tooltip="true" />
<el-table
ref="enrollmentTableRef"
v-loading="loading"
border
:data="enrollmentInfoList"
row-key="id"
class="scroll-table"
@selection-change="handleSelectionChange"
style="width: 100%"
:scroll-x="true"
>
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="姓名" align="center" prop="name" :show-overflow-tooltip="true" min-width="100" />
<el-table-column label="身份证号" align="center" prop="idCard" :show-overflow-tooltip="true" width="180" />
<el-table-column label="性别" align="center" prop="gender">
<el-table-column label="性别" align="center" prop="gender" width="80">
<template #default="scope">
<!-- 直接显示性别文字 -->
<span class="gender-text-direct">
{{ scope.row.gender === 'M' ? '男' : scope.row.gender === 'F' ? '女' : getGenderDisplay(scope.row.gender, scope.row.idCard) }}
</span>
@@ -128,7 +136,7 @@
</el-table-column>
<el-table-column label="联系电话" align="center" prop="phone1" :show-overflow-tooltip="true" width="130" />
<el-table-column label="准考证号" align="center" prop="examNumber" :show-overflow-tooltip="true" width="130" />
<el-table-column label="中考地区" align="center" prop="examRegion" :show-overflow-tooltip="true" />
<el-table-column label="中考地区" align="center" prop="examRegion" :show-overflow-tooltip="true" min-width="120" />
<el-table-column label="中考成绩" align="center" prop="totalScore" width="100" />
<el-table-column label="报考专业" align="center" prop="appliedMajor" :show-overflow-tooltip="true" width="120" />
<el-table-column label="所属学院" align="center" prop="collegeName" :show-overflow-tooltip="true" width="120" />
@@ -142,39 +150,31 @@
<span>{{ parseTime(scope.row.applicationTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="220" fixed="right">
<el-table-column label="操作" align="center" width="280" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<div class="action-buttons">
<el-tooltip content="查看" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['zsjy:enrollment:info:query']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:enrollment:info:edit']"></el-button>
</el-tooltip>
<el-tooltip content="审核" placement="top">
<el-button link type="success" icon="Check" @click="handleAudit(scope.row)" v-hasPermi="['zsjy:enrollment:info:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button
link
type="danger"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['zsjy:enrollment:info:remove']"
></el-button>
</el-tooltip>
</div>
<el-tooltip content="查看" placement="top">
<el-button link type="info" icon="View" @click="handleView(scope.row)" v-hasPermi="['zsjy:enrollment:info:query']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:enrollment:info:edit']"></el-button>
</el-tooltip>
<el-tooltip content="审核" placement="top">
<el-button link type="success" icon="Check" @click="handleAudit(scope.row)" v-hasPermi="['zsjy:enrollment:info:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:enrollment:info:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</div>
</el-card>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :page="queryParams.pageNum" :limit="queryParams.pageSize" :total="total" @pagination="getList" />
</div>
<!-- 添加或修改招生报名信息对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1000px" append-to-body>
<el-form ref="enrollmentInfoFormRef" :model="form" :rules="rules" label-width="120px">
@@ -892,6 +892,7 @@ const handleBatchCurrentChange = (val: number) => {
const queryFormRef = ref<FormInstance>();
const enrollmentInfoFormRef = ref<FormInstance>();
const enrollmentTableRef = ref();
const dialog = reactive<DialogOption>({
visible: false,
@@ -1594,6 +1595,33 @@ const handleExport = () => {
);
};
/** 批量更新按钮操作 */
const handleBatchUpdate = async () => {
if (ids.value.length === 0) {
proxy?.$modal.msgError('请选择要修改的招生报名信息');
return;
}
if (ids.value.length > 1) {
proxy?.$modal.msgError('批量修改功能暂不支持,请选择单条记录进行修改');
return;
}
// 如果只选择了一条记录,调用单个修改方法
const row = enrollmentInfoList.value.find(item => item.id === ids.value[0]);
if (row) {
handleUpdate(row);
}
};
/** 批量删除按钮操作 */
const handleBatchDelete = async () => {
if (ids.value.length === 0) {
proxy?.$modal.msgError('请选择要删除的招生报名信息');
return;
}
// 调用现有的删除方法,它已经支持批量删除
handleDelete();
};
/** 批量审核按钮操作 */
const handleBatchAudit = async () => {
if (ids.value.length === 0) {
@@ -1920,77 +1948,157 @@ onMounted(() => {
</script>
<style scoped>
/* 页面容器样式 */
.page-container {
padding: 20px;
background-color: #f5f7fa;
}
.search-card {
margin-bottom: 20px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.search-btn-container {
text-align: right;
}
.button-card {
margin-bottom: 20px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.card-header-vertical {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.toolbar-title {
font-size: 18px;
font-weight: bold;
color: #303133;
}
.button-group {
display: flex;
align-items: center;
gap: 10px;
padding-top: 5px;
}
.search-toggle {
display: flex;
align-items: center;
padding: 8px;
}
/* 表格卡片布局 */
.table-card {
margin-bottom: 20px;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
margin-top: 0;
}
.table-card :deep(.el-card__body) {
padding: 0px 20px 20px 20px !important;
}
/* 表格容器 - 支持横向滚动 */
.table-container {
overflow-x: auto;
width: 100%;
margin-bottom: 0;
}
/* 横向滚动表格样式 */
.scroll-table {
width: 100%;
}
.pagination-container {
text-align: right;
padding-top: 20px;
/* 表格横向滚动条样式优化 */
.scroll-table :deep(.el-table__body-wrapper) {
overflow-x: auto !important; /* 自动显示横向滚动条 */
overflow-y: auto;
}
.scroll-table :deep(.el-table__header-wrapper) {
overflow-x: hidden;
}
/* 强制显示表格横向滚动条 - 适用于所有浏览器 */
.scroll-table :deep(.el-table__body-wrapper) {
scrollbar-width: thin; /* Firefox */
scrollbar-color: #409eff #f0f0f0; /* Firefox - thumb track */
}
/* Webkit 浏览器的横向滚动条样式 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar {
height: 12px !important; /* 增加滚动条高度 */
width: 12px !important;
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-track {
background: #f0f0f0 !important;
border-radius: 6px !important;
border: 1px solid #e4e7ed !important; /* 添加边框使其更明显 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb {
background: #409eff !important; /* 使用主题色,更明显 */
border-radius: 6px !important;
border: 2px solid #f0f0f0 !important; /* 添加白色边框 */
min-height: 20px !important; /* 确保最小高度 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:hover {
background: #337ecc !important; /* 悬停时更深的蓝色 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:active {
background: #2b6cb0 !important; /* 点击时的颜色 */
}
/* 确保滚动条始终可见的额外设置 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-corner {
background: #f0f0f0;
}
/* 固定列样式优化 */
.scroll-table :deep(.el-table__fixed-right) {
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
}
.scroll-table :deep(.el-table__fixed-left) {
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
/* 确保固定列在滚动时有正确的背景色 */
.scroll-table :deep(.el-table__fixed-right .el-table__cell),
.scroll-table :deep(.el-table__fixed-left .el-table__cell) {
background-color: #fff;
}
/* 表格行悬停效果在固定列上的同步 */
.scroll-table :deep(.el-table__row:hover .el-table__cell) {
background-color: #f5f7fa !important;
}
/* 分页容器样式 */
.pagination-container {
display: flex;
justify-content: flex-end;
padding: 16px 20px 0 0 !important;
background-color: #fff;
margin-top: 0px !important;
}
/* 移除按钮栏底部边框 */
.button-card :deep(.el-card__header) {
border-bottom: none !important;
}
/* 对话框样式 */
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.dialog-form {
.el-form-item {
margin-bottom: 18px;
}
.form-tip {
font-size: 12px;
color: #909399;
margin-top: 4px;
line-height: 1.4;
}
}
/* 描述列表样式优化 */
:deep(.el-descriptions) {
.el-descriptions__label {
font-weight: 600;
color: #606266;
width: 120px;
}
.el-descriptions__content {
color: #303133;
}
}
.search-btn-container {
display: flex;
justify-content: flex-end;
margin-top: 10px;
.el-form-item {
margin-bottom: 0 !important;
}
}
/* 表单区域样式 */
.form-section {
margin-bottom: 20px;
}
@@ -2004,6 +2112,7 @@ onMounted(() => {
border-bottom: 2px solid #409eff;
}
/* 查看文本样式 */
.view-text {
color: #606266;
font-size: 14px;
@@ -2015,16 +2124,43 @@ onMounted(() => {
line-height: 1.5;
}
.w-100 {
width: 100% !important;
/* 性别文本样式 */
.gender-text-direct {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 10px;
/* 住宿文本样式 */
.boarding-text {
font-size: 14px;
color: #303133;
}
/* 学院和专业名称样式 */
.college-name {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.college-code {
font-size: 14px;
color: #303133;
}
.major-name {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.major-code {
font-size: 14px;
color: #303133;
}
/* 学生信息区域样式 */
.student-info-section {
margin-bottom: 20px;
padding: 20px;
@@ -2041,6 +2177,7 @@ onMounted(() => {
border-bottom: 2px solid #409eff;
}
/* 批量审核相关样式 */
.batch-audit-info {
margin-bottom: 20px;
}
@@ -2069,6 +2206,17 @@ onMounted(() => {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
/* 其他辅助样式 */
.w-100 {
width: 100% !important;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 10px;
}
.selected-gender {
margin-top: 5px;
font-size: 12px;
@@ -2095,37 +2243,4 @@ onMounted(() => {
font-size: 14px;
color: #606266;
}
.gender-text-direct {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.boarding-text {
font-size: 14px;
color: #303133;
}
.college-name {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.college-code {
font-size: 14px;
color: #303133;
}
.major-name {
font-size: 14px;
color: #303133;
font-weight: 500;
}
.major-code {
font-size: 14px;
color: #303133;
}
</style>
+163 -97
View File
@@ -1,5 +1,5 @@
<template>
<div class="p-2 page-container">
<div class="page-container">
<!-- 搜索区域 -->
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
@@ -34,7 +34,7 @@
</el-col>
</el-row>
<!-- 第二行:日期筛选 + 操作按钮 -->
<!-- 第二行:日期筛选 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="签到日期">
@@ -50,8 +50,12 @@
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12" class="search-btn-container">
<el-form-item>
</el-row>
<!-- 第三行:搜索按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="24" class="search-btn-container">
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
@@ -120,35 +124,38 @@
</el-row>
</div>
<!-- 操作工具栏 -->
<el-card shadow="never" class="button-card">
<div class="card-header-vertical">
<div class="toolbar-title">实习日常管理</div>
<div class="button-group">
<el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipdaily:add']">新增签到</el-button>
<el-button plain icon="Search" @click="showSearch = !showSearch">搜索</el-button>
<el-button type="primary" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipdaily:export']">导出</el-button>
</div>
</div>
</el-card>
<!-- 表格数据 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<el-row ref="toolbarRef" :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipdaily:add']">新增签到</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipdaily:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<!-- 数据表格 -->
<el-card shadow="never" class="table-card">
<div class="table-container">
<el-table
ref="internshipDailyTableRef"
v-loading="loading"
border
:data="internshipDailyList"
row-key="id"
class="scroll-table"
@selection-change="handleSelectionChange"
style="width: 100%"
:scroll-x="true"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="学生信息" min-width="180" align="left">
<template #default="scope">
<div class=":liststudent-info">
<div class="student-info">
<div class="student-name">{{ scope.row.studentName }}</div>
<div class="student-number">学号:{{ scope.row.studentNumber }}</div>
<!-- <div class="student-class">班级:{{ scope.row.className }}</div> -->
@@ -176,27 +183,35 @@
<el-table-column label="签到地点" prop="checkInLocation" min-width="150" align="left" show-overflow-tooltip />
<el-table-column label="操作" width="120" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" width="160" align="center" class-name="small-padding fixed-width" fixed="right">
<template #default="scope">
<div class="action-buttons">
<el-tooltip content="查看详情" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" />
</el-tooltip>
<el-tooltip content="查看日历" placement="top">
<el-button link type="success" icon="Calendar" @click="handleCalendar(scope.row)" />
</el-tooltip>
</div>
<el-tooltip content="查看详情" placement="top">
<el-button
link
type="info"
icon="View"
@click="handleView(scope.row)"
></el-button>
</el-tooltip>
<el-tooltip content="查看日历" placement="top">
<el-button
link
type="success"
icon="Calendar"
@click="handleCalendar(scope.row)"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<div class="pagination-container">
<pagination v-show="total > 0" :total="total" :page="queryParams.pageNum" :limit="queryParams.pageSize" @pagination="getList" />
</div>
</el-card>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :page="queryParams.pageNum" :limit="queryParams.pageSize" :total="total" @pagination="getList" />
</div>
<!-- 详情对话框 -->
<el-dialog title="考勤详情" v-model="viewDialogVisible" width="600px" append-to-body>
<div v-if="currentRecord" class="detail-container">
@@ -615,47 +630,114 @@ onMounted(() => {
</script>
<style scoped lang="scss">
// 继承后勤管理的样式
/* 页面容器 */
.page-container {
.search-btn-container {
text-align: right;
padding: 8px;
}
/* 搜索按钮容器 */
.search-btn-container {
display: flex;
justify-content: flex-end;
margin-top: 10px;
.el-form-item {
margin-bottom: 0 !important;
}
}
.button-card {
margin-bottom: 20px;
/* 表格卡片 */
.button-card {
:deep(.el-card__header) {
border-bottom: none !important;
padding: 18px 20px 0 20px;
}
}
.card-header-vertical {
display: flex;
justify-content: space-between;
align-items: center;
/* 表格容器和滚动样式 */
.table-container {
overflow-x: auto;
overflow-y: hidden;
.scroll-table {
min-width: 100%;
/* 滚动条样式 */
:deep(.el-table__body-wrapper) {
&::-webkit-scrollbar {
height: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 4px;
&:hover {
background: #a8a8a8;
}
}
/* Firefox 滚动条 */
scrollbar-width: thin;
scrollbar-color: #c1c1c1 #f1f1f1;
}
.toolbar-title {
font-size: 18px;
font-weight: bold;
color: #303133;
/* 固定列阴影效果 */
:deep(.el-table__fixed) {
&::before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: -1px;
width: 30px;
pointer-events: none;
transition: box-shadow 0.3s;
}
}
.button-group {
display: flex;
align-items: center;
gap: 10px;
:deep(.el-table__fixed-right) {
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: -1px;
width: 30px;
pointer-events: none;
transition: box-shadow 0.3s;
}
}
/* 表格行悬停效果 */
:deep(.el-table__row) {
&:hover {
background-color: #f5f7fa;
.el-table__fixed .el-table__cell {
background-color: #f5f7fa;
}
.el-table__fixed-right .el-table__cell {
background-color: #f5f7fa;
}
}
}
}
}
.table-card {
.table-container {
overflow-x: auto;
}
.pagination-container {
display: flex;
justify-content: flex-end;
padding: 16px 20px 0 0 !important;
background-color: #fff;
margin-top: 0px !important;
}
}
/* 分页容器 */
.pagination-container {
display: flex;
justify-content: flex-end;
padding: 16px 20px 0 0 !important;
background-color: #fff;
margin-top: 0px !important;
}
/* 统计卡片样式 */
@@ -721,27 +803,6 @@ onMounted(() => {
}
}
/* 表格样式 */
.scroll-table {
:deep(.el-table__header-wrapper) {
.el-table__header {
th {
background-color: #f8f9fa;
color: #333;
font-weight: 600;
}
}
}
:deep(.el-table__body-wrapper) {
.el-table__row {
&:hover {
background-color: #f5f7fa;
}
}
}
}
/* 学生信息样式 */
.student-info {
.student-name {
@@ -772,14 +833,6 @@ onMounted(() => {
color: #909399;
}
/* 操作按钮样式 */
.action-buttons {
display: flex;
gap: 8px;
justify-content: center;
align-items: center;
}
/* 对话框样式 */
.dialog-footer-right {
display: flex;
@@ -831,15 +884,28 @@ onMounted(() => {
}
}
/* 描述列表样式优化 */
:deep(.el-descriptions) {
.el-descriptions__label {
font-weight: 600;
color: #606266;
width: 120px;
}
.el-descriptions__content {
color: #303133;
}
}
/* 按钮栏样式 */
.mb8 {
margin-bottom: 8px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.stat-card {
margin-bottom: 10px;
}
.action-buttons {
flex-direction: column;
gap: 4px;
}
}
</style>
+308 -168
View File
@@ -1,9 +1,11 @@
<template>
<div class="p-2 page-container">
<div class="page-container">
<!-- 搜索区域 -->
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" label-width="120px">
<!-- 第一行:4个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="学生姓名" prop="studentName">
@@ -30,13 +32,14 @@
</el-form-item>
</el-col>
</el-row>
<!-- 第二行:2个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="实习公司" prop="companyName">
<el-input v-model="queryParams.companyName" placeholder="请输入实习公司名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-col :span="6">
<el-form-item label="实习开始时间">
<el-date-picker
v-model="dateRange"
@@ -50,10 +53,10 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<!-- 搜索按钮行 -->
<el-row :gutter="10" class="mb8">
<el-col :span="24" class="search-btn-container">
<el-form-item>
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
@@ -115,82 +118,95 @@
</el-row>
</el-card>
<!-- 表格数据 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<el-row :gutter="10" class="mb8">
<el-row ref="toolbarRef" :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button icon="Download" @click="handleExport" v-hasPermi="['zsjy:internship:export']">导出</el-button>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internship:export']">导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="internshipList" @row-dblclick="handleView">
<el-table-column label="学号" align="center" prop="studentNo" width="120" />
<el-table-column label="姓名" align="center" prop="studentName" width="100" />
<el-table-column label="性别" align="center" prop="gender" width="80">
<template #default="scope">
<dict-tag :options="sys_user_sex" :value="scope.row.gender" />
</template>
</el-table-column>
<el-table-column label="班级" align="center" prop="className" width="180" />
<el-table-column label="班主任" align="center" prop="classTeacherName" width="100" />
<el-table-column label="实习状态" align="center" prop="internshipStatus" width="100">
<template #default="scope">
<span v-if="scope.row.internshipStatus === 'null' || !scope.row.internshipStatus" class="status-tag not-started">未实习</span>
<dict-tag v-else :options="internship_status" :value="scope.row.internshipStatus" />
</template>
</el-table-column>
<el-table-column label="实习公司" align="center" prop="companyName" min-width="150" show-overflow-tooltip />
<el-table-column label="实习岗位" align="center" prop="internshipPosition" width="120" show-overflow-tooltip />
<el-table-column label="实习开始时间" align="center" prop="internshipStartDate" width="120">
<template #default="scope">
<span v-if="scope.row.internshipStartDate">{{ parseTime(scope.row.internshipStartDate, '{y}-{m}-{d}') }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="实习地点" align="center" prop="companyAddress" width="120" show-overflow-tooltip />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template #default="scope">
<el-tooltip content="查看详情" placement="top">
<el-button
link
type="primary"
icon="View"
size="default"
@click="handleView(scope.row)"
v-hasPermi="['zsjy:internship:query']"
></el-button>
</el-tooltip>
<el-tooltip content="新增实习信息" placement="top" v-if="!scope.row.internshipId">
<el-button
link
type="success"
icon="Plus"
size="default"
@click="handleAdd(scope.row)"
v-hasPermi="['zsjy:internship:add']"
></el-button>
</el-tooltip>
<el-tooltip content="编辑实习信息" placement="top" v-if="scope.row.internshipId">
<el-button
link
type="warning"
icon="Edit"
size="default"
@click="handleEdit(scope.row)"
v-hasPermi="['zsjy:internship:edit']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<div class="pagination-container">
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
<div class="table-container">
<el-table
ref="internshipTableRef"
v-loading="loading"
border
:data="internshipList"
row-key="studentId"
class="scroll-table"
@row-dblclick="handleView"
style="width: 100%"
:scroll-x="true"
>
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="学号" align="center" prop="studentNo" width="120" />
<el-table-column label="姓名" align="center" prop="studentName" width="100" />
<el-table-column label="性别" align="center" prop="gender" width="80">
<template #default="scope">
<dict-tag :options="sys_user_sex" :value="scope.row.gender" />
</template>
</el-table-column>
<el-table-column label="班级" align="center" prop="className" width="180" />
<el-table-column label="班主任" align="center" prop="classTeacherName" width="100" />
<el-table-column label="实习状态" align="center" prop="internshipStatus" width="100">
<template #default="scope">
<span v-if="scope.row.internshipStatus === 'null' || !scope.row.internshipStatus" class="status-tag not-started">未实习</span>
<dict-tag v-else :options="internship_status" :value="scope.row.internshipStatus" />
</template>
</el-table-column>
<el-table-column label="实习公司" align="center" prop="companyName" min-width="150" show-overflow-tooltip />
<el-table-column label="实习岗位" align="center" prop="internshipPosition" width="120" show-overflow-tooltip />
<el-table-column label="实习开始时间" align="center" prop="internshipStartDate" width="120">
<template #default="scope">
<span v-if="scope.row.internshipStartDate">{{ parseTime(scope.row.internshipStartDate, '{y}-{m}-{d}') }}</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="实习地点" align="center" prop="companyAddress" width="120" show-overflow-tooltip />
<el-table-column label="操作" width="280" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看详情" placement="top">
<el-button
link
type="info"
icon="View"
@click="handleView(scope.row)"
v-hasPermi="['zsjy:internship:query']"
></el-button>
</el-tooltip>
<el-tooltip content="新增实习信息" placement="top" v-if="!scope.row.internshipId">
<el-button
link
type="success"
icon="Plus"
@click="handleAdd(scope.row)"
v-hasPermi="['zsjy:internship:add']"
></el-button>
</el-tooltip>
<el-tooltip content="编辑实习信息" placement="top" v-if="scope.row.internshipId">
<el-button
link
type="primary"
icon="Edit"
@click="handleEdit(scope.row)"
v-hasPermi="['zsjy:internship:edit']"
></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :page="queryParams.pageNum" :limit="queryParams.pageSize" :total="total" @pagination="getList" />
</div>
<!-- 学生实习详情对话框 -->
<el-dialog title="学生实习详情" v-model="dialog.visible" width="900px" append-to-body>
<div v-if="studentDetail" class="student-detail">
@@ -460,110 +476,234 @@ const cancel = () => {
})();
</script>
<style lang="scss" scoped>
<style scoped>
/* 页面容器样式 */
.page-container {
.search-btn-container {
text-align: right;
margin-top: 10px;
padding: 8px;
}
/* 表格卡片布局 */
.table-card {
margin-top: 0;
}
.table-card :deep(.el-card__body) {
padding: 0px 20px 20px 20px !important;
}
/* 表格容器 - 支持横向滚动 */
.table-container {
width: 100%;
margin-bottom: 0;
}
/* 横向滚动表格样式 */
.scroll-table {
width: 100%;
}
/* 表格横向滚动条样式优化 */
.scroll-table :deep(.el-table__body-wrapper) {
overflow-x: auto !important; /* 自动显示横向滚动条 */
overflow-y: auto;
}
.scroll-table :deep(.el-table__header-wrapper) {
overflow-x: hidden;
}
/* 强制显示表格横向滚动条 - 适用于所有浏览器 */
.scroll-table :deep(.el-table__body-wrapper) {
scrollbar-width: thin; /* Firefox */
scrollbar-color: #409eff #f0f0f0; /* Firefox - thumb track */
}
/* Webkit 浏览器的横向滚动条样式 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar {
height: 12px !important; /* 增加滚动条高度 */
width: 12px !important;
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-track {
background: #f0f0f0 !important;
border-radius: 6px !important;
border: 1px solid #e4e7ed !important; /* 添加边框使其更明显 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb {
background: #409eff !important; /* 使用主题色,更明显 */
border-radius: 6px !important;
border: 2px solid #f0f0f0 !important; /* 添加白色边框 */
min-height: 20px !important; /* 确保最小高度 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:hover {
background: #337ecc !important; /* 悬停时更深的蓝色 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:active {
background: #2b6cb0 !important; /* 点击时的颜色 */
}
/* 确保滚动条始终可见的额外设置 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-corner {
background: #f0f0f0;
}
/* 固定列样式优化 */
.scroll-table :deep(.el-table__fixed-right) {
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
}
.scroll-table :deep(.el-table__fixed-left) {
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
/* 确保固定列在滚动时有正确的背景色 */
.scroll-table :deep(.el-table__fixed-right .el-table__cell),
.scroll-table :deep(.el-table__fixed-left .el-table__cell) {
background-color: #fff;
}
/* 表格行悬停效果在固定列上的同步 */
.scroll-table :deep(.el-table__row:hover .el-table__cell) {
background-color: #f5f7fa !important;
}
/* 分页容器样式 */
.pagination-container {
display: flex;
justify-content: flex-end;
padding: 16px 20px 0 0 !important;
background-color: #fff;
margin-top: 0px !important;
}
/* 移除按钮栏底部边框 */
.button-card :deep(.el-card__header) {
border-bottom: none !important;
}
/* 对话框样式 */
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.dialog-form {
.el-form-item {
margin-bottom: 18px;
}
.statistics-row {
.statistics-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
color: white;
position: relative;
overflow: hidden;
height: 100px; /* 设置固定高度,确保所有卡片高度一致 */
.statistics-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center; /* 内容垂直居中 */
.statistics-number {
font-size: 28px;
font-weight: bold;
margin-bottom: 5px;
}
.statistics-label {
font-size: 14px;
opacity: 0.9;
}
.statistics-rate {
font-size: 12px;
opacity: 0.8;
margin-top: 2px;
}
.statistics-description {
font-size: 12px;
opacity: 0.8;
margin-top: 2px;
}
}
.statistics-icon {
font-size: 40px;
opacity: 0.8;
}
&.total-students {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
&.not-internship {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
&.internshiping {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
&.completed {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
}
}
.button-card {
.mb8 {
margin-bottom: 8px;
}
}
.table-card {
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
}
.student-detail {
.mt-4 {
margin-top: 20px;
}
}
.status-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
.form-tip {
font-size: 12px;
font-weight: 500;
color: #909399;
margin-top: 4px;
line-height: 1.4;
}
}
&.not-started {
background-color: #f56c6c;
color: white;
/* 描述列表样式优化 */
:deep(.el-descriptions) {
.el-descriptions__label {
font-weight: 600;
color: #606266;
width: 120px;
}
.el-descriptions__content {
color: #303133;
}
}
.search-btn-container {
display: flex;
justify-content: flex-end;
margin-top: 10px;
.el-form-item {
margin-bottom: 0 !important;
}
}
/* 统计卡片样式 */
.statistics-row {
.statistics-card {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
color: white;
position: relative;
overflow: hidden;
height: 100px; /* 设置固定高度,确保所有卡片高度一致 */
.statistics-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center; /* 内容垂直居中 */
.statistics-number {
font-size: 28px;
font-weight: bold;
margin-bottom: 5px;
}
.statistics-label {
font-size: 14px;
opacity: 0.9;
}
.statistics-description {
font-size: 12px;
opacity: 0.8;
margin-top: 2px;
}
}
.statistics-icon {
font-size: 40px;
opacity: 0.8;
}
&.total-students {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
&.not-internship {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
&.internshiping {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
&.completed {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
}
}
/* 状态标签样式 */
.status-tag {
display: inline-block;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
&.not-started {
background-color: #f56c6c;
color: white;
}
}
/* 按钮栏样式 */
.mb8 {
margin-bottom: 8px;
}
</style>
+234 -103
View File
@@ -34,8 +34,10 @@
<el-input-number v-model="queryParams.professionalSkills" :min="1" :max="10" placeholder="请输入专业技能评分" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item>
</el-row>
<el-row :gutter="10" class="mb8">
<el-col :span="24" class="search-btn-container">
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
@@ -46,95 +48,119 @@
</div>
</transition>
<!-- 操作按钮区域 -->
<el-card shadow="never">
<!-- 表格数据 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<el-row :gutter="10" class="mb8">
<el-row ref="toolbarRef" :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipmonthly:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['zsjy:internshipmonthly:edit']"
>修改</el-button
>
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleUpdate()"
v-hasPermi="['zsjy:internshipmonthly:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['zsjy:internshipmonthly:remove']"
>删除</el-button
>
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete()"
v-hasPermi="['zsjy:internshipmonthly:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipmonthly:export']">导出</el-button>
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['zsjy:internshipmonthly:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="monthlyList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="总结月份" align="center" prop="summaryMonth" width="120" />
<el-table-column label="工作内容" align="center" prop="workContent" :show-overflow-tooltip="true" min-width="200" />
<el-table-column label="综合评分" align="center" width="120">
<template #default="scope">
<el-tooltip content="专业/沟通/团队/学习/态度" placement="top">
<el-tag :type="getScoreTagType(getAverageScore(scope.row))"> {{ getAverageScore(scope.row).toFixed(1) }}分 </el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="字数统计" align="center" width="100">
<template #default="scope"> {{ scope.row.wordCount || 0 }}字 </template>
</el-table-column>
<el-table-column label="审核状态" align="center" prop="reviewStatus" width="100">
<template #default="scope">
<dict-tag :options="internship_monthly_status" :value="scope.row.reviewStatus" />
</template>
</el-table-column>
<el-table-column label="是否逾期" align="center" prop="isOverdue" width="100">
<template #default="scope">
<el-tag v-if="scope.row.isOverdue === 1" type="danger">逾期</el-tag>
<el-tag v-else type="success">正常</el-tag>
</template>
</el-table-column>
<el-table-column label="提交时间" align="center" prop="submitTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200" fixed="right">
<template #default="scope">
<!-- 查看详情 -->
<el-tooltip content="查看详情" placement="top">
<el-button link type="primary" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['zsjy:internshipmonthly:list']"></el-button>
</el-tooltip>
<div class="table-container">
<el-table
ref="monthlyTableRef"
v-loading="loading"
border
:data="monthlyList"
row-key="id"
class="scroll-table"
@selection-change="handleSelectionChange"
style="width: 100%"
:scroll-x="true"
>
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="总结月份" prop="summaryMonth" width="120" align="center" />
<el-table-column label="工作内容" prop="workContent" min-width="200" show-overflow-tooltip />
<el-table-column label="综合评分" width="120" align="center">
<template #default="scope">
<el-tooltip content="专业/沟通/团队/学习/态度" placement="top">
<el-tag :type="getScoreTagType(getAverageScore(scope.row))"> {{ getAverageScore(scope.row).toFixed(1) }}分 </el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="字数统计" width="100" align="center">
<template #default="scope"> {{ scope.row.wordCount || 0 }}字 </template>
</el-table-column>
<el-table-column label="审核状态" prop="reviewStatus" width="100" align="center">
<template #default="scope">
<dict-tag :options="internship_monthly_status" :value="scope.row.reviewStatus" />
</template>
</el-table-column>
<el-table-column label="是否逾期" prop="isOverdue" width="100" align="center">
<template #default="scope">
<el-tag v-if="scope.row.isOverdue === 1" type="danger">逾期</el-tag>
<el-tag v-else type="success">正常</el-tag>
</template>
</el-table-column>
<el-table-column label="提交时间" prop="submitTime" width="180" align="center">
<template #default="scope">
<span>{{ parseTime(scope.row.submitTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" width="180" align="center">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="操作" width="280" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="查看" placement="top">
<el-button link type="info" icon="View" @click="handleDetail(scope.row)" v-hasPermi="['zsjy:internshipmonthly:list']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:internshipmonthly:edit']"></el-button>
</el-tooltip>
<el-tooltip content="提交" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="success" icon="Check" @click="handleSubmit(scope.row)" v-hasPermi="['zsjy:internshipmonthly:submit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:internshipmonthly:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<!-- 编辑(只有草稿状态才能编辑) -->
<el-tooltip content="编辑" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:internshipmonthly:edit']"></el-button>
</el-tooltip>
<!-- 提交(只有草稿状态才能提交) -->
<el-tooltip content="提交" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="success" icon="Check" @click="handleSubmit(scope.row)" v-hasPermi="['zsjy:internshipmonthly:submit']"></el-button>
</el-tooltip>
<!-- 删除(只有草稿状态才能删除) -->
<el-tooltip content="删除" placement="top" v-if="scope.row.reviewStatus === 3">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:internshipmonthly:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :page="queryParams.pageNum" :limit="queryParams.pageSize" :total="total" @pagination="getList" />
</div>
<!-- 添加或修改月度总结对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1000px" append-to-body>
<MonthlyForm ref="monthlyFormRef" @success="getList" />
@@ -148,6 +174,9 @@
</template>
<script setup name="InternshipMonthly" lang="ts">
import { reactive, ref, toRefs, getCurrentInstance, nextTick, onMounted, type ComponentInternalInstance } from 'vue';
// import type { ElFormInstance, ComponentRef, DialogOption, PageData } from '@/types';
// import { parseTime } from '@/utils/ruoyi';
import {
listInternshipMonthly,
getInternshipMonthly,
@@ -169,12 +198,12 @@ const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const dialog = reactive<DialogOption>({
const dialog = reactive({
visible: false,
title: ''
});
const detailDialog = reactive<DialogOption>({
const detailDialog = reactive({
visible: false,
title: ''
});
@@ -186,7 +215,7 @@ const initFormData: any = {
reviewStatus: undefined,
professionalSkills: undefined
};
const data = reactive<PageData<any, any>>({
const data = reactive({
form: {},
queryParams: { ...initFormData },
rules: {}
@@ -194,9 +223,9 @@ const data = reactive<PageData<any, any>>({
const { queryParams, form, rules } = toRefs(data);
const queryFormRef = ref<ElFormInstance>();
const monthlyFormRef = ref<ComponentRef<typeof MonthlyForm>>();
const monthlyDetailRef = ref<ComponentRef<typeof MonthlyDetail>>();
const queryFormRef = ref();
const monthlyFormRef = ref();
const monthlyDetailRef = ref();
/** 查询月度总结列表 */
const getList = async () => {
@@ -307,44 +336,101 @@ const getScoreTagType = (score: number) => {
return 'danger';
};
/** 时间格式化函数 */
const parseTime = (time: any, pattern: string) => {
if (!time) return '';
const date = new Date(time);
const format = {
y: date.getFullYear(),
m: String(date.getMonth() + 1).padStart(2, '0'),
d: String(date.getDate()).padStart(2, '0'),
h: String(date.getHours()).padStart(2, '0'),
i: String(date.getMinutes()).padStart(2, '0'),
s: String(date.getSeconds()).padStart(2, '0')
};
return pattern.replace(/{([ymdhis])+}/g, (result, key) => {
return format[key as keyof typeof format] || result;
});
};
onMounted(() => {
getList();
});
</script>
<style scoped>
/* 操作按钮样式优化 - 参考后勤管理页面 */
:deep(.el-table__fixed-right) {
/* 页面容器样式 */
.page-container {
padding: 20px;
background-color: #f4f4f5;
min-height: calc(100vh - 84px);
}
/* 表格容器样式 */
.table-container {
overflow-x: auto;
position: relative;
}
/* 表格滚动条样式 */
.scroll-table :deep(.el-table__body-wrapper) {
scrollbar-width: thin; /* Firefox */
scrollbar-color: #409eff #f0f0f0; /* Firefox - thumb track */
}
/* Webkit 浏览器的横向滚动条样式 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar {
height: 12px !important; /* 增加滚动条高度 */
width: 12px !important;
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-track {
background: #f0f0f0 !important;
border-radius: 6px !important;
border: 1px solid #e4e7ed !important; /* 添加边框使其更明显 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb {
background: #409eff !important; /* 使用主题色,更明显 */
border-radius: 6px !important;
border: 2px solid #f0f0f0 !important; /* 添加白色边框 */
min-height: 20px !important; /* 确保最小高度 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:hover {
background: #337ecc !important; /* 悬停时更深的蓝色 */
}
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:active {
background: #2b6cb0 !important; /* 点击时的颜色 */
}
/* 确保滚动条始终可见的额外设置 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-corner {
background: #f0f0f0;
}
/* 固定列样式优化 */
.scroll-table :deep(.el-table__fixed-right) {
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
}
:deep(.el-table__fixed-right .el-table__cell) {
.scroll-table :deep(.el-table__fixed-left) {
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
/* 确保固定列在滚动时有正确的背景色 */
.scroll-table :deep(.el-table__fixed-right .el-table__cell),
.scroll-table :deep(.el-table__fixed-left .el-table__cell) {
background-color: #fff;
}
:deep(.el-table__row:hover .el-table__cell) {
/* 表格行悬停效果在固定列上的同步 */
.scroll-table :deep(.el-table__row:hover .el-table__cell) {
background-color: #f5f7fa !important;
}
/* 操作列按钮间距优化 */
.small-padding .el-button + .el-button {
margin-left: 8px;
}
/* 确保操作按钮在固定列中居中对齐 */
.small-padding {
text-align: center;
}
.small-padding .el-tooltip {
display: inline-block;
margin-right: 8px;
}
.small-padding .el-tooltip:last-child {
margin-right: 0;
}
/* 分页容器样式 */
.pagination-container {
display: flex;
@@ -353,4 +439,49 @@ onMounted(() => {
background-color: #fff;
margin-top: 0px !important;
}
/* 移除按钮栏底部边框 */
.button-card :deep(.el-card__header) {
border-bottom: none !important;
}
/* 搜索按钮容器样式 */
.search-btn-container {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.search-btn-container .el-form-item {
margin-bottom: 0 !important;
}
/* 对话框样式 */
.dialog-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.dialog-form .el-form-item {
margin-bottom: 18px;
}
.dialog-form .form-tip {
font-size: 12px;
color: #909399;
margin-top: 4px;
line-height: 1.4;
}
/* 描述列表样式优化 */
:deep(.el-descriptions .el-descriptions__label) {
font-weight: 600;
color: #606266;
width: 120px;
}
:deep(.el-descriptions .el-descriptions__content) {
color: #303133;
}
</style>
+218 -302
View File
@@ -1,91 +1,25 @@
<template>
<div class="app-container">
<!-- 统计卡片 -->
<el-row :gutter="16" class="stats-row">
<el-col :xl="6" :lg="12" :md="12" :sm="12" :xs="24">
<div class="stat-card total">
<div class="stat-icon">
<el-icon><User /></el-icon>
</div>
<div class="stat-content">
<div class="stat-number">{{ statistics.total }}</div>
<div class="stat-label">走访总数</div>
</div>
</div>
</el-col>
<el-col :xl="6" :lg="12" :md="12" :sm="12" :xs="24">
<div class="stat-card month">
<div class="stat-icon">
<el-icon><Calendar /></el-icon>
</div>
<div class="stat-content">
<div class="stat-number">{{ statistics.monthCount }}</div>
<div class="stat-label">本月走访</div>
</div>
</div>
</el-col>
<el-col :xl="6" :lg="12" :md="12" :sm="12" :xs="24">
<div class="stat-card completed">
<div class="stat-icon">
<el-icon><CircleCheck /></el-icon>
</div>
<div class="stat-content">
<div class="stat-number">{{ statistics.completedCount }}</div>
<div class="stat-label">已完成</div>
</div>
</div>
</el-col>
<el-col :xl="6" :lg="12" :md="12" :sm="12" :xs="24">
<div class="stat-card pending">
<div class="stat-icon">
<el-icon><Clock /></el-icon>
</div>
<div class="stat-content">
<div class="stat-number">{{ statistics.pendingCount }}</div>
<div class="stat-label">待走访</div>
</div>
</div>
</el-col>
</el-row>
<div class="page-container">
<!-- 搜索区域 -->
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" label-width="100px">
<!-- 搜索条件 -->
<!-- 第一行:4个搜索条件 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="学生信息" prop="studentName">
<el-input
v-model="queryParams.studentName"
placeholder="请输入学生姓名或学号"
clearable
style="width: 100%"
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名或学号" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实习单位" prop="companyName">
<el-input
v-model="queryParams.companyName"
placeholder="请输入实习单位名称"
clearable
style="width: 100%"
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.companyName" placeholder="请输入实习单位名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="走访人" prop="visitorName">
<el-input
v-model="queryParams.visitorName"
placeholder="请输入走访人姓名"
clearable
style="width: 100%"
@keyup.enter="handleQuery"
/>
<el-input v-model="queryParams.visitorName" placeholder="请输入走访人姓名" clearable @keyup.enter="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="6">
@@ -97,30 +31,31 @@
</el-col>
</el-row>
<!-- 第二行:日期范围 + 操作按钮 -->
<!-- 第二行:1个搜索条件 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="走访日期" prop="visitDateRange">
<el-form-item label="走访日期">
<el-date-picker
v-model="queryParams.visitDateRange"
value-format="YYYY-MM-DD"
type="daterange"
range-separator="至"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
@change="handleQuery"
style="width: 100%"
/>
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<div class="search-btn-container">
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-row>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch"> {{ showSearch ? '隐藏' : '显示' }}搜索 </el-button>
</el-form-item>
</div>
<!-- 第三行:搜索按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="24" class="search-btn-container">
<el-form-item style="margin-bottom: 0;">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
@@ -128,37 +63,59 @@
</div>
</transition>
<!-- 操作按钮栏 -->
<el-card shadow="hover" class="button-card">
<!-- 表格数据 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<div class="card-header-vertical">
<div class="toolbar-title">班主任走访列表</div>
<div class="button-group">
<el-row ref="toolbarRef" :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['zsjy:internshipVisit:add']">新增走访</el-button>
<el-button type="success" plain icon="Download" @click="handleExport" v-hasPermi="['zsjy:internshipVisit:export']">导出</el-button>
<el-button type="info" plain icon="Search" @click="showSearch = !showSearch"> {{ showSearch ? '隐藏' : '显示' }}搜索 </el-button>
<el-tooltip content="刷新" placement="top">
<el-button icon="Refresh" circle @click="getList" />
</el-tooltip>
</div>
</div>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="single"
@click="handleBatchUpdate"
v-hasPermi="['zsjy:internshipVisit:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleBatchDelete"
v-hasPermi="['zsjy:internshipVisit:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Download"
@click="handleExport"
v-hasPermi="['zsjy:internshipVisit:export']"
>导出</el-button>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
</el-card>
<!-- 数据表格 -->
<el-card shadow="hover" class="table-card">
<div class="table-container">
<el-table
ref="visitTableRef"
v-loading="loading"
border
:data="visitList"
row-key="visitId"
border
stripe
highlight-current-row
class="scroll-table"
@selection-change="handleSelectionChange"
style="width: 100%"
:scroll-x="true"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column type="selection" width="55" align="center" fixed="left" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column label="学生信息" min-width="150" align="left">
<template #default="scope">
<div class="student-info">
@@ -168,53 +125,45 @@
</div>
</template>
</el-table-column>
<el-table-column label="实习单位" prop="companyName" min-width="150" align="left" show-overflow-tooltip />
<el-table-column label="走访人" prop="visitorName" min-width="100" align="center" />
<el-table-column label="走访日期" prop="visitDate" min-width="120" align="center">
<template #default="scope">
{{ parseTime(scope.row.visitDate, '{y}-{m}-{d}') }}
</template>
</el-table-column>
<el-table-column label="走访状态" prop="status" min-width="100" align="center">
<template #default="scope">
<dict-tag :options="visitStatusOptions" :value="scope.row.status || ''" />
</template>
</el-table-column>
<el-table-column label="创建时间" prop="createTime" min-width="160" align="center">
<template #default="scope">
{{ parseTime(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width">
<el-table-column label="操作" width="180" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<div class="action-buttons">
<el-tooltip content="查看详情" placement="top">
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['zsjy:internshipVisit:query']" />
</el-tooltip>
<el-tooltip content="编辑" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:internshipVisit:edit']" />
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:internshipVisit:remove']" />
</el-tooltip>
</div>
<el-tooltip content="查看" placement="top">
<el-button link type="info" icon="View" @click="handleView(scope.row)" v-hasPermi="['zsjy:internshipVisit:query']"></el-button>
</el-tooltip>
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['zsjy:internshipVisit:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="danger" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['zsjy:internshipVisit:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页组件 -->
<div class="pagination-container">
<pagination v-show="total > 0" :total="total" :page="queryParams.pageNum" :limit="queryParams.pageSize" @pagination="getList" />
</div>
</el-card>
<!-- 分页 -->
<div class="pagination-container">
<pagination v-show="total > 0" :page="queryParams.pageNum" :limit="queryParams.pageSize" :total="total" @pagination="getList" />
</div>
<!-- 详情对话框 -->
<el-dialog title="走访详情" v-model="viewDialogVisible" width="800px" append-to-body>
<div v-if="currentRecord" class="detail-container">
@@ -386,13 +335,7 @@ const viewDialogVisible = ref(false);
const formDialogVisible = ref(false);
const currentRecord = ref(null);
// 统计数据
const statistics = ref({
total: 0,
monthCount: 0,
completedCount: 0,
pendingCount: 0
});
// 字典数据
const visitStatusOptions = ref([]);
@@ -495,8 +438,6 @@ function getList() {
}
loading.value = false;
// 计算统计数据
calculateStatistics();
})
.catch((error) => {
console.error('获取走访记录列表失败:', error);
@@ -508,18 +449,7 @@ function getList() {
});
}
/** 计算统计数据 */
function calculateStatistics() {
const now = new Date();
const currentMonth = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0');
statistics.value = {
total: visitList.value.length,
monthCount: visitList.value.filter((item) => item.visitDate && item.visitDate.startsWith(currentMonth)).length,
completedCount: visitList.value.filter((item) => item.status === '2').length, // 2-已审核
pendingCount: visitList.value.filter((item) => item.status === '0').length // 0-草稿
};
}
/** 搜索按钮操作 */
function handleQuery() {
@@ -605,6 +535,34 @@ function submitForm() {
});
}
/** 批量修改按钮操作 */
function handleBatchUpdate() {
if (ids.value.length === 1) {
// 单个修改,直接调用修改方法
const visitId = ids.value[0];
const row = visitList.value.find(item => item.visitId === visitId);
if (row) {
handleUpdate(row);
}
} else {
ElMessage.warning('请选择一条记录进行修改');
}
}
/** 批量删除按钮操作 */
function handleBatchDelete() {
const visitIds = ids.value;
ElMessageBox.confirm('是否确认删除选中的' + visitIds.length + '条走访记录?')
.then(function () {
return delInternshipVisit(visitIds);
})
.then(() => {
getList();
ElMessage.success('删除成功');
})
.catch(() => {});
}
/** 删除按钮操作 */
function handleDelete(row) {
const visitIds = row.visitId || ids.value;
@@ -819,177 +777,124 @@ onMounted(() => {
</script>
<style scoped>
/* 搜索按钮容器样式 */
.search-btn-container {
display: flex;
justify-content: flex-end;
align-items: center;
height: 100%;
/* 页面容器样式 */
.page-container {
padding: 8px;
}
/* 按钮卡片样式 */
.button-card {
margin-bottom: 16px;
/* 表格卡片布局 */
.table-card {
margin-top: 0;
}
.form-item-tip {
font-size: 12px;
color: #909399;
line-height: 1.4;
margin-top: 4px;
.table-card :deep(.el-card__body) {
padding: 0px 20px 20px 20px !important;
}
.card-header-vertical {
display: flex;
justify-content: space-between;
align-items: center;
/* 表格容器 - 支持横向滚动 */
.table-container {
width: 100%;
margin-bottom: 0;
}
/* 横向滚动表格样式 */
.scroll-table {
width: 100%;
}
.toolbar-title {
font-size: 16px;
font-weight: 600;
color: #303133;
/* 表格横向滚动条样式优化 */
.scroll-table :deep(.el-table__body-wrapper) {
overflow-x: auto !important; /* 自动显示横向滚动条 */
overflow-y: auto;
}
.button-group {
display: flex;
gap: 8px;
align-items: center;
.scroll-table :deep(.el-table__header-wrapper) {
overflow-x: hidden;
}
.table-card {
margin-bottom: 16px;
/* 强制显示表格横向滚动条 - 适用于所有浏览器 */
.scroll-table :deep(.el-table__body-wrapper) {
scrollbar-width: thin; /* Firefox */
scrollbar-color: #409eff #f0f0f0; /* Firefox - thumb track */
}
/* 统计卡片样式 */
.stats-row {
margin-bottom: 20px;
/* Webkit 浏览器的横向滚动条样式 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar {
height: 12px !important; /* 增加滚动条高度 */
width: 12px !important;
}
.stat-card {
background: white;
border-radius: 8px;
padding: 20px;
display: flex;
align-items: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
margin-bottom: 16px;
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-track {
background: #f0f0f0 !important;
border-radius: 6px !important;
border: 1px solid #e4e7ed !important; /* 添加边框使其更明显 */
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb {
background: #409eff !important; /* 使用主题色,更明显 */
border-radius: 6px !important;
border: 2px solid #f0f0f0 !important; /* 添加白色边框 */
min-height: 20px !important; /* 确保最小高度 */
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16px;
font-size: 24px;
color: white;
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:hover {
background: #337ecc !important; /* 悬停时更深的蓝色 */
}
.stat-card.total .stat-icon {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-thumb:active {
background: #2b6cb0 !important; /* 点击时的颜色 */
}
.stat-card.month .stat-icon {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
/* 确保滚动条始终可见的额外设置 */
.scroll-table :deep(.el-table__body-wrapper)::-webkit-scrollbar-corner {
background: #f0f0f0;
}
.stat-card.completed .stat-icon {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
/* 固定列样式优化 */
.scroll-table :deep(.el-table__fixed-right) {
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
}
.stat-card.pending .stat-icon {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
.scroll-table :deep(.el-table__fixed-left) {
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
}
.stat-content {
flex: 1;
/* 确保固定列在滚动时有正确的背景色 */
.scroll-table :deep(.el-table__fixed-right .el-table__cell),
.scroll-table :deep(.el-table__fixed-left .el-table__cell) {
background-color: #fff;
}
.stat-number {
font-size: 28px;
font-weight: bold;
color: #303133;
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: #909399;
}
/* 主卡片样式 */
.main-card {
margin-top: 20px;
}
.main-card .el-card__body {
padding: 20px;
}
/* 搜索容器样式 */
.search-container {
background: #f8f9fa;
padding: 16px;
border-radius: 6px;
margin-bottom: 16px;
}
/* 工具栏样式 */
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding: 0 4px;
}
.toolbar-left {
display: flex;
gap: 12px;
}
.toolbar-right {
display: flex;
gap: 8px;
}
/* 表格容器样式 */
.table-container {
border-radius: 6px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.el-table {
border-radius: 6px;
}
.el-table th {
background-color: #f5f7fa;
color: #606266;
font-weight: 600;
}
.el-table .el-table__row:hover {
background-color: #f5f7fa;
/* 表格行悬停效果在固定列上的同步 */
.scroll-table :deep(.el-table__row:hover .el-table__cell) {
background-color: #f5f7fa !important;
}
/* 分页容器样式 */
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
padding: 16px 0;
justify-content: flex-end;
padding: 16px 20px 0 0 !important;
background-color: #fff;
margin-top: 0px !important;
}
/* 移除按钮栏底部边框 */
.button-card :deep(.el-card__header) {
border-bottom: none !important;
}
/* 搜索按钮容器样式 */
.search-btn-container {
display: flex;
justify-content: flex-end;
margin-top: 10px;
.el-form-item {
margin-bottom: 0 !important;
}
}
/* 学生信息样式 */
@@ -1008,12 +913,12 @@ onMounted(() => {
}
}
/* 操作按钮样式 */
.action-buttons {
display: flex;
gap: 8px;
justify-content: center;
align-items: center;
/* 表单提示样式 */
.form-item-tip {
font-size: 12px;
color: #909399;
line-height: 1.4;
margin-top: 4px;
}
/* 对话框样式 */
@@ -1023,6 +928,32 @@ onMounted(() => {
gap: 10px;
}
.dialog-form {
.el-form-item {
margin-bottom: 18px;
}
.form-tip {
font-size: 12px;
color: #909399;
margin-top: 4px;
line-height: 1.4;
}
}
/* 描述列表样式优化 */
:deep(.el-descriptions) {
.el-descriptions__label {
font-weight: 600;
color: #606266;
width: 120px;
}
.el-descriptions__content {
color: #303133;
}
}
/* 详情容器样式 */
.detail-container {
padding: 8px 0;
@@ -1030,21 +961,6 @@ onMounted(() => {
/* 响应式设计 */
@media (max-width: 768px) {
.stat-card {
margin-bottom: 10px;
}
.toolbar {
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.toolbar-left,
.toolbar-right {
justify-content: center;
}
.action-buttons {
flex-direction: column;
gap: 4px;