有下述代码,其中代码1、代码2和代码3是java代码,其中上传文件接口如下代码1中的uploadInstitution()方法,在代码4中,修改一下uploadInstitution()方法(允许多个附件上传),请修改代码4和代码5中的附件上传的功能:
### 代码1:LearnController.java
```java
package com.zhiruan.business.learn.controller;
import com.zhiruan.business.learn.service.LearnService;
import com.zhiruan.core.entity.business.learn.Learn;
import com.zhiruan.core.web.controller.BaseController;
import com.zhiruan.core.web.domain.AjaxResult;
import com.zhiruan.core.web.page.TableDataInfo;
import com.zhiruan.log.annotation.Log;
import com.zhiruan.log.enums.BusinessType;
import com.zhiruan.security.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
/**
* @Author: HZH
* @ClassName: LearnController
* @Description TODO
* @version: 1.0v
* @DATE: 2025/9/19 23:37
*/
@RestController
@RequestMapping("/learn")
public class LearnController extends BaseController {
@Resource
LearnService learnService;
/**
* 01-制度学习/业务学习-上传
*/
@RequiresPermissions({"learn:institution:upload","learn:business:upload"})
@Log(title = "制度学习", businessType = BusinessType.INSERT)
@PostMapping("/institution/upload")
public AjaxResult uploadInstitution(@RequestParam("file") MultipartFile[] files, Long[] learnIds){
learnService.uploadLearnFile(files, learnIds);
return success();
}
}
```
### 代码2:LearnService.java
```java
package com.zhiruan.business.learn.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zhiruan.core.entity.business.file.FileInfo;
import com.zhiruan.core.entity.business.learn.Learn;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* @Author: HZH
* @ClassName: LearnService
* @Description TODO
* @version: 1.0v
* @DATE: 2025/9/19 23:39
*/
public interface LearnService extends IService<Learn> {
boolean uploadLearnFile(MultipartFile[] files, Long[] learnIds);
}
```
### 代码3:LearnServiceImpl.java
```java
/**
* 批量上传
* @param files 上传的文件数组
* @param learnIds 关联的学习ID数组
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean uploadLearnFile(MultipartFile[] files, Long[] learnIds) {
// 校验文件数组是否为空
if (Objects.isNull(files) || files.length == 0) {
log.error("uploadLearnFile: 上传的文件数组为空");
throw new ServiceException("附件上传失败:未选择任何文件");
}
// 校验关联的学习ID数组
if (Objects.isNull(learnIds) || learnIds.length == 0) {
log.error("uploadLearnFile: 关联的学习ID数组为空");
throw new ServiceException("附件上传失败:未指定关联的学习记录");
}
// 遍历每个上传的文件
for (MultipartFile file : files) {
// 校验单个文件是否为空
if (Objects.isNull(file) || file.isEmpty()) {
log.warn("uploadLearnFile: 跳过空文件");
continue; // 跳过空文件,继续处理其他文件
}
// 每个文件关联所有learnIds
for (Long learnId : learnIds) {
FileInfo fileInfo = FileInfo.builder()
.linkId(learnId) // 绑定当前学习记录ID
.fileClazz("6") // 保持原业务标识
.build();
// 调用文件服务保存单个文件
iFileService.addFile(file, fileInfo);
}
}
return true; // 原代码返回false可能是笔误,成功应返回true
}
```
### 代码4:src\api\learn\institution\institution.js
```js
import request from '@/utils/request'
// 制度学习-查询列表
export function list(query){
return request({
url: '/business/learn/institution/list',
method: 'get',
params: query
})
}
// 制度学习-新增
export function addInstitution(data){
return request({
url: '/business/learn/institution/add',
method: 'post',
data: data
})
}
// 制度学习-确认
export function delUser(learnId) {
return request({
url: '/business/learn/institution/confirm/' + learnId,
method: 'get'
})
}
// 制度学习-详情
export function getInstitutionById(learnId) {
return request({
url: '/business/learn/institution/getById/' + learnId,
method: 'get'
})
}
// 制度学习-编辑
export function editInstitution(data) {
return request({
url: '/business/learn/institution/edit',
method: 'put',
data: data
})
}
// 制度学习-删除
export function removeInstitution(learnId) {
return request({
url: '/business/learn/institution/remove/' + learnId,
method: 'delete'
})
}
// 制度学习-上传附件
export function uploadInstitution(file, learnIds) {
const formData = new FormData();
// 添加文件参数,与Java接口的@RequestParam("file")对应
formData.append('file', file);
// 添加learnIds数组参数,后端需要接收Long[]类型
if (learnIds && learnIds.length) {
learnIds.forEach(id => {
formData.append('learnIds', id);
});
}
return request({
url: '/business/learn/institution/upload',
method: 'post',
data: formData,
// 上传文件需要指定Content-Type为multipart/form-data
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
// 查看附件详情
export function getInstitutionFile(learnId, clazz) {
return request({
url: `/business/learn/institution/getFile/${learnId}/${clazz}`,
method: 'get'
});
}
```
### 代码5:src\views\learn\business\index.vue
```vue
<template>
<div class="app-container">
<!-- 搜索表单 -->
<el-form
:model="queryParams"
ref="queryRef"
:inline="true"
v-show="showSearch"
label-width="80px"
>
<el-form-item label="行政区划" prop="areaId">
<el-tree-select
v-model="queryParams.areaId"
:data="deptOptions"
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
value-key="deptId"
placeholder="请选择行政区划"
clearable
style="width: 240px"
@change="handleQuery"
:check-strictly="true"
/>
</el-form-item>
<el-form-item label="所在部门" prop="deptId">
<el-tree-select
v-model="queryParams.deptId"
:data="deptOptions"
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
value-key="deptId"
placeholder="请选择所在部门"
clearable
style="width: 240px"
@change="handleQuery"
:check-strictly="true"
/>
</el-form-item>
<el-form-item label="制度名称" prop="learnName">
<el-input
v-model="queryParams.learnName"
placeholder="请输入制度名称"
clearable
style="width: 240px"
@change="handleQuery"
@keyup.enter="handleQuery"
/>
</el-form-item>
<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-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Upload"
@click="handleUpload"
v-hasPermi="['learn:business:upload']"
:disabled="multiple"
>上传</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAdd"
v-hasPermi="['learn:business:add']"
>新增</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['learn:business:remove']"
>删除</el-button
>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="Check"
:disabled="isAdmin || !canBatchConfirm"
@click="handleConfirm"
v-hasPermi="['learn:business:confirm']"
>学习</el-button
>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<!-- 数据表格 -->
<el-table
v-loading="loading"
:data="institutionList"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="learnId" width="60" />
<el-table-column
label="行政区划"
align="center"
prop="areaName"
:show-overflow-tooltip="true"
/>
<el-table-column
label="所在部门"
align="center"
prop="deptName"
:show-overflow-tooltip="true"
/>
<el-table-column
label="制度名称"
align="center"
prop="learnName"
:show-overflow-tooltip="true"
/>
<el-table-column label="是否生效" align="center" prop="isEnable">
<template #default="scope">
<el-tag :type="scope.row.isEnable === '1' ? 'success' : 'info'">
{{ scope.row.isEnable === "1" ? "已生效" : "未生效" }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="上传时间"
align="center"
prop="enableTime"
width="180"
>
<template #default="scope">
<span>{{
scope.row.enableTime ? parseTime(scope.row.enableTime) : "-"
}}</span>
</template>
</el-table-column>
<!-- 角色相关的动态列 -->
<template v-if="isAdminTypeRole">
<el-table-column
label="学习人数"
align="center"
prop="learnNumber"
width="120"
/>
<el-table-column
label="未学习人数"
align="center"
prop="unLearnNumber"
width="120"
/>
</template>
<template v-else>
<el-table-column label="是否学习" align="center" prop="isConfirm">
<template #default="scope">
<el-tag :type="scope.row.isConfirm === '1' ? 'success' : 'warning'">
{{ scope.row.isConfirm === "1" ? "已学习" : "未学习" }}
</el-tag>
</template>
</el-table-column>
<el-table-column
label="学习时间"
align="center"
prop="learnTime"
width="180"
>
<template #default="scope">
<span>{{
scope.row.learnTime ? parseTime(scope.row.learnTime) : "-"
}}</span>
</template>
</el-table-column>
</template>
<el-table-column
label="操作"
align="center"
width="360"
class-name="small-padding fixed-width"
>
<template #default="scope">
<el-button
link
type="primary"
icon="Edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['learn:business:edit']"
>编辑</el-button
>
<el-button
link
type="primary"
icon="Delete"
@click="handleDelete(scope.row)"
v-hasPermi="['learn:business:remove']"
>删除</el-button
>
<el-button
link
type="primary"
icon="Check"
@click="handleConfirm(scope.row)"
v-hasPermi="['learn:business:confirm']"
:disabled="isAdmin || scope.row.isConfirm === '1'"
>
学习
</el-button>
<el-button
link
type="primary"
icon="Document"
@click="handleViewFiles(scope.row.learnId)"
v-hasPermi="['learn:business:viewFile']"
>
查看附件
</el-button>
</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-dialog :title="title" v-model="open" width="500px" append-to-body>
<el-form
ref="institutionRef"
:model="form"
:rules="rules"
label-width="100px"
>
<el-form-item label="行政区划" prop="areaId">
<el-tree-select
v-model="form.areaId"
:data="deptOptions"
:props="{
value: 'deptId',
label: 'deptName',
children: 'children',
}"
value-key="deptId"
placeholder="请选择行政区划"
clearable
:check-strictly="true"
/>
</el-form-item>
<el-form-item label="所在部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
:data="deptOptions"
:props="{
value: 'deptId',
label: 'deptName',
children: 'children',
}"
value-key="deptId"
placeholder="请选择所在部门"
clearable
:check-strictly="true"
/>
</el-form-item>
<el-form-item label="制度名称" prop="learnName">
<el-input v-model="form.learnName" placeholder="请输入制度名称" />
</el-form-item>
<el-form-item label="是否生效" prop="isEnable">
<el-radio-group v-model="form.isEnable">
<el-radio label="0">未生效</el-radio>
<el-radio label="1">已生效</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 上传对话框 -->
<el-dialog
title="上传制度文件"
v-model="uploadOpen"
width="680px"
append-to-body
class="custom-dialog"
>
<el-form ref="uploadRef" :model="uploadForm" label-width="100px">
<!-- 选择制度:每行5个,显示前3个字,超出用 tooltip 展示完整名称 -->
<el-form-item label="选择制度" prop="selectedItems">
<div class="institution-grid">
<el-tooltip
v-for="item in selectedInstitutions"
:key="item.learnId"
effect="dark"
:content="item.learnName"
placement="top"
>
<div class="institution-cell">
<el-checkbox
v-model="uploadForm.selectedItems"
:label="item.learnId"
class="institution-btn"
>
{{ shortName(item.learnName) }}
</el-checkbox>
</div>
</el-tooltip>
</div>
</el-form-item>
<el-form-item label="上传文件" prop="files">
<el-upload
class="upload-area"
drag
action=""
:on-change="handleFileChange"
:auto-upload="false"
:file-list="fileList"
accept=".doc,.docx,.pdf,.txt,.jpg,.jpeg,.png,.gif,.html"
:multiple="true"
>
<el-icon class="el-icon--upload"><UploadFilled /></el-icon>
<div class="el-upload__text">
将文件拖拽到此处,或 点击选择文件
</div>
<template #tip>
<div class="upload-tip">
支持 .pdf, .jpg, .jpeg, .png, .gif
格式文件<br />
单个文件大小不超过 <b>1MB</b>
</div>
</template>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitUpload">上传</el-button>
<el-button @click="cancelUpload">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 附件查看对话框 -->
<el-dialog
title="附件详情"
v-model="fileDialogOpen"
width="850px"
append-to-body
class="custom-dialog"
>
<div v-loading="fileLoading">
<el-empty
v-if="fileList.length === 0"
description="暂无附件"
></el-empty>
<el-table v-else :data="fileList" border stripe style="width: 100%">
<!-- 文件名 -->
<el-table-column
label="文件名"
prop="fileName"
min-width="200"
show-overflow-tooltip
align="center"
/>
<!-- 文件内容:区分图片/非图片 -->
<el-table-column
label="文件预览"
prop="fileUrl"
min-width="300"
align="center"
>
<template #default="scope">
<!-- 图片类型 -->
<template v-if="/\.(jpg|jpeg|png|gif)$/i.test(scope.row.fileUrl)">
<el-image
:src="scope.row.fileUrl"
:preview-src-list="[scope.row.fileUrl]"
preview-teleported
fit="cover"
style="
width: 80px;
height: 80px;
border-radius: 6px;
cursor: pointer;
"
/>
</template>
<!-- PDF 文件 -->
<template v-else-if="/\.pdf$/i.test(scope.row.fileUrl)">
<a :href="scope.row.fileUrl" target="_blank">
<el-icon size="32" color="#E34133"><Document /></el-icon>
</a>
</template>
<!-- Word 文件 -->
<template v-else-if="/\.(doc|docx)$/i.test(scope.row.fileUrl)">
<a :href="scope.row.fileUrl" target="_blank">
<el-icon size="32" color="#2A5699"><DocumentAdd /></el-icon>
</a>
</template>
<!-- 其他文件 -->
<template v-else>
<a :href="scope.row.fileUrl" target="_blank">
<el-icon size="32" color="#606266"><Files /></el-icon>
</a>
</template>
</template>
</el-table-column>
<!-- 上传人 -->
<el-table-column
label="创建人用户"
prop="userName"
align="center"
width="140"
/>
<!-- 上传时间 -->
<el-table-column
label="上传时间"
prop="createTime"
align="center"
width="160"
>
<template #default="scope">
<span>{{
scope.row.createTime
? parseTime(scope.row.createTime, "{y}-{m}-{d} {h}:{i}:{s}")
: "-"
}}</span>
</template>
</el-table-column>
</el-table>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="fileDialogOpen = false"
>关 闭</el-button
>
</div>
</template>
</el-dialog>
<!-- 制度确认对话框 -->
<el-dialog
:title="'制度确认'"
v-model="confirmDialogVisible"
width="600px"
center
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div class="text-center mb-4">
本人已阅读该项制度并承诺在职期间遵守本项制度;
</div>
<template #footer>
<div class="dialog-footer flex justify-center space-x-4">
<el-button type="primary" @click="handleSign">签字</el-button>
<el-button @click="confirmDialogVisible = false">返回</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="InstitutionLearn">
import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
import { UploadFilled } from "@element-plus/icons-vue";
import {
list,
addInstitution,
getInstitutionById,
editInstitution,
removeInstitution,
delUser as confirmInstitution,
uploadInstitution,
getInstitutionFile,
} from "@/api/learn/institution/institution";
import { getInfo } from "@/api/login";
import { listDept } from "@/api/system/dept";
// 获取当前组件实例
const { proxy } = getCurrentInstance();
// 用户角色相关
const userRoles = ref([]);
const isAdminTypeRole = computed(() => {
// 检查是否包含管理员类型角色
const adminRoles = ["admin", "deptLead", "opManager"];
return userRoles.value.some((role) => adminRoles.includes(role));
});
// 新增:判断当前用户是否为超级管理员(admin角色)
const isAdmin = computed(() => {
return userRoles.value.includes("admin");
});
// 部门数据(同时用于行政区划和所在部门)
const deptOptions = ref([]);
// 表格数据
const institutionList = ref([]);
const loading = ref(true);
const total = ref(0);
const showSearch = ref(true);
const open = ref(false);
const uploadOpen = ref(false);
const fileDialogOpen = ref(false);
const title = ref("");
// 选中项
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const selectedInstitutions = ref([]); // 选中的制度列表,用于上传附件
// 制度确认对话框相关
const confirmDialogVisible = ref(false);
const currentConfirmIds = ref([]);
// 新增:判断是否可以进行批量确认(基于选中项的isConfirm状态)
const canBatchConfirm = computed(() => {
if (ids.value.length === 0) return false;
const selectedItems = institutionList.value.filter((item) =>
ids.value.includes(item.learnId)
);
return selectedItems.every((item) => item.isConfirm === "0");
});
// 文件相关
const fileList = ref([]);
const currentLearnId = ref(""); // 当前查看附件的制度ID
const fileLoading = ref(false);
// 上传表单数据
const uploadForm = reactive({
selectedItems: [], // 选中的制度ID
});
// 表单数据
const data = reactive({
form: {
learnId: undefined,
areaId: undefined,
deptId: undefined,
learnName: undefined,
isEnable: "0", // 默认未生效
areaName: undefined, // 用于显示
deptName: undefined, // 用于显示
},
queryParams: {
pageNum: 1,
pageSize: 10,
areaId: undefined,
deptId: undefined,
learnName: undefined,
isEnable: undefined,
learnClazz: 2,
},
rules: {
areaId: [{ required: true, message: "行政区划不能为空", trigger: "blur" }],
deptId: [{ required: true, message: "所在部门不能为空", trigger: "blur" }],
learnName: [
{ required: true, message: "制度名称不能为空", trigger: "blur" },
],
},
});
const { form, queryParams, rules } = toRefs(data);
/** 将制度名称仅显示前三个字符(中文/英文都适用) */
function shortName(name = "") {
if (!name) return "";
// 如果长度小于等于3,直接返回;否则返回前三个字符(不加省略号,根据你的要求)
return name.length <= 3 ? name : name.slice(0, 3);
}
/** 获取部门列表数据 - 同时用于行政区划和所在部门 */
function getDeptList() {
listDept()
.then((response) => {
// 处理树形结构,保留所有层级
deptOptions.value = proxy.handleTree(response.data, "deptId");
})
.catch((error) => {
console.error("获取部门列表失败:", error);
});
}
/** 获取用户信息和角色 */
function getUserInfo() {
getInfo()
.then((response) => {
// 存储用户角色
userRoles.value = response.roles || [];
// 获取部门数据
getDeptList();
// 获取数据列表
getList();
})
.catch((error) => {
console.error("获取用户信息失败:", error);
loading.value = false;
});
}
/** 查询制度学习列表 */
function getList() {
loading.value = true;
list(queryParams.value)
.then((response) => {
institutionList.value = response.rows || [];
total.value = response.total || 0;
loading.value = false;
})
.catch((error) => {
console.error("获取数据列表失败:", error);
loading.value = false;
});
}
/** 取消按钮 */
function cancel() {
open.value = false;
reset();
}
/** 取消上传 */
function cancelUpload() {
uploadOpen.value = false;
fileList.value = [];
uploadForm.selectedItems = [];
}
/** 表单重置 */
function reset() {
form.value = {
learnId: undefined,
areaId: undefined,
deptId: undefined,
learnName: undefined,
isEnable: "0",
areaName: undefined,
deptName: undefined,
};
proxy.resetForm("institutionRef");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1; // 搜索时重置为第一页
getList();
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm("queryRef");
// 清空查询参数
queryParams.value = {
pageNum: 1,
pageSize: 10,
areaId: undefined,
deptId: undefined,
learnName: undefined,
isEnable: undefined,
learnClazz: 2
};
handleQuery();
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "新增制度学习";
}
/** 上传按钮操作 */
function handleUpload() {
// 打开弹窗前,强制清空上一次的文件列表和选中状态
fileList.value = []; // 清空文件列表
uploadForm.selectedItems = []; // 清空选中的制度ID
// 存储当前选中的制度
selectedInstitutions.value = institutionList.value.filter((item) =>
ids.value.includes(item.learnId)
);
uploadForm.selectedItems = [...ids.value];
uploadOpen.value = true;
}
/** 文件变化处理 */
function handleFileChange(file, newFileList) {
fileList.value = newFileList;
}
/** 提交上传 */
function submitUpload() {
if (fileList.value.length === 0) {
proxy.$modal.msgError("请选择文件");
return;
}
if (uploadForm.selectedItems.length === 0) {
proxy.$modal.msgError("请选择要关联的制度");
return;
}
// 处理多文件上传
const uploadPromises = fileList.value.map((file) => {
return uploadInstitution(file.raw, uploadForm.selectedItems);
});
loading.value = true;
Promise.all(uploadPromises)
.then(() => {
proxy.$modal.msgSuccess("文件上传成功");
cancelUpload();
getList();
})
.catch((error) => {
proxy.$modal.msgError(
"文件上传失败: " + (error.msg || error.message || "未知错误")
);
})
.finally(() => {
loading.value = false;
});
}
/** 多选框选中数据 */
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.learnId);
single.value = selection.length !== 1;
multiple.value = !selection.length;
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
const learnId = row ? row.learnId : ids.value[0];
getInstitutionById(learnId).then((response) => {
form.value = {
...response.data,
areaId: response.data.areaId,
deptId: response.data.deptId,
};
open.value = true;
title.value = "编辑制度学习";
});
}
/** 提交按钮 */
function submitForm() {
proxy.$refs["institutionRef"].validate((valid) => {
if (valid) {
// 提交前获取部门名称用于显示
const areaItem = findDeptById(deptOptions.value, form.value.areaId);
const deptItem = findDeptById(deptOptions.value, form.value.deptId);
const submitData = {
...form.value,
areaName: areaItem ? areaItem.deptName : "",
deptName: deptItem ? deptItem.deptName : "",
learnClazz: 2
};
if (form.value.learnId !== undefined) {
editInstitution(submitData).then((response) => {
proxy.$modal.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
addInstitution(submitData).then((response) => {
proxy.$modal.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
});
}
/** 递归查找部门 - 支持所有层级查找 */
function findDeptById(deptList, deptId) {
for (const dept of deptList) {
if (dept.deptId === deptId) {
return dept;
}
if (dept.children && dept.children.length > 0) {
const found = findDeptById(dept.children, deptId);
if (found) return found;
}
}
return null;
}
/** 删除按钮操作 */
function handleDelete(row) {
const learnIds = row.learnId || ids.value;
proxy.$modal
.confirm("是否确认删除选中的" + learnIds.length + "条数据?")
.then(function () {
return removeInstitution(learnIds);
})
.then(() => {
getList();
proxy.$modal.msgSuccess("删除成功");
})
.catch(() => {});
}
/** 确认按钮操作 - 显示自定义制度确认弹窗 */
function handleConfirm(row) {
// 新增:超级管理员直接禁止操作
if (isAdmin.value) {
proxy.$modal.msgWarning("超级管理员不允许执行确认操作");
return;
}
const learnIds = row.learnId || ids.value;
if (learnIds.length === 0) {
proxy.$modal.msgWarning("请选择要确认的数据");
return;
}
// 获取选中项详情
const selectedItems = row
? [row]
: institutionList.value.filter((item) => learnIds.includes(item.learnId));
// 检查是否存在已确认数据(isConfirm=1)
const hasConfirmed = selectedItems.some((item) => item.isConfirm === "1");
if (hasConfirmed) {
proxy.$modal.msgWarning("存在已确认的数据,不可重复确认");
return;
}
// 显示自定义确认弹窗,并记录要确认的ID
currentConfirmIds.value = learnIds;
confirmDialogVisible.value = true;
}
/** 处理签字确认操作 */
function handleSign() {
// 1. 统一将数据处理为数组(兼容单条/多条)
let learnIds = currentConfirmIds.value;
// 如果不是数组(单条数据场景),包装成数组
if (!Array.isArray(learnIds)) {
learnIds = [learnIds];
}
// 校验数据有效性
if (!learnIds || learnIds.length === 0) {
proxy.$modal.msgWarning("请选择要确认的数据");
return;
}
// 2. 转为逗号分隔字符串(适配后端Long[]解析)
const batchIds = learnIds.join(",");
// 3. 调用接口
loading.value = true;
confirmInstitution(batchIds)
.then(() => {
confirmDialogVisible.value = false;
getList();
proxy.$modal.msgSuccess("确认成功");
})
.catch((error) => {
proxy.$modal.msgError(
"确认失败: " + (error.msg || error.message || "未知错误")
);
})
.finally(() => {
loading.value = false;
});
}
/** 查看附件 */
function handleViewFiles(learnId) {
currentLearnId.value = learnId;
fileDialogOpen.value = true;
fileLoading.value = true;
// 调用接口获取附件列表,clazz固定为6
getInstitutionFile(learnId, "6")
.then((response) => {
fileList.value = response.data || [];
fileLoading.value = false;
})
.catch((error) => {
console.error("获取附件列表失败:", error);
proxy.$modal.msgError("获取附件失败");
fileLoading.value = false;
});
}
/** 下载文件 */
function downloadFile(file) {
// 这里实现文件下载逻辑,根据实际接口调整
proxy.download(
`/business/learn/institution/download/${file.fileId}`,
{},
file.fileName
);
}
// 初始化时加载数据
getUserInfo();
</script>
<style scoped>
.text-red {
color: #ff4d4f;
}
.text-gray-500 {
color: #909399;
font-size: 12px;
}
/* 上传区样式 */
.upload-area {
width: 100%;
border: 2px dashed #d9d9d9;
border-radius: 8px;
background: #fafafa;
}
.upload-tip {
margin-top: 6px;
font-size: 12px;
color: #666;
line-height: 1.5;
}
.custom-dialog ::v-deep(.el-dialog__header) {
font-weight: bold;
font-size: 16px;
}
/* --- 选择制度:使用 Grid,保证每行固定 5 个并对齐 --- */
.institution-grid {
display: grid;
grid-template-columns: repeat(5, 1fr); /* 固定 5 列 */
gap: 8px 10px; /* 行间距8px,列间距10px */
align-items: center;
margin-top: 0px;
}
/* 每个单元格,水平垂直居中 */
.institution-cell {
display: flex;
align-items: center;
justify-content: center;
}
/* checkbox 占满单元格,内容居中,显示前三个字 */
.institution-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 32px;
padding: 2px 6px;
box-sizing: border-box;
border-radius: 6px;
background: #f5f7fa;
border: 1px solid #dcdfe6;
font-size: 13px;
color: #333;
overflow: hidden;
white-space: nowrap;
text-overflow: clip; /* 不显示省略号,只显示前三个字符由 shortName 控制 */
}
/* 调整内部复选框图标与文字间距 */
.institution-btn .el-checkbox__inner {
margin-right: 6px;
}
/* 悬浮效果 */
.institution-btn:hover {
background: #ecf5ff;
border-color: #409eff;
}
/* 超长文本显示省略号 */
.ellipsis {
display: inline-block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
/* 文件链接样式 */
.file-link {
color: #409eff;
text-decoration: none;
word-break: break-all;
}
.file-link:hover {
text-decoration: underline;
}
.ellipsis-text {
display: inline-block;
max-width: 200px; /* 或者根据实际UI调整 */
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
}
</style>
```