This commit is contained in:
@jyuhsin
2025-10-13 10:33:38 +08:00
parent 8dad7c09ba
commit 3d7a081eb3
3 changed files with 610 additions and 0 deletions
@@ -0,0 +1,360 @@
package io.v.nutz.zhgh.trainSignUp.controller.manage;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.export.ExcelExportService;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.wizzer.framework.base.Result;
import io.v.nutz.base.annontation.ViReturn;
import io.v.nutz.base.page.Pagination;
import io.v.nutz.base.query.PageForm;
import io.v.nutz.base.service.BaseService;
import io.v.nutz.base.utils.CommonDownloadUtil;
import io.v.nutz.base.utils.ViTool;
import io.v.nutz.sys.models.Sys_user;
import io.v.nutz.sys.models.User;
import io.v.nutz.zhgh.activityBudget.models.ActivityBudget;
import io.v.nutz.zhgh.activityBudget.template.ActivityBudgetTemp;
import io.v.nutz.zhgh.trainSignUp.constant.TrainCourseType;
import io.v.nutz.zhgh.trainSignUp.models.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.VarIndex;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
/**
* @ClassName TrainSignUpDataController
* @Author JyuHsin
* @Date 2025/10/11 15:44
* @Version 1.0
* @Description TODO
*/
@Slf4j
@IocBean
@At("/platform/trainSignUp/data")
public class TrainSignUpDataController {
@Inject
private Dao dao;
@Inject
private BaseService baseService;
@At("")
@RequiresPermissions("trainSignUp.data")
@Ok("beetl:/platform/trainSingUp/data/index.html")
public void index() {
}
@At
@ViReturn
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
public Object pageData(PageForm pageForm,
@Param(value = "activityId") String activityId,
@Param(value = "courseId") String courseId,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId) {
Sql sql = Sqls.create("""
select
td.*,
u.username as userName,
u.loginname as loginName,
u.unitname as unitName,
u.unionname as unionName,
count(td.userId) as count
from
train_sign_up_user_data td
left join user u on u.id = td.userId
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("td.activityId", "=", activityId);
cnd.andEX("td.courseId", "=", courseId);
cnd.andEX("u.unionId", "=", unionId);
cnd.andEX("u.unitId", "=", unitId);
cnd.groupBy("td.userId");
sql.setCondition(cnd);
return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
}
@At
@ViReturn
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
public Object view(String activityId, String userId) {
return dao.query(TrainSignUpUserData.class, Cnd.where("activityId", "=", activityId).and("userId", "=", userId).asc("signUpTime"));
}
@At
@ViReturn
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
public Object selectActivity() {
return dao.query(TrainSignUpActivity.class, Cnd.where("isDisabled", "=", false).desc("activitySignUpStartTime"));
}
@At
@ViReturn
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
public Object selectCourse(String activityId) {
return dao.query(TrainSignUpCourse.class, Cnd.where("activityId", "=", activityId).asc("orderNum"));
}
@At
@ViReturn
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
public Object delete(String id) {
dao.delete(TrainSignUpUserData.class, id);
return null;
}
@At
@RequiresPermissions("trainSignUp.data")
public void downLoad(String activityId,
String courseId,
HttpServletResponse response) throws IOException {
TrainSignUpCourse course = dao.fetch(TrainSignUpCourse.class, courseId);
TrainSignUpType type = dao.fetch(TrainSignUpType.class, course.getCourseType());
dao.fetchLinks(type, "^trainMobileSignColumnList$", Cnd.NEW().asc("columnIndex"));
List<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("姓名", "userName", 20));
exportEntities.add(new ExcelExportEntity("工号(必填)", "loginName", 20));
if (Lang.isNotEmpty(type.getTrainMobileSignColumnList())) {
for (TrainMobileSignColumn column : type.getTrainMobileSignColumnList()) {
exportEntities.add(new ExcelExportEntity(column.getColumnName(), column.getColumnCode(), 20));
}
}
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("导入模板.xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, new ArrayList<>());
workbook.write(response.getOutputStream());
}
@At
@Ok("json:full")
@RequiresPermissions("trainSignUp.data")
@Aop(TransAop.READ_COMMITTED)
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
public Object importData(@Param(value = "courseId") String courseId,
@Param(value = "file") TempFile file) throws IOException {
TrainSignUpCourse course = dao.fetch(TrainSignUpCourse.class, courseId);
TrainSignUpType type = dao.fetch(TrainSignUpType.class, course.getCourseType());
dao.fetchLinks(type, "^trainMobileSignColumnList$", Cnd.NEW().asc("columnIndex"));
List<Sys_user> userList = dao.query(Sys_user.class, Cnd.NEW());
Map<String, Sys_user> userMap = userList.stream().collect(Collectors.toMap(Sys_user::getLoginname, o -> o));
ImportParams params = new ImportParams();
params.setTitleRows(0);
params.setHeadRows(1);
List<Map<String, Object>> list = ExcelImportUtil.importExcel(file.getFile(), Map.class, params);
List<Map> errorInfos = new ArrayList<>();
List<TrainSignUpUserData> datas = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Map<String, Object> map = list.get(i);
map.put("index", i + 1);
Sys_user sysUser = userMap.get(map.get("工号(必填)").toString());
if (ObjectUtil.isEmpty(map.get("工号(必填)"))) {
map.put("errorInfo", "工号不能为空");
errorInfos.add(map);
continue;
}
if (ObjectUtil.isEmpty(sysUser)) {
map.put("errorInfo", "查询不到" + map.get("工号(必填)") + "的用户");
errorInfos.add(map);
continue;
}
TrainSignUpUserData userData = new TrainSignUpUserData();
userData.setSource(2);
userData.setActivityId(course.getActivityId());
userData.setCourseId(courseId);
userData.setUserId(sysUser.getId());
userData.setMobile(sysUser.getMobile());
userData.setSignUpTime(DateUtil.date());
List<NutMap> columnValues = new ArrayList<>();
for (TrainMobileSignColumn column : type.getTrainMobileSignColumnList()) {
NutMap nutMap = new NutMap();
nutMap.put("columnName", column.getColumnName());
nutMap.put("columnValue", map.get(column.getColumnName()).toString());
nutMap.put("columnCode", column.getColumnCode());
nutMap.put("columnFormType", column.getColumnFormType());
columnValues.add(nutMap);
}
userData.setMobileColumnsValue(columnValues);
datas.add(userData);
}
dao.insert(datas);
if (Lang.isNotEmpty(errorInfos)) {
NutMap nutMap = NutMap.NEW();
nutMap.setv("totalCount", list.size());
nutMap.setv("successCount", Math.max(datas.size() - errorInfos.size(), 0));
nutMap.setv("errorCount", errorInfos.size());
nutMap.setv("errorList", errorInfos.stream().map(v -> NutMap.NEW().addv("序号", v.get("index")).addv("错误原因", v.get("errorInfo"))).collect(Collectors.toList()));
return Result.success(nutMap);
}
return Result.success().addMsg("导入成功");
}
@At
@RequiresPermissions("trainSignUp.data")
public void doExport(String activityId,
String courseId,
HttpServletResponse response) throws IOException {
List<User> userList = dao.query(User.class, Cnd.NEW());
Map<String, User> userMap = userList.stream().collect(Collectors.toMap(User::getId, o -> o));
List<TrainSignUpUserData> list = dao.query(TrainSignUpUserData.class, Cnd.where("activityId", "=", activityId));
Map<String, List<TrainSignUpUserData>> listMap = list.stream().collect(Collectors.groupingBy(TrainSignUpUserData::getCourseId));
List<TrainSignUpCourse> courseList = dao.query(TrainSignUpCourse.class, Cnd.where("activityId", "=", activityId));
List<TrainSignUpType> typeList = dao.query(TrainSignUpType.class, Cnd.NEW());
dao.fetchLinks(typeList, "trainMobileSignColumnList", Cnd.NEW().asc("columnIndex"));
Map<String, TrainSignUpType> typeMap = typeList.stream().collect(Collectors.toMap(TrainSignUpType::getId, o -> o));
List<Map<String, Object>> sheetsList = new ArrayList<>();
List<Map<String, String>> basicEntity = List.of(
Map.of("name", "姓名", "key", "userName"),
Map.of("name", "工号", "key", "loginName"),
Map.of("name", "单位", "key", "unitName"),
Map.of("name", "分工会", "key", "unionName"),
Map.of("name", "性别", "key", "sex"),
Map.of("name", "手机号", "key", "mobile")
);
List<ExcelExportEntity> excelCommonExportEntity = basicEntity.stream().map(entity -> {
ExcelExportEntity excelExportEntity = new ExcelExportEntity();
excelExportEntity.setKey(entity.get("key"));
excelExportEntity.setName(entity.get("name"));
excelExportEntity.setWidth(20);
excelExportEntity.setNeedMerge(true);
return excelExportEntity;
}).collect(Collectors.toCollection(ArrayList::new));
for (TrainSignUpCourse c : courseList) {
String k = c.getCourseName();
List<TrainSignUpUserData> userData = listMap.get(c.getId());
ExportParams userExportParams = new ExportParams();
userExportParams.setSheetName(k);
userExportParams.setType(ExcelType.HSSF);
List<ExcelExportEntity> currentEntities = new ArrayList<>(excelCommonExportEntity);
TrainSignUpType signUpType = typeMap.get(c.getCourseType());
if (Lang.isNotEmpty(signUpType.getTrainMobileSignColumnList())) {
ExcelExportEntity familyEntity = new ExcelExportEntity("其他信息", "extraInfos", 20);
List<ExcelExportEntity> signColumn = signUpType.getTrainMobileSignColumnList().stream().map(column -> {
ExcelExportEntity entity = new ExcelExportEntity();
entity.setName(column.getColumnName());
entity.setKey(column.getColumnCode());
entity.setWidth(20);
if ("FILE".equals(column.getColumnFormType())) {
entity.setType(2);
entity.setExportImageType(2);
}
return entity;
}).collect(Collectors.toCollection(ArrayList::new));
familyEntity.setList(signColumn);
currentEntities.add(familyEntity);
}
Map<String, List<TrainSignUpUserData>> courseGroupUser = userData.stream().collect(Collectors.groupingBy(TrainSignUpUserData::getUserId));
List<NutMap> courseUsers = new ArrayList<>();
for (String userId : courseGroupUser.keySet()) {
User user = userMap.get(userId);
NutMap nutMap = new NutMap();
nutMap.put("userName", user.getUsername());
nutMap.put("loginName", user.getLoginname());
nutMap.put("unitName", user.getUnitname());
nutMap.put("unionName", user.getUnionname());
nutMap.put("sex", user.getSex());
nutMap.put("mobile", user.getMobile());
List<TrainSignUpUserData> users = courseGroupUser.get(userId);
List<NutMap> extraInfos = new ArrayList<>();
for (TrainSignUpUserData sign : users) {
List<NutMap> columnsValue = sign.getMobileColumnsValue();
if (Lang.isEmpty(columnsValue)) {
continue;
}
NutMap extraMap = new NutMap();
for (NutMap map : columnsValue) {
if ("FILE".equals(map.getString("columnFormType"))) {
continue;
}
extraMap.put(map.getString("columnCode"), map.getString("columnValue"));
}
extraInfos.add(extraMap);
}
nutMap.put("extraInfos", extraInfos);
courseUsers.add(nutMap);
}
Map<String, Object> userExportMap = new HashMap<>();
userExportMap.put("name", k);
userExportMap.put("title", userExportParams);
userExportMap.put("entity", currentEntities);
userExportMap.put("data", courseUsers);
sheetsList.add(userExportMap);
}
Workbook workbook = new HSSFWorkbook();
for (Map<String, Object> map : sheetsList) {
ExcelExportService service = new ExcelExportService();
service.createSheetForMap(workbook, (ExportParams) map.get("title"), (List<ExcelExportEntity>) map.get("entity"), (Collection<?>) map.get("data"));
}
CommonDownloadUtil.download("人员数据信息" + ".xlsx", workbook, response);
}
}
@@ -0,0 +1,31 @@
package io.v.nutz.zhgh.trainSignUp.models;
import lombok.Data;
import lombok.experimental.Accessors;
import org.nutz.dao.entity.annotation.*;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.util.Date;
/**
* @ClassName TrainSignUpUserData
* @Author JyuHsin
* @Date 2025/10/11 16:14
* @Version 1.0
* @Description TODO
*/
@Table
@Data
@Accessors(chain = true)
@TableIndexes({@Index(name = "INDEX_TRAIN_SIGN_UP_USER_COURSEID", fields = {"courseId"}, unique = false)})
public class TrainSignUpUserData extends TrainSignUpUser{
@Name
@PrevInsert(uu32 = true)
private String id;
@Column
@ColDefine(type = ColType.INT)
@Comment("数据来源(1.报名表,2.导入)")
private Integer source;
}
@@ -0,0 +1,219 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">活动名称:</div>
<div class="search-item-option">
<el-select placeholder="请选择活动" v-model="pageForm.activityId" style="width: 100%;" clearable filterable
@change="selectCourse(); doSearch(); courseChange()">
<el-option v-for="item in activityOptions" :label="item.activityName" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">{{ trainType }}</div>
<div class="search-item-option">
<el-select :placeholder="'请选择' + trainType" v-model="pageForm.courseId" style="width: 100%;" clearable filterable>
<el-option v-for="item in courseOptions" :label="item.courseName" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button type="primary" icon="el-icon-search" @click="doSearch">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool :app="this" label="表格数据">
<template #func>
<el-button @click="onImport" size="small" type="primary">导入数据</el-button>
<el-button @click="onExport" size="small" type="primary">导出数据</el-button>
</template>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder">
<el-table-column :index="indexMethod" align="center" header-align="center" label="序号" type="index" width="60"></el-table-column>
<el-table-column
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
align="center"
header-align="center"
show-overflow-tooltip
v-for="column in tableColumns"
>
</el-table-column>
<el-table-column label="操作" width="100">
<template scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</template>
<template #view>
<template v-for="item,index in infoData">
<vi-title2 :title="'数据创建顺序' + (index + 1)">
<template #func>
<el-button @click="onDelete(item)" size="mini" type="danger">删除</el-button>
</template>
</vi-title2>
<el-descriptions border class="mb20">
<el-descriptions-item label="来源">
{{ item.source === 1 ? '活动报名' : '数据导入' }}
</el-descriptions-item>
<el-descriptions-item label="创建时间">{{ item.signUpTime }}</el-descriptions-item>
<el-descriptions-item v-for="column in item.mobileColumnsValue" :label="column.columnName">
{{ column.columnValue }}
</el-descriptions-item>
</el-descriptions>
</template>
</template>
</guava>
<el-dialog
top="40px"
title="导入数据"
:visible.sync="exportVisible"
:close-on-click-modal="false"
width="60%">
<file-import ref="importRef" :temp_url="'/platform/trainSignUp/data/downLoad?courseId=' + pageForm.courseId"
:post_url="'/platform/trainSignUp/data/importData?courseId=' + pageForm.courseId"
:is_show_radio="false" @flush="doSearch"></file-import>
</el-dialog>
</div>
<script>
const vue = new Vue({
el: '#app',
dicts: ['trainSignUpType'],
mixins: [initTableMixins],
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
courseId: '',
},
tableColumns: [
{prop: 'userName', label: '姓名'},
{prop: 'loginName', label: '工号'},
{prop: 'unitName', label: '所属单位'},
{prop: 'unionName', label: "所属工会"},
{prop: 'signUpTime', label: "报名时间"},
{prop: 'count', label: "记录数"},
],
activityOptions: [],
courseOptions: [],
trainType: '',
exportVisible: false,
infoData: [],
}
},
components: {
'file-import': httpVueLoader('/components/plugins/FileImport.vue')
},
methods: {
onDelete(row) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const res = await $.post('/platform/trainSignUp/data/delete', {id: row.id})
if (res.code === 0) {
this.$message.success(res.msg)
this.onView(row)
} else {
this.$message.warning(res.msg)
}
}).catch(() => {})
},
onView(row) {
$.post('/platform/trainSignUp/data/view', {activityId: row.activityId, userId: row.userId})
.then(res => {
if(res.code === 0) {
this.infoData = res.data
this.$refs.guava.view()
} else {
this.$message.error(res.msg)
}
})
},
onImport() {
if(!this.pageForm.activityId) {
this.$message.warning('请选择活动')
return
}
if(!this.pageForm.courseId) {
this.$message.warning('请选择' + this.trainType)
return
}
this.exportVisible = true
},
onExport() {
if(!this.pageForm.activityId) {
this.$message.warning('请选择活动')
return
}
this.$downLoad('/platform/trainSignUp/data/doExport', this.pageForm)
},
doSearch() {
this.pageForm.pageNumber = 1
this.pageData()
this.exportVisible = false
},
async selectActivity() {
const res = await $.post(loc() + '/selectActivity')
if (res.code === 0) {
this.activityOptions = res.data
if(this.activityOptions.length > 0) {
this.$set(this.pageForm, 'activityId', this.activityOptions[0].id)
}
}
},
async selectCourse() {
const res = await $.post(loc() + '/selectCourse', { activityId: this.pageForm.activityId })
if (res.code === 0) {
this.courseOptions = res.data
}
},
pageData() {
$.post(loc() + '/pageData', this.pageForm).then(res => {
if (res.code === 0) {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
})
},
courseChange() {
const activity = this.activityOptions.find(o => o.id === this.pageForm.activityId)
const type = this.dict.type.trainSignUpType.find(o => o.value === activity.trainType)
this.trainType = type ? type.label : ''
}
},
async created() {
await this.selectActivity()
await this.selectCourse()
this.pageData()
this.courseChange()
}
})
</script>
<!--#
}
#-->