提交代码
This commit is contained in:
1 parent
b7122b6b67
commit
8757ffc6df
6 files changed
+1469
-6
No files matched your search
+15
@@ -1,7 +1,10 @@
|
||||
package org.dromara.xskh.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.xskh.domain.XskhRewardRecord;
|
||||
import org.dromara.xskh.domain.bo.XskhRewardRecordBo;
|
||||
import org.dromara.xskh.domain.vo.XskhRewardRecordVo;
|
||||
import org.dromara.xskh.domain.vo.XskhStudentOptionVo;
|
||||
|
||||
@@ -22,4 +25,16 @@ public interface XskhRewardRecordMapper extends BaseMapperPlus<XskhRewardRecord,
|
||||
* @return 学生选项列表
|
||||
*/
|
||||
List<XskhStudentOptionVo> selectStudentOptions(String keyword);
|
||||
|
||||
/**
|
||||
* 查询班主任班级的奖励记录列表(班主任专用)
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param bo 查询条件
|
||||
* @param classTeacherId 班主任ID
|
||||
* @return 分页查询结果
|
||||
*/
|
||||
Page<XskhRewardRecordVo> selectClassTeacherVoPage(@Param("page") Page<XskhRewardRecordVo> page,
|
||||
@Param("bo") XskhRewardRecordBo bo,
|
||||
@Param("classTeacherId") Long classTeacherId);
|
||||
}
|
||||
+36
-5
@@ -10,6 +10,7 @@ import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.xskh.domain.bo.XskhRewardRecordBo;
|
||||
import org.dromara.xskh.domain.vo.XskhRewardRecordVo;
|
||||
@@ -172,8 +173,36 @@ public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XskhRewardRecordVo> queryMyPageList(XskhRewardRecordBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<XskhRewardRecord> lqw = buildQueryWrapper(bo);
|
||||
// TODO: 添加当前登录学生ID的查询条件
|
||||
// 获取当前登录用户的学生ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 构建查询条件,强制只查询当前学生的记录
|
||||
LambdaQueryWrapper<XskhRewardRecord> lqw = Wrappers.lambdaQuery();
|
||||
|
||||
// 通过当前登录用户ID查询对应的学生记录
|
||||
lqw.eq(XskhRewardRecord::getStudentId, currentUserId);
|
||||
|
||||
// 可选的其他查询条件(保持原有的查询逻辑,但学生ID已固定)
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), XskhRewardRecord::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XskhRewardRecord::getStudentName, bo.getStudentName());
|
||||
lqw.eq(bo.getCollegeId() != null, XskhRewardRecord::getCollegeId, bo.getCollegeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XskhRewardRecord::getCollegeName, bo.getCollegeName());
|
||||
lqw.eq(bo.getMajorId() != null, XskhRewardRecord::getMajorId, bo.getMajorId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XskhRewardRecord::getMajorName, bo.getMajorName());
|
||||
lqw.eq(bo.getClassId() != null, XskhRewardRecord::getClassId, bo.getClassId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassName()), XskhRewardRecord::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getRewardTypeId() != null, XskhRewardRecord::getRewardTypeId, bo.getRewardTypeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRewardTypeName()), XskhRewardRecord::getRewardTypeName,
|
||||
bo.getRewardTypeName());
|
||||
lqw.eq(bo.getRewardDate() != null, XskhRewardRecord::getRewardDate, bo.getRewardDate());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getRewardContent()), XskhRewardRecord::getRewardContent,
|
||||
bo.getRewardContent());
|
||||
lqw.eq(bo.getScoreAddition() != null, XskhRewardRecord::getScoreAddition, bo.getScoreAddition());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), XskhRewardRecord::getStatus, bo.getStatus());
|
||||
|
||||
// 按创建时间倒序排列
|
||||
lqw.orderByDesc(XskhRewardRecord::getCreateTime);
|
||||
|
||||
Page<XskhRewardRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
@@ -187,9 +216,11 @@ public class XskhRewardRecordServiceImpl implements IXskhRewardRecordService {
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XskhRewardRecordVo> queryClassTeacherPageList(XskhRewardRecordBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<XskhRewardRecord> lqw = buildQueryWrapper(bo);
|
||||
// TODO: 添加班主任班级的查询条件
|
||||
Page<XskhRewardRecordVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
// 获取当前登录用户ID(班主任ID)
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 调用mapper中的专用查询方法
|
||||
Page<XskhRewardRecordVo> result = baseMapper.selectClassTeacherVoPage(pageQuery.build(), bo, currentUserId);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
}
|
||||
+30
@@ -101,4 +101,34 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
limit 50
|
||||
</select>
|
||||
|
||||
<select id="selectClassTeacherVoPage" resultType="XskhRewardRecordVo">
|
||||
select rr.id, rr.student_id, rr.student_no, rr.student_name, rr.college_id, rr.college_name,
|
||||
rr.major_id, rr.major_name, rr.class_id, rr.class_name, rr.reward_type_id,
|
||||
rr.reward_type_name, rr.reward_date, rr.reward_content, rr.score_addition,
|
||||
rr.attachment_oss_ids, rr.status, rr.create_by, rr.create_time, rr.create_dept,
|
||||
rr.update_by, rr.update_time, rr.deleted, rr.tenant_id
|
||||
from xskh_reward_record rr
|
||||
where rr.deleted = 0
|
||||
and rr.student_id in (
|
||||
select sm.id
|
||||
from xg_student_msg sm
|
||||
inner join xg_class_msg cm on sm.class_id = cm.id
|
||||
where cm.deleted = 0
|
||||
and cm.class_status = 1
|
||||
and cm.class_teacher_id = #{classTeacherId}
|
||||
and sm.deleted = 0
|
||||
and sm.student_status = 1
|
||||
)
|
||||
<if test="bo.studentNo != null and bo.studentNo != ''">
|
||||
and rr.student_no like concat('%', #{bo.studentNo}, '%')
|
||||
</if>
|
||||
<if test="bo.studentName != null and bo.studentName != ''">
|
||||
and rr.student_name like concat('%', #{bo.studentName}, '%')
|
||||
</if>
|
||||
<if test="bo.status != null and bo.status != ''">
|
||||
and rr.status = #{bo.status}
|
||||
</if>
|
||||
order by rr.create_time desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -1,6 +1,7 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { XskhRewardRecordVo, XskhRewardRecordBo, XskhRewardRecordQuery, XskhRewardRecordForm } from './types';
|
||||
import { TableDataInfo, R } from '@/api/types';
|
||||
import { XskhRewardRecordVo, XskhRewardRecordBo, XskhRewardRecordQuery, XskhRewardRecordForm, XskhStudentOptionVO } from './types';
|
||||
|
||||
/**
|
||||
* 查询学生奖励记录列表
|
||||
@@ -90,3 +91,29 @@ export function getStudentOptions(keyword?: string): AxiosPromise<R<XskhStudentO
|
||||
params: { keyword }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前登录学生的奖励记录列表
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
export function listMyRewardRecords(query: XskhRewardRecordQuery): AxiosPromise<TableDataInfo<XskhRewardRecordVo>> {
|
||||
return request({
|
||||
url: '/rewardRecord/rewardRecord/my',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询班主任班级的奖励记录列表(班主任专用)
|
||||
* @param query
|
||||
* @returns
|
||||
*/
|
||||
export function listClassTeacherRewardRecords(query: XskhRewardRecordQuery): AxiosPromise<TableDataInfo<XskhRewardRecordVo>> {
|
||||
return request({
|
||||
url: '/rewardRecord/rewardRecord/classTeacherList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,676 @@
|
||||
<template>
|
||||
<div class="p-2 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">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option v-for="dict in student_reward_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" 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>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<span class="text-lg font-medium">班级奖励记录列表</span>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch="showSearch" @update:showSearch="showSearch = $event" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="rewardRecordList" class="full-width-table">
|
||||
<el-table-column label="学号" align="center" prop="studentNo" min-width="120" />
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" min-width="100" />
|
||||
<el-table-column label="学院名称" align="center" prop="collegeName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="专业名称" align="center" prop="majorName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="班级名称" align="center" prop="className" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="奖励类型" align="center" prop="rewardTypeName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="奖励日期" align="center" prop="rewardDate" min-width="130" />
|
||||
<el-table-column label="加分分值" align="center" prop="scoreAddition" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.scoreAddition ? parseFloat(scope.row.scoreAddition).toFixed(2) : '0.00' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" min-width="80">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="student_reward_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['rewardRecord:classTeacher:list']"></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>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1000px" append-to-body destroy-on-close>
|
||||
<el-form :model="form" label-width="120px" readonly>
|
||||
<el-row :gutter="20">
|
||||
<!-- 左列:学生基本信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学号">
|
||||
<div class="student-display">
|
||||
<span class="student-no-text">{{ form.studentNo }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="学生姓名">
|
||||
<div class="student-display">
|
||||
<span class="student-name-text">{{ form.studentName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="学院名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.collegeName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.majorName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.className }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 右列:奖励信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="奖励类型">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.rewardTypeName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="奖励日期">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.rewardDate }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="加分分值">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.scoreAddition ? parseFloat(form.scoreAddition).toFixed(2) : '0.00' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<dict-tag :options="student_reward_status" :value="form.status" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.createTime }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 完整宽度的字段 -->
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="奖励内容">
|
||||
<div class="content-display">
|
||||
<span class="content-text">{{ form.rewardContent || '暂无内容' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 附件展示区域 -->
|
||||
<el-row v-if="attachmentList.length > 0">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="附件">
|
||||
<div class="attachment-upload-container">
|
||||
<div class="upload-demo">
|
||||
<div class="attachment-view-grid">
|
||||
<div v-for="file in attachmentList" :key="file.uid" class="upload-file-card">
|
||||
<!-- 缩略图区域 -->
|
||||
<div class="upload-file-thumb">
|
||||
<image-preview v-if="isImageFile(file) && file.url" :src="getFileOssId(file)" class="upload-thumb-image" :isOssId="true" />
|
||||
<div v-else class="upload-file-placeholder">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span class="file-ext">{{ getFileExt(file.name) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文件名称 -->
|
||||
<div class="upload-file-name" :title="file.name">
|
||||
{{ getShortFileName(file.name) }}
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区域 - 查看模式只显示下载按钮 -->
|
||||
<div class="upload-file-card-actions">
|
||||
<el-button type="success" size="small" @click.stop="handleDownloadAttachment(file)" title="下载">
|
||||
<el-icon><Download /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ClassTeacherRewardRecord" lang="ts">
|
||||
import { ref, reactive, toRefs, onMounted, getCurrentInstance, ComponentInternalInstance } from 'vue';
|
||||
import { Document, Download } from '@element-plus/icons-vue';
|
||||
import { ElMessage, ElLoading } from 'element-plus';
|
||||
import ImagePreview from '@/components/ImagePreview/index.vue';
|
||||
import request from '@/utils/request';
|
||||
import { listClassTeacherRewardRecords, getRewardRecord } from '@/api/xskh/rewardRecord/rewardRecord';
|
||||
import type { XskhRewardRecordVo, XskhRewardRecordQuery } from '@/api/xskh/rewardRecord/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { student_reward_status } = toRefs<any>(proxy?.useDict('student_reward_status'));
|
||||
|
||||
const rewardRecordList = ref<XskhRewardRecordVo[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
// 附件相关状态
|
||||
const attachmentList = ref<any[]>([]);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: XskhRewardRecordVo = {
|
||||
id: undefined,
|
||||
studentId: undefined,
|
||||
studentNo: undefined,
|
||||
studentName: undefined,
|
||||
collegeId: undefined,
|
||||
collegeName: undefined,
|
||||
majorId: undefined,
|
||||
majorName: undefined,
|
||||
classId: undefined,
|
||||
className: undefined,
|
||||
rewardTypeId: undefined,
|
||||
rewardTypeName: undefined,
|
||||
rewardDate: undefined,
|
||||
rewardContent: undefined,
|
||||
scoreAddition: undefined,
|
||||
attachmentOssIds: undefined,
|
||||
status: undefined
|
||||
};
|
||||
|
||||
const data = reactive<PageData<XskhRewardRecordVo, XskhRewardRecordQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentId: undefined,
|
||||
studentNo: undefined,
|
||||
studentName: undefined,
|
||||
collegeId: undefined,
|
||||
collegeName: undefined,
|
||||
majorId: undefined,
|
||||
majorName: undefined,
|
||||
classId: undefined,
|
||||
className: undefined,
|
||||
rewardTypeId: undefined,
|
||||
rewardTypeName: undefined,
|
||||
rewardDate: undefined,
|
||||
rewardContent: undefined,
|
||||
scoreAddition: undefined,
|
||||
status: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询班级奖励记录列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listClassTeacherRewardRecords(queryParams.value);
|
||||
rewardRecordList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 查看详情 */
|
||||
const handleView = async (row: XskhRewardRecordVo) => {
|
||||
reset();
|
||||
const id = row.id;
|
||||
try {
|
||||
const res = await getRewardRecord(id);
|
||||
Object.assign(form.value, res.data || res);
|
||||
|
||||
// 处理附件数据
|
||||
await handleAttachmentData();
|
||||
|
||||
dialog.visible = true;
|
||||
dialog.title = '查看奖励记录详情';
|
||||
} catch (error) {
|
||||
console.error('获取奖励记录详情失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 文件处理相关方法(从RewardRecordForm复制)
|
||||
const isImageFile = (file: any) => {
|
||||
const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
|
||||
return imageTypes.includes(file.raw?.type) || (file.url && /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name));
|
||||
};
|
||||
|
||||
const getFileOssId = (file: any) => {
|
||||
return file.ossId || '';
|
||||
};
|
||||
|
||||
const getFileExt = (fileName: string) => {
|
||||
const ext = fileName.split('.').pop()?.toUpperCase();
|
||||
return ext || 'FILE';
|
||||
};
|
||||
|
||||
const getShortFileName = (fileName: string) => {
|
||||
if (!fileName) return '';
|
||||
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
if (lastDotIndex === -1) {
|
||||
return fileName.length > 12 ? fileName.substring(0, 12) + '...' : fileName;
|
||||
}
|
||||
|
||||
const name = fileName.substring(0, lastDotIndex);
|
||||
const ext = fileName.substring(lastDotIndex);
|
||||
|
||||
if (name.length <= 8) {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
return name.substring(0, 8) + '...' + ext;
|
||||
};
|
||||
|
||||
const handleDownloadAttachment = async (file: any) => {
|
||||
// 下载文件逻辑(参考RewardRecordForm)
|
||||
let downloadUrl = '';
|
||||
let fileName = file.name || 'attachment';
|
||||
|
||||
if (file.response && file.response.data && file.response.data.filePath) {
|
||||
downloadUrl = file.response.data.filePath;
|
||||
fileName = file.response.data.fileName || fileName;
|
||||
} else if (file.ossId) {
|
||||
downloadUrl = file.ossId;
|
||||
} else if (file.raw) {
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(file.raw);
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!downloadUrl) {
|
||||
console.error('无法获取文件下载地址');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
text: '正在下载文件...',
|
||||
target: document.body
|
||||
});
|
||||
|
||||
const response = await request({
|
||||
url: '/resource/oss/download/' + downloadUrl,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
});
|
||||
|
||||
if (!response) {
|
||||
throw new Error('响应数据为空');
|
||||
}
|
||||
|
||||
let blobData: Blob;
|
||||
if (response instanceof Blob) {
|
||||
blobData = response;
|
||||
} else if (response.data instanceof Blob) {
|
||||
blobData = response.data;
|
||||
} else {
|
||||
throw new Error('无效的响应数据格式');
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(blobData);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
loading?.close();
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAttachmentData = async () => {
|
||||
try {
|
||||
if (!form.value.attachmentOssIds || !form.value.attachmentOssIds.toString().trim()) {
|
||||
attachmentList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const ossIdsArray = form.value.attachmentOssIds
|
||||
.toString()
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id);
|
||||
|
||||
if (ossIdsArray.length === 0) {
|
||||
attachmentList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await request({
|
||||
url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const attachmentFiles = response.data.map((item: any, index: number) => ({
|
||||
uid: `existing_${index}_${Date.now()}`,
|
||||
name: item.originalName || `附件${index + 1}`,
|
||||
url: item.url,
|
||||
ossId: item.ossId,
|
||||
status: 'success',
|
||||
response: {
|
||||
code: 200,
|
||||
data: {
|
||||
url: item.url,
|
||||
ossId: item.ossId
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
attachmentList.value = attachmentFiles;
|
||||
} else {
|
||||
attachmentList.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('处理附件数据失败:', error);
|
||||
attachmentList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
/* 搜索按钮区域右对齐 */
|
||||
.search-btn-container {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.full-width-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 表格内容区域充满宽度 */
|
||||
:deep(.el-table__body-wrapper) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 查看模式下的学生信息显示 */
|
||||
.student-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 11px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.student-name-text {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.student-no-text {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.student-info-text {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* 内容展示区域 */
|
||||
.content-display {
|
||||
padding: 8px 11px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
min-height: 80px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
color: #303133;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 附件上传容器样式 */
|
||||
.attachment-upload-container {
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 650px);
|
||||
min-height: 200px;
|
||||
overflow-y: auto;
|
||||
padding-right: 8px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 6px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* 附件上传区域内容样式 */
|
||||
.attachment-upload-container .upload-demo {
|
||||
padding: 12px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
/* 查看模式下的附件网格展示 */
|
||||
.attachment-view-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 9px;
|
||||
margin-top: 12px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 文件卡片样式 */
|
||||
.upload-file-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-file-card:hover {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.upload-file-thumb {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 110px;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-thumb-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 文件卡片占位封面样式 */
|
||||
.upload-file-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.upload-file-placeholder .el-icon {
|
||||
font-size: 28px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.upload-file-placeholder .file-ext {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.upload-file-name {
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
line-height: 1.2;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-all;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.upload-file-card-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 6px 8px;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
transition: all 0.3s;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.upload-file-card-actions .el-button {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #e0e0e0;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-file-card-actions .el-button:hover {
|
||||
background: #f5f5f5;
|
||||
border-color: #409eff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,684 @@
|
||||
<template>
|
||||
<div class="p-2 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">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="学号" prop="studentNo">
|
||||
<el-input v-model="queryParams.studentNo" placeholder="请输入学号" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="学生姓名" prop="studentName">
|
||||
<el-input v-model="queryParams.studentName" placeholder="请输入学生姓名" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
|
||||
<el-option v-for="dict in student_reward_status" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" 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>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<right-toolbar :showSearch="showSearch" @update:showSearch="showSearch = $event" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" border :data="rewardRecordList" @selection-change="handleSelectionChange" class="full-width-table">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="学号" align="center" prop="studentNo" min-width="120" />
|
||||
<el-table-column label="学生姓名" align="center" prop="studentName" min-width="100" />
|
||||
<el-table-column label="学院名称" align="center" prop="collegeName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="专业名称" align="center" prop="majorName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="班级名称" align="center" prop="className" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="奖励类型" align="center" prop="rewardTypeName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="奖励日期" align="center" prop="rewardDate" min-width="130" />
|
||||
<el-table-column label="加分分值" align="center" prop="scoreAddition" min-width="100">
|
||||
<template #default="scope">
|
||||
<span>{{ scope.row.scoreAddition ? parseFloat(scope.row.scoreAddition).toFixed(2) : '0.00' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status" min-width="80">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="student_reward_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="right" width="150">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="查看" placement="top">
|
||||
<el-button link type="primary" icon="View" @click="handleView(scope.row)" v-hasPermi="['rewardRecord:student:list']"></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>
|
||||
|
||||
<!-- 查看详情弹窗 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="1000px" append-to-body destroy-on-close>
|
||||
<el-form :model="form" label-width="120px" readonly>
|
||||
<el-row :gutter="20">
|
||||
<!-- 左列:学生基本信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="学号">
|
||||
<div class="student-display">
|
||||
<span class="student-no-text">{{ form.studentNo }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="学生姓名">
|
||||
<div class="student-display">
|
||||
<span class="student-name-text">{{ form.studentName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="学院名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.collegeName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="专业名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.majorName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="班级名称">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.className }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 右列:奖励信息 -->
|
||||
<el-col :span="12">
|
||||
<el-form-item label="奖励类型">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.rewardTypeName }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="奖励日期">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.rewardDate }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="加分分值">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.scoreAddition ? parseFloat(form.scoreAddition).toFixed(2) : '0.00' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<dict-tag :options="student_reward_status" :value="form.status" />
|
||||
</el-form-item>
|
||||
<el-form-item label="创建时间">
|
||||
<div class="student-display">
|
||||
<span class="student-info-text">{{ form.createTime }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 完整宽度的字段 -->
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="奖励内容">
|
||||
<div class="content-display">
|
||||
<span class="content-text">{{ form.rewardContent || '暂无内容' }}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 附件展示区域 -->
|
||||
<el-row v-if="attachmentList.length > 0">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="附件">
|
||||
<div class="attachment-upload-container">
|
||||
<div class="upload-demo">
|
||||
<div class="attachment-view-grid">
|
||||
<div v-for="file in attachmentList" :key="file.uid" class="upload-file-card">
|
||||
<!-- 缩略图区域 -->
|
||||
<div class="upload-file-thumb">
|
||||
<image-preview v-if="isImageFile(file) && file.url" :src="getFileOssId(file)" class="upload-thumb-image" :isOssId="true" />
|
||||
<div v-else class="upload-file-placeholder">
|
||||
<el-icon><Document /></el-icon>
|
||||
<span class="file-ext">{{ getFileExt(file.name) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 文件名称 -->
|
||||
<div class="upload-file-name" :title="file.name">
|
||||
{{ getShortFileName(file.name) }}
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区域 - 查看模式只显示下载按钮 -->
|
||||
<div class="upload-file-card-actions">
|
||||
<el-button type="success" size="small" @click.stop="handleDownloadAttachment(file)" title="下载">
|
||||
<el-icon><Download /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel">关 闭</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="StudentRewardRecord" lang="ts">
|
||||
import { ref, reactive, toRefs, onMounted, getCurrentInstance, ComponentInternalInstance } from 'vue';
|
||||
import { Document, Download } from '@element-plus/icons-vue';
|
||||
import { ElMessage, ElLoading } from 'element-plus';
|
||||
import ImagePreview from '@/components/ImagePreview/index.vue';
|
||||
import request from '@/utils/request';
|
||||
import { listMyRewardRecords, getRewardRecord } from '@/api/xskh/rewardRecord/rewardRecord';
|
||||
import type { XskhRewardRecordVo, XskhRewardRecordQuery } from '@/api/xskh/rewardRecord/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
const { student_reward_status } = toRefs<any>(proxy?.useDict('student_reward_status'));
|
||||
|
||||
const rewardRecordList = ref<XskhRewardRecordVo[]>([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<(string | number)[]>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
|
||||
// 附件相关状态
|
||||
const attachmentList = ref<any[]>([]);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: XskhRewardRecordVo = {
|
||||
id: undefined,
|
||||
studentId: undefined,
|
||||
studentNo: undefined,
|
||||
studentName: undefined,
|
||||
collegeId: undefined,
|
||||
collegeName: undefined,
|
||||
majorId: undefined,
|
||||
majorName: undefined,
|
||||
classId: undefined,
|
||||
className: undefined,
|
||||
rewardTypeId: undefined,
|
||||
rewardTypeName: undefined,
|
||||
rewardDate: undefined,
|
||||
rewardContent: undefined,
|
||||
scoreAddition: undefined,
|
||||
attachmentOssIds: undefined,
|
||||
status: undefined
|
||||
};
|
||||
|
||||
const data = reactive<PageData<XskhRewardRecordVo, XskhRewardRecordQuery>>({
|
||||
form: { ...initFormData },
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
studentId: undefined,
|
||||
studentNo: undefined,
|
||||
studentName: undefined,
|
||||
collegeId: undefined,
|
||||
collegeName: undefined,
|
||||
majorId: undefined,
|
||||
majorName: undefined,
|
||||
classId: undefined,
|
||||
className: undefined,
|
||||
rewardTypeId: undefined,
|
||||
rewardTypeName: undefined,
|
||||
rewardDate: undefined,
|
||||
rewardContent: undefined,
|
||||
scoreAddition: undefined,
|
||||
status: undefined,
|
||||
createBy: undefined,
|
||||
createTime: undefined,
|
||||
updateBy: undefined,
|
||||
updateTime: undefined,
|
||||
params: {}
|
||||
},
|
||||
rules: {}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询学生奖励记录列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await listMyRewardRecords(queryParams.value);
|
||||
rewardRecordList.value = res.rows;
|
||||
total.value = res.total;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
};
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = { ...initFormData };
|
||||
};
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: XskhRewardRecordVo[]) => {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
};
|
||||
|
||||
/** 查看详情 */
|
||||
const handleView = async (row: XskhRewardRecordVo) => {
|
||||
reset();
|
||||
const id = row.id;
|
||||
try {
|
||||
const res = await getRewardRecord(id);
|
||||
Object.assign(form.value, res.data || res);
|
||||
|
||||
// 处理附件数据
|
||||
await handleAttachmentData();
|
||||
|
||||
dialog.visible = true;
|
||||
dialog.title = '查看奖励记录详情';
|
||||
} catch (error) {
|
||||
console.error('获取奖励记录详情失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 文件处理相关方法(从RewardRecordForm复制)
|
||||
const isImageFile = (file: any) => {
|
||||
const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
|
||||
return imageTypes.includes(file.raw?.type) || (file.url && /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name));
|
||||
};
|
||||
|
||||
const getFileOssId = (file: any) => {
|
||||
return file.ossId || '';
|
||||
};
|
||||
|
||||
const getFileExt = (fileName: string) => {
|
||||
const ext = fileName.split('.').pop()?.toUpperCase();
|
||||
return ext || 'FILE';
|
||||
};
|
||||
|
||||
const getShortFileName = (fileName: string) => {
|
||||
if (!fileName) return '';
|
||||
|
||||
const lastDotIndex = fileName.lastIndexOf('.');
|
||||
if (lastDotIndex === -1) {
|
||||
return fileName.length > 12 ? fileName.substring(0, 12) + '...' : fileName;
|
||||
}
|
||||
|
||||
const name = fileName.substring(0, lastDotIndex);
|
||||
const ext = fileName.substring(lastDotIndex);
|
||||
|
||||
if (name.length <= 8) {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
return name.substring(0, 8) + '...' + ext;
|
||||
};
|
||||
|
||||
const handleDownloadAttachment = async (file: any) => {
|
||||
// 下载文件逻辑(参考RewardRecordForm)
|
||||
let downloadUrl = '';
|
||||
let fileName = file.name || 'attachment';
|
||||
|
||||
if (file.response && file.response.data && file.response.data.filePath) {
|
||||
downloadUrl = file.response.data.filePath;
|
||||
fileName = file.response.data.fileName || fileName;
|
||||
} else if (file.ossId) {
|
||||
downloadUrl = file.ossId;
|
||||
} else if (file.raw) {
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(file.raw);
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(link.href);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!downloadUrl) {
|
||||
console.error('无法获取文件下载地址');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const loading = ElLoading.service({
|
||||
text: '正在下载文件...',
|
||||
target: document.body
|
||||
});
|
||||
|
||||
const response = await request({
|
||||
url: '/resource/oss/download/' + downloadUrl,
|
||||
method: 'get',
|
||||
responseType: 'blob',
|
||||
timeout: 300000
|
||||
});
|
||||
|
||||
if (!response) {
|
||||
throw new Error('响应数据为空');
|
||||
}
|
||||
|
||||
let blobData: Blob;
|
||||
if (response instanceof Blob) {
|
||||
blobData = response;
|
||||
} else if (response.data instanceof Blob) {
|
||||
blobData = response.data;
|
||||
} else {
|
||||
throw new Error('无效的响应数据格式');
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(blobData);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(url);
|
||||
loading?.close();
|
||||
} catch (error) {
|
||||
console.error('下载文件失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAttachmentData = async () => {
|
||||
try {
|
||||
if (!form.value.attachmentOssIds || !form.value.attachmentOssIds.toString().trim()) {
|
||||
attachmentList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const ossIdsArray = form.value.attachmentOssIds
|
||||
.toString()
|
||||
.split(',')
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id);
|
||||
|
||||
if (ossIdsArray.length === 0) {
|
||||
attachmentList.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await request({
|
||||
url: `/resource/oss/listByIds/${ossIdsArray.join(',')}`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const attachmentFiles = response.data.map((item: any, index: number) => ({
|
||||
uid: `existing_${index}_${Date.now()}`,
|
||||
name: item.originalName || `附件${index + 1}`,
|
||||
url: item.url,
|
||||
ossId: item.ossId,
|
||||
status: 'success',
|
||||
response: {
|
||||
code: 200,
|
||||
data: {
|
||||
url: item.url,
|
||||
ossId: item.ossId
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
attachmentList.value = attachmentFiles;
|
||||
} else {
|
||||
attachmentList.value = [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('处理附件数据失败:', error);
|
||||
attachmentList.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 页面容器样式 */
|
||||
.page-container {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
/* 搜索按钮区域右对齐 */
|
||||
.search-btn-container {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 表格样式 */
|
||||
.full-width-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 表格内容区域充满宽度 */
|
||||
:deep(.el-table__body-wrapper) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 查看模式下的学生信息显示 */
|
||||
.student-display {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 0 11px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
height: 32px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.student-name-text {
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.student-no-text {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.student-info-text {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
/* 内容展示区域 */
|
||||
.content-display {
|
||||
padding: 8px 11px;
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
min-height: 80px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
color: #303133;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* 附件上传容器样式 */
|
||||
.attachment-upload-container {
|
||||
width: 100%;
|
||||
max-height: calc(100vh - 650px);
|
||||
min-height: 200px;
|
||||
overflow-y: auto;
|
||||
padding-right: 8px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 6px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* 附件上传区域内容样式 */
|
||||
.attachment-upload-container .upload-demo {
|
||||
padding: 12px;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
/* 查看模式下的附件网格展示 */
|
||||
.attachment-view-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 9px;
|
||||
margin-top: 12px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 文件卡片样式 */
|
||||
.upload-file-card {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-file-card:hover {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.upload-file-thumb {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 110px;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-thumb-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
/* 文件卡片占位封面样式 */
|
||||
.upload-file-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.upload-file-placeholder .el-icon {
|
||||
font-size: 28px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.upload-file-placeholder .file-ext {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.upload-file-name {
|
||||
padding: 6px 8px;
|
||||
font-size: 11px;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
line-height: 1.2;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
word-break: break-all;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.upload-file-card-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 6px 8px;
|
||||
background: #fafafa;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
transition: all 0.3s;
|
||||
height: 38px;
|
||||
}
|
||||
|
||||
.upload-file-card-actions .el-button {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid #e0e0e0;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.upload-file-card-actions .el-button:hover {
|
||||
background: #f5f5f5;
|
||||
border-color: #409eff;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user