This commit is contained in:
2026-07-20 14:36:55 +08:00
parent fbce4a5a15
commit 64dbcba3c6
17 changed files with 1925 additions and 1007 deletions
@@ -92,6 +92,7 @@ public class EnrollmentRegistrationApplyController {
@SaCheckPermission(value = {"enrollmentRegistration.apply", "h5.enrollmentRegistration.apply"}, mode = SaMode.OR)
@ApiOperation("保存申请")
@SLog(tag = "子女入学管理-子女入学登记", msg = "保存子女入学登记")
@Aop(TransAop.READ_COMMITTED)
public Result save(@Param("data") EnrollmentRegistration enrollmentRegistration) {
enrollmentRegistration.setApplyTime(DateUtil.now());
baseService.insertOrUpdate(enrollmentRegistration);
@@ -117,6 +118,7 @@ public class EnrollmentRegistrationApplyController {
@SaCheckPermission(value = {"enrollmentRegistration.apply", "h5.enrollmentRegistration.apply"}, mode = SaMode.OR)
@ApiOperation("提交申请")
@SLog(tag = "子女入学管理-子女入学登记", msg = "提交子女入学登记")
@Aop(TransAop.READ_COMMITTED)
public Result submit(@Param("data") EnrollmentRegistration enrollmentRegistration) {
if (StrUtil.isBlank(enrollmentRegistration.getId())) {
enrollmentRegistration.setApplyTime(DateUtil.now());
@@ -160,9 +160,22 @@ public class EnrollmentRegistrationSummaryController {
List<JSONObject> huKouFiles = Json.fromJsonAsList(JSONObject.class, item.getString("huKouFiles"));
List<JSONObject> birthCertificateFiles = item.getList("birthCertificateFiles", JSONObject.class);
List<JSONObject> qualificationCertificateFiles = item.getList("qualificationCertificateFiles", JSONObject.class);
List<JSONObject> employmentContractFiles = item.getList("employmentContractFiles", JSONObject.class);
List<JSONObject> mergedList = new ArrayList<>();
mergedList.addAll(huKouFiles);
mergedList.addAll(birthCertificateFiles);
// 历史登记可能缺少新增材料,逐类判空后合并,避免导出旧数据时中断整个压缩包。
if (huKouFiles != null) {
mergedList.addAll(huKouFiles);
}
if (birthCertificateFiles != null) {
mergedList.addAll(birthCertificateFiles);
}
if (qualificationCertificateFiles != null) {
mergedList.addAll(qualificationCertificateFiles);
}
if (employmentContractFiles != null) {
mergedList.addAll(employmentContractFiles);
}
for (JSONObject file : mergedList) {
String fileName = file.getStr("name");
@@ -91,7 +91,7 @@ public class EnrollmentRegistration extends BaseModel implements Serializable {
@Column
@ColDefine(type = ColType.VARCHAR,width = 30)
@Comment("身年月")
@Comment("生日期")
private String childrenBirthday;
@Column
@@ -111,14 +111,29 @@ public class EnrollmentRegistration extends BaseModel implements Serializable {
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("报就读学校")
@Comment("选区域")
private String childrenPlanSchool;
@Column
@ColDefine(type = ColType.VARCHAR,width = 100)
@Comment("拟选学校")
private String childrenPlanSchoolName;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("子女户口所在地")
@Comment("户籍所在地")
private String childrenHuKouAddress;
@Column
@ColDefine(type = ColType.VARCHAR,width = 100)
@Comment("职务、职称")
private String positionTitle;
@Column
@ColDefine(type = ColType.VARCHAR,width = 30)
@Comment("用工方式")
private String employmentType;
@Column
@ColDefine(type = ColType.VARCHAR,width = 50)
@Comment("备注")
@@ -139,6 +154,16 @@ public class EnrollmentRegistration extends BaseModel implements Serializable {
@Comment("子女出生证照片")
private List<JSONObject> birthCertificateFiles;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("学历学位证或教师资格证")
private List<JSONObject> qualificationCertificateFiles;
@Column
@ColDefine(type = ColType.MYSQL_JSON)
@Comment("聘用合同复印件")
private List<JSONObject> employmentContractFiles;
}
@@ -26,7 +26,6 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.util.cri.SqlExpressionGroup;
@@ -52,8 +51,6 @@ import java.util.List;
@Ok("json:full")
public class CondolenceApplyController {
@Inject
private Dao dao;
@Inject
private FlowEngine flowEngine;
@Inject
@@ -71,13 +68,43 @@ public class CondolenceApplyController {
@SaCheckPermission("h5.condolence.apply")
public void h5Index() {}
/**
* 查询慰问申报截止日期。
*
* @return Resultdata 为 yyyy-MM-dd 格式的截止日期字符串;未配置时为空字符串
*/
@At
@ApiOperation("查询慰问申报截止日期")
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
public Result getApplyEndDate() {
return Result.success().addData(condolenceService.getApplyEndDate());
}
/**
* 保存慰问申报截止日期,服务层会再次校验当前用户必须为系统管理员。
*
* @param endDate 截止日期,格式为 yyyy-MM-dd
* @return 保存成功结果
*/
@At
@ApiOperation("保存慰问申报截止日期")
@SaCheckPermission("condolence.apply")
@SLog(tag = "职工慰问系统-慰问申请", msg = "设置申报截止日期:${endDate}")
@Aop(TransAop.READ_COMMITTED)
public Result saveApplyEndDate(@Param("endDate") String endDate) {
condolenceService.saveApplyEndDate(endDate);
return Result.success("设置成功");
}
@At
@ApiOperation("保存申请")
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
@SLog(tag = "职工慰问系统-慰问申请", msg = "保存申请")
@Aop(TransAop.READ_COMMITTED)
public Result save(@Param("data") Condolence condolence) {
condolenceService.checkApplyDeadline(condolence.getId());
if(StrUtil.isBlank(condolence.getId())) condolence.setCreateTime(DateUtil.now());
dao.insertOrUpdate(condolence);
condolenceService.insertOrUpdate(condolence);
return Result.success();
}
@@ -87,8 +114,9 @@ public class CondolenceApplyController {
@SLog(tag = "职工慰问系统-慰问申请", msg = "提交申请")
@Aop(TransAop.READ_COMMITTED)
public Result submit(@Param("data") Condolence condolence) {
condolenceService.checkApplyDeadline(condolence.getId());
if(StrUtil.isBlank(condolence.getId())) condolence.setCreateTime(DateUtil.now());
dao.insertOrUpdate(condolence);
condolenceService.insertOrUpdate(condolence);
// 开启流程实例
Dict args = Dict.create();
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
@@ -108,7 +136,7 @@ public class CondolenceApplyController {
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
public Result submitAgain(@Param("data") Condolence condolence, @Param("taskId") Long taskId) {
dao.insertOrUpdate(condolence);
condolenceService.insertOrUpdate(condolence);
Dict dict = Dict.create();
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
@@ -117,6 +145,12 @@ public class CondolenceApplyController {
return Result.success();
}
/**
* 查询慰问申请可选择的补贴对象或收款人。
*
* @param keyword 姓名或工号关键字;为空时按照当前用户角色范围返回人员
* @return Resultdata 为人员列表,包含人员 ID、姓名、工号、性别、出生年月、联系电话、单位和工会信息
*/
@At
@ApiOperation("查询用户")
@SaCheckPermission(value = {"condolence.apply", "h5.condolence.apply"}, mode = SaMode.OR)
@@ -127,6 +161,7 @@ public class CondolenceApplyController {
username as userName,
loginname as loginName,
sex,
birthday,
mobile,
technicalTitle,
IFNULL(unitname, '暂无') as unitName,
@@ -1,30 +1,20 @@
package com.budwk.app.zhgh.staffbenefit.condolence.controller;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.PageUtil;
import com.budwk.app.flow.entity.ProcessInstance;
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
import com.budwk.app.sys.param.SysMsgSummaryPageForm;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
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.util.cri.SqlExpressionGroup;
@@ -36,16 +26,9 @@ import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName CondolenceReadController
* @Author JyuHsin
* @Date 2025/7/29 16:25
* @Version 1.0
* @Description TODO
* 职工慰问阅览。
*/
@Slf4j
@IocBean
@@ -63,22 +46,40 @@ public class CondolenceReadController {
public void index() {
}
/**
* 按月份范围及页面筛选条件分页查询慰问记录。
*
* @param pageForm 分页、排序及姓名或工号关键字参数
* @param startMonth 开始月份,格式为 yyyy-MM;为空时不限制开始月份
* @param endMonth 结束月份,格式为 yyyy-MM;为空时不限制结束月份
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @return Resultdata 为包含 list、totalCount 等分页字段的 Pagination 数据
*/
@At
@ApiOperation("分页查询")
@SaCheckPermission("condolence.read")
public Result pageData(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "startMonth") String startMonth,
@Param(value = "endMonth") String endMonth,
@Param(value = "type") String type,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId) {
// 当前节点只取进行中的任务;流程结束后没有活动任务,按实例状态显示“已完结”或“已拒绝”。
Sql sql = Sqls.create("""
SELECT
info.*,
ins.id AS instanceId,
type.name as typeName,
COALESCE(NULLIF(info.typeCode, ''), type.code) AS exportTypeCode,
ins.state instanceState,
ins.processDefineId instanceProcessDefineId,
t.displayName taskName
CASE
WHEN ins.state = 20 THEN '已完结'
WHEN ins.state = 45 THEN '已拒绝'
ELSE t.displayName
END AS taskName
FROM
condolence info
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
@@ -87,15 +88,17 @@ public class CondolenceReadController {
processInstanceId,
displayName,
createdAt,
ROW_NUMBER() OVER (PARTITION BY processInstanceId ORDER BY createdAt DESC) AS rn
ROW_NUMBER() OVER (PARTITION BY processInstanceId ORDER BY createdAt DESC, id DESC) AS rn
FROM wf_process_task
WHERE taskState = 10
) t ON t.processInstanceId = ins.id AND t.rn = 1
LEFT JOIN condolence_type type ON info.type = type.id
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.andEX("info.type", "=", type);
cnd.andEX("YEAR(info.createTime)", "=", year);
cnd.andEX("DATE_FORMAT(info.createTime,'%Y-%m')", ">=", startMonth);
cnd.andEX("DATE_FORMAT(info.createTime,'%Y-%m')", "<=", endMonth);
cnd.andEX("info.applyUnionId", "=", unionId);
cnd.andEX("info.applyUnitId", "=", unitId);
@@ -120,58 +123,108 @@ public class CondolenceReadController {
return Result.success(pageVO);
}
/**
* 导出申报人汇总 Excel。
*
* @param pageForm 页面查询参数,searchKeyword 为慰问对象姓名或工号
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @param response 文件下载响应,内容为 xlsx
*/
@At
@Ok("void")
@SaCheckPermission("condolence.read")
@ApiOperation("导出职工慰问汇总")
@ApiOperation("导出申报人汇总")
public void onExport(PageForm pageForm,
@Param(value = "year") Integer year,
@Param(value = "startMonth") String startMonth,
@Param(value = "endMonth") String endMonth,
@Param(value = "type") String type,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId,
HttpServletResponse response) {
//查询审核通过的数据
Sql sql = Sqls.create("""
select
con.*,
type.name as typeName
from
condolence con
left join wf_process_instance ins on ins.businessNo = con.id
left join condolence_type type on type.id = con.type
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and(ProcessInstance::getState, "=", ProcessTaskStateEnum.FINISHED.getCode());
cnd.andEX("con.type", "=", type);
cnd.andEX("YEAR(info.createTime)", "=", year);
cnd.andEX("con.applyUnionId", "=", unionId);
cnd.andEX("con.applyUnitId", "=", unitId);
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup seg = new SqlExpressionGroup();
seg.or("info.helpUserName", "like", "%" + pageForm.getSearchKeyword() + "%");
seg.or("info.helpLoginName", "like", "%" + pageForm.getSearchKeyword() + "%");
cnd.and(seg);
}
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("con.applyUnionId", "=", SecurityUtil.getUnionId());
}
sql.setCondition(cnd);
List<NutMap> list = condolenceService.listMap(sql);
validateExportMonthRange(startMonth, endMonth);
condolenceService.exportSummary(pageForm, startMonth, endMonth, type, unionId, unitId, response);
}
List<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("慰问对象", "helpUserName", 20));
exportEntities.add(new ExcelExportEntity("慰问对象工号", "helpLoginName", 20));
exportEntities.add(new ExcelExportEntity("申请人", "applyUserName", 20));
exportEntities.add(new ExcelExportEntity("所在工会", "helpUnionName", 20));
exportEntities.add(new ExcelExportEntity("所在单位", "helpUnitName", 20));
exportEntities.add(new ExcelExportEntity("慰问类型", "typeName", 20));
exportEntities.add(new ExcelExportEntity("拟补贴金额", "money", 20));
exportEntities.add(new ExcelExportEntity("申请理由", "remark", 20));
/**
* 导出单条工会领条 Word。
*
* @param id 慰问申请 ID
* @param response 文件下载响应,内容为 docx
*/
@At
@Ok("void")
@SaCheckPermission("condolence.read")
@ApiOperation("导出工会领条")
public void onExportReceipt(@Param("id") String id, HttpServletResponse response) {
if (StrUtil.isBlank(id)) {
throw new BaseException("慰问申请ID不能为空");
}
condolenceService.exportReceipt(id, response);
}
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
CommonDownloadUtil.download("申报人汇总.xlsx", workbook, response);
/**
* 导出生育慰问补贴登记表 Word。
*
* @param id 慰问申请 ID,且慰问类型必须为生育慰问或生育双胎慰问
* @param response 文件下载响应,内容为 docx
*/
@At
@Ok("void")
@SaCheckPermission("condolence.read")
@ApiOperation("导出补贴登记表")
public void onExportSubsidyRegistration(@Param("id") String id, HttpServletResponse response) {
if (StrUtil.isBlank(id)) {
throw new BaseException("慰问申请ID不能为空");
}
condolenceService.exportSubsidyRegistration(id, response);
}
/**
* 按当前页面筛选条件导出慰问资料压缩包。
*
* @param pageForm 页面查询参数,searchKeyword 为慰问对象姓名或工号
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @param response 文件下载响应,内容为 zip
*/
@At
@Ok("void")
@SaCheckPermission("condolence.read")
@ApiOperation("导出慰问资料压缩包")
public void onExportZip(PageForm pageForm,
@Param(value = "startMonth") String startMonth,
@Param(value = "endMonth") String endMonth,
@Param(value = "type") String type,
@Param(value = "unionId") String unionId,
@Param(value = "unitId") String unitId,
HttpServletResponse response) {
validateExportMonthRange(startMonth, endMonth);
condolenceService.exportZip(pageForm, startMonth, endMonth, type, unionId, unitId, response);
}
/**
* 校验批量导出的月份范围,避免缺少条件时误导出全部数据。
*
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
*/
private void validateExportMonthRange(String startMonth, String endMonth) {
if (StrUtil.isBlank(startMonth) || StrUtil.isBlank(endMonth)) {
throw new BaseException("请选择需要导出的月份");
}
if (!startMonth.matches("\\d{4}-(0[1-9]|1[0-2])")
|| !endMonth.matches("\\d{4}-(0[1-9]|1[0-2])")) {
throw new BaseException("月份格式不正确");
}
if (startMonth.compareTo(endMonth) > 0) {
throw new BaseException("开始月份不能晚于结束月份");
}
}
}
@@ -100,6 +100,21 @@ public class Condolence extends BaseModel {
@ColDefine(type = ColType.VARCHAR, width = 100)
private String helpUnitName;
@Column
@Comment("补助人性别")
@ColDefine(type = ColType.VARCHAR, width = 10)
private String sex;
@Column
@Comment("补助人联系电话")
@ColDefine(type = ColType.VARCHAR, width = 30)
private String mobile;
@Column
@Comment("补助人出生年月")
@ColDefine(type = ColType.VARCHAR, width = 30)
private String birthday;
@Column
@Comment("类型")
@ColDefine(type = ColType.VARCHAR, width = 20)
@@ -180,6 +195,11 @@ public class Condolence extends BaseModel {
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> files;
@Column
@Comment("纸质申请表")
@ColDefine(type = ColType.MYSQL_JSON)
private List<JSONObject> applyFiles;
@Comment("签字")
@ColDefine(type = ColType.VARCHAR, width = 255)
@Column(hump = true)
@@ -293,4 +313,12 @@ public class Condolence extends BaseModel {
@ColDefine(type = ColType.INT)
private Integer thisYearHospitalizationNum;
/**
* 旧系统慰问申请单据号,仅用于保留历史数据的原始编号。
*/
@Column
@Comment("旧系统单据号")
@ColDefine(type = ColType.INT)
private Integer legacyDocumentNo;
}
@@ -1,8 +1,11 @@
package com.budwk.app.zhgh.staffbenefit.condolence.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
import javax.servlet.http.HttpServletResponse;
/**
* @ClassName CondolenceService
* @Author JyuHsin
@@ -11,4 +14,68 @@ import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
* @Description TODO
*/
public interface CondolenceService extends BaseService<Condolence> {
/**
* 查询慰问申报截止日期。
*
* @return 截止日期,格式为 yyyy-MM-dd;未配置时返回空字符串
*/
String getApplyEndDate();
/**
* 保存慰问申报截止日期,仅允许系统管理员操作。
*
* @param endDate 截止日期,格式为 yyyy-MM-dd
*/
void saveApplyEndDate(String endDate);
/**
* 校验新慰问申请是否已超过申报截止日期。
*
* @param condolenceId 慰问申请 ID;为空表示新申请,已有 ID 的草稿或退回申请不受截止日期限制
*/
void checkApplyDeadline(String condolenceId);
/**
* 导出审核完成的慰问申报人汇总表。
*
* @param pageForm 页面查询参数,searchKeyword 为慰问对象姓名或工号
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @param response HTTP 文件下载响应
*/
void exportSummary(PageForm pageForm, String startMonth, String endMonth, String type, String unionId, String unitId,
HttpServletResponse response);
/**
* 导出单条审核完成记录的工会领条 Word。
*
* @param id 慰问申请 ID
* @param response HTTP 文件下载响应
*/
void exportReceipt(String id, HttpServletResponse response);
/**
* 导出单条审核完成的生育慰问补贴登记表 Word。
*
* @param id 慰问申请 ID
* @param response HTTP 文件下载响应
*/
void exportSubsidyRegistration(String id, HttpServletResponse response);
/**
* 按页面查询条件批量生成慰问资料压缩包。
*
* @param pageForm 页面查询参数,searchKeyword 为慰问对象姓名或工号
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @param response HTTP 文件下载响应
*/
void exportZip(PageForm pageForm, String startMonth, String endMonth, String type, String unionId, String unitId,
HttpServletResponse response);
}
@@ -1,24 +1,549 @@
package com.budwk.app.zhgh.staffbenefit.condolence.service.impl;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.constant.RoleConstant;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.MoneyUtil;
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
import com.budwk.app.flow.engine.FlowEngine;
import com.budwk.app.flow.entity.ProcessTask;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.flow.vo.ProcessTaskVO;
import com.budwk.app.sys.models.Sys_config;
import com.budwk.app.sys.models.Sys_file;
import com.budwk.app.sys.services.SysConfigService;
import com.budwk.app.sys.utils.SysFileMinIoUtil;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.web.commons.base.Globals;
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceService;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.PictureRenderData;
import com.deepoove.poi.data.PictureType;
import com.deepoove.poi.data.Pictures;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
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.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.lang.util.NutMap;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @ClassName CondolenceServiceImpl
* @Author JyuHsin
* @Date 2025/7/29 11:22
* @Version 1.0
* @Description TODO
* 职工慰问业务服务。
*/
@Slf4j
@IocBean(args = {"refer:dao"})
public class CondolenceServiceImpl extends BaseServiceImpl<Condolence> implements CondolenceService {
private static final String RECEIPT_TEMPLATE_CODE = "condolence_lt";
private static final String SUBSIDY_TEMPLATE_CODE = "zgww_must_visit";
private static final String APPLY_END_DATE_CONFIG_KEY = "CondolenceApplyEndDate";
private static final List<String> BIRTH_TYPE_CODES = List.of("A", "B");
@Inject
private FlowEngine flowEngine;
@Inject
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
@Inject
private SysConfigService sysConfigService;
public CondolenceServiceImpl(Dao dao) {
super(dao);
}
@Override
public String getApplyEndDate() {
Sys_config config = sysConfigService.fetch(APPLY_END_DATE_CONFIG_KEY);
return config == null ? "" : StrUtil.blankToDefault(config.getConfigValue(), "");
}
/**
* 保存慰问申报截止日期。参数必须是 yyyy-MM-dd,且仅 SYSADMIN 可以修改。
*
* @param endDate 截止日期,格式为 yyyy-MM-dd
*/
@Override
@Aop(TransAop.READ_COMMITTED)
public void saveApplyEndDate(String endDate) {
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
throw new BaseException("仅系统管理员可以设置慰问申报时间");
}
parseApplyEndDate(endDate);
Sys_config config = sysConfigService.fetch(APPLY_END_DATE_CONFIG_KEY);
if (config == null) {
config = new Sys_config();
config.setConfigKey(APPLY_END_DATE_CONFIG_KEY);
config.setConfigValue(endDate);
config.setNote("慰问申报截止日期");
sysConfigService.insert(config);
return;
}
config.setConfigValue(endDate);
sysConfigService.update(config);
}
@Override
public void checkApplyDeadline(String condolenceId) {
// 与旧系统保持一致:已有申请可以继续保存或重新提交,仅限制新申请。
if (StrUtil.isNotBlank(condolenceId)) {
return;
}
String endDate = getApplyEndDate();
if (StrUtil.isBlank(endDate)) {
return;
}
LocalDate deadline = parseApplyEndDate(endDate);
if (!LocalDate.now().isBefore(deadline)) {
throw new BaseException("本次申报已截止请关注下次申报");
}
}
/**
* 校验并解析慰问申报截止日期。
*
* @param endDate 截止日期,必须为 yyyy-MM-dd
* @return 解析后的日期
*/
private LocalDate parseApplyEndDate(String endDate) {
if (StrUtil.isBlank(endDate)) {
throw new BaseException("申报截止日期不能为空");
}
try {
return LocalDate.parse(endDate);
} catch (DateTimeParseException e) {
throw new BaseException("申报截止日期格式不正确,应为yyyy-MM-dd");
}
}
@Override
public void exportSummary(PageForm pageForm, String startMonth, String endMonth, String type, String unionId,
String unitId,
HttpServletResponse response) {
List<NutMap> list = queryFinishedList(pageForm, startMonth, endMonth, type, unionId, unitId);
List<ExcelExportEntity> exportEntities = new ArrayList<>();
exportEntities.add(new ExcelExportEntity("慰问对象", "helpUserName", 20));
exportEntities.add(new ExcelExportEntity("慰问对象工号", "helpLoginName", 20));
exportEntities.add(new ExcelExportEntity("申请人", "applyUserName", 20));
exportEntities.add(new ExcelExportEntity("所在工会", "helpUnionName", 20));
exportEntities.add(new ExcelExportEntity("所在单位", "helpUnitName", 20));
exportEntities.add(new ExcelExportEntity("慰问类型", "typeName", 20));
exportEntities.add(new ExcelExportEntity("拟补贴金额", "money", 20));
exportEntities.add(new ExcelExportEntity("申请理由", "remark", 20));
// Excel 导出统一使用 XSSF,避免旧版 xls 行数和格式限制。
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
CommonDownloadUtil.download("申报人汇总.xlsx", workbook, response);
}
@Override
public void exportReceipt(String id, HttpServletResponse response) {
NutMap record = findExportRecord(id);
if (!ProcessInstanceStateEnum.FINISHED.getCode().equals(record.getInt("instanceState"))) {
throw new BaseException("仅流程已完成的慰问申请可以导出工会领条");
}
if (isBirthType(record.getString("typeCode"))) {
throw new BaseException("生育慰问请导出补贴登记表");
}
byte[] docx = buildDocx(record, false, RECEIPT_TEMPLATE_CODE);
String fileName = Globals.AppName + "工会领条_" + safeFileName(record.getString("helpUserName")) + ".docx";
CommonDownloadUtil.download(fileName, docx, response);
}
@Override
public void exportSubsidyRegistration(String id, HttpServletResponse response) {
NutMap record = findExportRecord(id);
if (!ProcessInstanceStateEnum.FINISHED.getCode().equals(record.getInt("instanceState"))) {
throw new BaseException("仅流程已完成的慰问申请可以导出补贴登记表");
}
if (!isBirthType(record.getString("typeCode"))) {
throw new BaseException("仅生育慰问可以导出补贴登记表");
}
byte[] docx = buildDocx(record, true, SUBSIDY_TEMPLATE_CODE);
String fileName = Globals.AppName + "教职工生育补贴登记表_"
+ safeFileName(record.getString("helpUserName")) + ".docx";
CommonDownloadUtil.download(fileName, docx, response);
}
@Override
public void exportZip(PageForm pageForm, String startMonth, String endMonth, String type, String unionId,
String unitId,
HttpServletResponse response) {
List<NutMap> list = queryFinishedList(pageForm, startMonth, endMonth, type, unionId, unitId);
if (list.isEmpty()) {
throw new BaseException("当前条件下没有已完成的慰问申请可导出");
}
String zipName = startMonth + "" + endMonth + "慰问补贴.zip";
response.setContentType("application/zip;charset=UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(zipName));
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
// 直接向响应流写 ZIP,不在服务器生成临时目录,避免并发导出时残留文件。
try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
for (NutMap row : list) {
NutMap record = findExportRecord(row.getString("id"));
boolean birthType = isBirthType(record.getString("typeCode"));
String folderName = safeFileName(record.getString("helpUserName") + "-"
+ record.getString("typeName") + "-" + record.getString("id"));
String documentName = birthType ? Globals.AppName + "教职工生育补贴登记表.docx"
: Globals.AppName + "工会领条.docx";
zipOutputStream.putNextEntry(new ZipEntry(folderName + "/" + safeFileName(documentName)));
String templateCode = birthType ? SUBSIDY_TEMPLATE_CODE : RECEIPT_TEMPLATE_CODE;
zipOutputStream.write(buildDocx(record, birthType, templateCode));
zipOutputStream.closeEntry();
}
zipOutputStream.finish();
} catch (IOException e) {
log.error("职工慰问压缩包导出失败:{}", e.getMessage(), e);
throw new BaseException("职工慰问压缩包导出失败:{}", e.getMessage());
}
}
/**
* 查询符合页面筛选条件且 wf 流程已完成的慰问记录。
*
* @param pageForm 页面分页和关键字参数,仅使用 searchKeyword
* @param startMonth 开始月份,格式为 yyyy-MM
* @param endMonth 结束月份,格式为 yyyy-MM
* @param type 慰问类型 ID
* @param unionId 申请人所属工会 ID
* @param unitId 申请人所属单位 ID
* @return 导出记录列表,每项包含慰问信息、类型名称和 wf 实例信息
*/
private List<NutMap> queryFinishedList(PageForm pageForm, String startMonth, String endMonth, String type,
String unionId, String unitId) {
Sql sql = Sqls.create("""
SELECT
con.*,
type.name AS typeName,
type.code AS currentTypeCode,
ins.id AS instanceId,
ins.state AS instanceState
FROM condolence con
LEFT JOIN wf_process_instance ins ON ins.businessNo = con.id
LEFT JOIN condolence_type type ON type.id = con.type
$condition
""");
Cnd cnd = Cnd.NEW();
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
cnd.andEX("con.type", "=", type);
cnd.andEX("DATE_FORMAT(con.createTime,'%Y-%m')", ">=", startMonth);
cnd.andEX("DATE_FORMAT(con.createTime,'%Y-%m')", "<=", endMonth);
cnd.andEX("con.applyUnionId", "=", unionId);
cnd.andEX("con.applyUnitId", "=", unitId);
if (pageForm != null && StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
SqlExpressionGroup group = new SqlExpressionGroup();
group.or("con.helpUserName", "like", "%" + pageForm.getSearchKeyword() + "%");
group.or("con.helpLoginName", "like", "%" + pageForm.getSearchKeyword() + "%");
cnd.and(group);
}
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
cnd.and("con.applyUnionId", "=", SecurityUtil.getUnionId());
}
cnd.desc("con.createTime");
sql.setCondition(cnd);
return listMap(sql);
}
/**
* 查询生成 Word 所需的完整记录。
*
* @param id 慰问申请 ID
* @return 慰问信息、类型信息和 wf 实例信息
*/
private NutMap findExportRecord(String id) {
Sql sql = Sqls.create("""
SELECT
con.*,
type.name AS typeName,
type.code AS currentTypeCode,
helpUser.idCard AS exportIdCard,
helpUser.homeAddress AS exportHomeAddress,
COALESCE(NULLIF(con.sex, ''), helpUser.sex) AS exportSex,
COALESCE(NULLIF(con.mobile, ''), helpUser.mobile) AS exportMobile,
TIMESTAMPDIFF(
YEAR,
COALESCE(STR_TO_DATE(NULLIF(con.birthday, ''), '%Y-%m-%d'), helpUser.birthday),
CURDATE()
) AS exportAge,
ins.id AS instanceId,
ins.state AS instanceState
FROM condolence con
LEFT JOIN wf_process_instance ins ON ins.businessNo = con.id
LEFT JOIN condolence_type type ON type.id = con.type
LEFT JOIN vw_user helpUser ON helpUser.id = con.helpUserId
WHERE con.id = @id
""").setParam("id", id);
sql.setCallback(Sqls.callback.map());
dao().execute(sql);
NutMap record = (NutMap) sql.getResult();
if (record == null) {
throw new BaseException("慰问申请不存在");
}
// 历史数据可能未保存 typeCode,以类型表当前编码作为兼容值。
if (StrUtil.isBlank(record.getString("typeCode"))) {
record.put("typeCode", record.getString("currentTypeCode"));
}
// 非校级管理员只能导出本工会数据,避免通过手工拼接 ID 越权下载。
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())
&& !StrUtil.equals(record.getString("applyUnionId"), SecurityUtil.getUnionId())) {
throw new BaseException("无权导出该慰问申请");
}
return record;
}
/**
* 组装模板数据并生成 Word 字节数组。
*
* @param record 慰问信息,必须包含 instanceId、typeCode 和 files
* @param includeAttachmentPictures 是否把图片附件组装到模板 picFiles 列表
* @param templateCode 系统 Office 模板编码,工会领条为 condolence_lt,补贴登记表为 zgww_must_visit
* @return docx 文件字节数组
*/
private byte[] buildDocx(NutMap record, boolean includeAttachmentPictures, String templateCode) {
prepareTemplateData(record, includeAttachmentPictures);
try (InputStream templateStream = sysOfficeTemplateUtil.getTemplate(templateCode);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
XWPFTemplate.compile(templateStream).render(record).writeAndClose(outputStream);
return outputStream.toByteArray();
} catch (Exception e) {
log.error("职工慰问 Word 导出失败,申请ID:{},错误信息:{}", record.getString("id"), e.getMessage(), e);
throw new BaseException("职工慰问 Word 导出失败:{}", e.getMessage());
}
}
/**
* 填充模板所需的金额大写、签名、审批意见和附件图片。
*
* @param record 慰问记录
* @param includeAttachmentPictures 是否读取 MinIO 图片附件
*/
private void prepareTemplateData(NutMap record, boolean includeAttachmentPictures) {
record.put("schoolName", Globals.AppName);
record.put("be_username", record.getString("helpUserName"));
record.put("be_idcard", record.getString("exportIdCard"));
record.put("be_sex", record.getString("exportSex"));
record.put("age", record.get("exportAge") == null ? "" : record.get("exportAge"));
record.put("be_loginname", record.getString("helpLoginName"));
record.put("be_unionname", record.getString("helpUnionName"));
record.put("be_unitname", record.getString("helpUnitName"));
record.put("unitname", record.getString("helpUnitName"));
record.put("jtzz", record.getString("exportHomeAddress"));
record.put("mobile", record.getString("exportMobile"));
// 当前业务数据未保存配偶所在单位,模板字段保留为空,避免误用其他单位信息。
record.put("poszdw", "");
record.put("typename", record.getString("typeName"));
record.put("payee_username", record.getString("payUserName"));
record.put("payee_loginname", record.getString("payLoginName"));
record.put("payee_bank_number", record.getString("bankCardNumber"));
record.put("manager_name", StrUtil.blankToDefault(record.getString("handlerUserName"),
record.getString("applyUserName")));
record.put("apply_time", record.getString("createTime"));
try {
String moneyUpper = record.get("money") == null ? "" : MoneyUtil.toRMBUpper(record.get("money").toString());
record.put("moneyBig", moneyUpper);
record.put("money_big", moneyUpper);
} catch (Exception e) {
log.warn("慰问金额转大写失败,申请ID:{},金额:{}", record.getString("id"), record.get("money"));
record.put("moneyBig", "");
record.put("money_big", "");
}
if (StrUtil.isNotBlank(record.getString("signature"))) {
PictureRenderData applicantSign = sysOfficeTemplateUtil.createPictureRenderData(record.getString("signature"));
record.put("applicantSign", applicantSign);
record.put("ms", applicantSign);
}
fillApprovalData(record);
if (includeAttachmentPictures) {
record.put("picFiles", buildAttachmentPictures(record));
}
}
/**
* 将 wf 已办任务转换为模板审批节点数据。
*
* @param record 慰问记录,instanceId 为 wf 流程实例 ID
*/
private void fillApprovalData(NutMap record) {
Long instanceId = record.getLong("instanceId");
if (instanceId == null) {
return;
}
List<Map<String, Object>> approvals = new ArrayList<>();
List<ProcessTask> doneTasks = flowEngine.processTaskService().getDoneTaskList(instanceId, null);
for (ProcessTask doneTask : doneTasks) {
ProcessTaskVO task = flowEngine.processTaskService().findById(doneTask.getId());
if ("提交申请".equals(task.getDisplayName())) {
continue;
}
Dict taskFormData = task.getTaskFormData();
Map<String, Object> approval = new HashMap<>();
approval.put("nodeName", task.getDisplayName());
approval.put("user", taskFormData.getStr("userName"));
approval.put("opinion", taskFormData.getStr("opinion"));
approval.put("date", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy年MM月dd日"));
approval.put("time", task.getFinishTime());
if (StrUtil.isNotBlank(taskFormData.getStr("sign"))) {
approval.put("sign", sysOfficeTemplateUtil.createPictureRenderData(taskFormData.getStr("sign")));
}
approvals.add(approval);
bindApprovalNode(record, task.getDisplayName(), approval);
}
record.put("approvals", approvals);
}
/**
* 同时提供新版和旧版模板常用的审批节点键,保证系统模板平滑迁移。
*
* @param record 模板数据
* @param nodeName wf 节点显示名称
* @param approval 审批人、意见、日期和签名
*/
private void bindApprovalNode(NutMap record, String nodeName, Map<String, Object> approval) {
if (StrUtil.contains(nodeName, "分工会")) {
record.put("fgh", approval);
record.put("ucr", approval.get("sign"));
record.put("ucrTime", approval.get("date"));
record.put("ucrOpinion", approval.get("opinion"));
} else if (StrUtil.contains(nodeName, "校工会")) {
record.put("xgh", approval);
record.put("vcr", approval.get("sign"));
record.put("vcrTime", approval.get("date"));
record.put("vcrOpinion", approval.get("opinion"));
} else if (StrUtil.containsAny(nodeName, "校领导", "学校领导", "主席")) {
record.put("xld", approval);
record.put("ecr", approval.get("sign"));
record.put("ecrTime", approval.get("date"));
record.put("ecrOpinion", approval.get("opinion"));
}
}
/**
* 将上传组件保存的附件 JSON 转换为 poi-tl 图片列表。
*
* @param record 慰问记录,files 为上传组件 complete_result 数组
* @return 图片及原文件名列表,供模板循环渲染
*/
private List<Map<String, Object>> buildAttachmentPictures(NutMap record) {
List<Map<String, Object>> pictures = new ArrayList<>();
Object filesValue = record.get("files");
if (filesValue == null) {
return pictures;
}
List<JSONObject> files;
try {
String filesJson = filesValue instanceof String ? filesValue.toString() : JSONUtil.toJsonStr(filesValue);
files = JSONUtil.toList(filesJson, JSONObject.class);
} catch (Exception e) {
log.warn("慰问附件数据格式错误,申请ID{}", record.getString("id"));
return pictures;
}
for (JSONObject file : files) {
String fileUrl = extractFileUrl(file);
String fileId = extractFileId(fileUrl);
if (StrUtil.isBlank(fileId)) {
continue;
}
Sys_file sysFile = dao().fetch(Sys_file.class, fileId);
if (sysFile == null) {
continue;
}
byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
if (bytes == null || bytes.length == 0) {
continue;
}
try {
PictureType pictureType = PictureType.suggestFileType(bytes);
PictureRenderData picture = Pictures.ofBytes(bytes, pictureType).size(100, 100).create();
Map<String, Object> pictureData = new HashMap<>();
pictureData.put("file", picture);
pictureData.put("fileName", StrUtil.blankToDefault(file.getStr("name"), sysFile.getName()));
pictures.add(pictureData);
} catch (Exception e) {
// 非图片附件不参与 Word 图片循环,附件本身仍保留在系统文件中。
log.debug("慰问附件不是可渲染图片,文件ID{}", fileId);
}
}
return pictures;
}
/**
* 从 complete_result 附件对象中读取下载地址。
*
* @param file 上传组件附件对象
* @return 下载地址或文件 ID
*/
private String extractFileUrl(JSONObject file) {
JSONObject response = file.getJSONObject("response");
if (response != null && StrUtil.isNotBlank(response.getStr("data"))) {
return response.getStr("data");
}
return file.getStr("url");
}
/**
* 从下载地址中截取 sys_file 主键。
*
* @param fileUrl 下载地址或文件 ID
* @return sys_file 主键
*/
private String extractFileId(String fileUrl) {
if (StrUtil.isBlank(fileUrl)) {
return null;
}
String fileId = fileUrl.contains("=") ? StrUtil.subAfter(fileUrl, "=", true) : fileUrl;
return StrUtil.subBefore(fileId, "&", false);
}
private boolean isBirthType(String typeCode) {
return BIRTH_TYPE_CODES.contains(typeCode);
}
/**
* 清理 ZIP 路径和下载文件名中的 Windows 非法字符及路径片段。
*
* @param fileName 原文件名
* @return 可安全用于 ZIP 条目的文件名
*/
private String safeFileName(String fileName) {
String safeName = StrUtil.blankToDefault(fileName, "未命名").replaceAll("[\\\\/:*?\"<>|]", "_");
return safeName.replace("..", "_");
}
}
@@ -4,11 +4,11 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<el-card shadow="never">
<custom-card>
<snaker-start slot="header" label="子女入学登记" define_key="ZNRXDJ"></snaker-start>
<el-form :model="formData" ref="formRef" class="flow-task-form">
<el-descriptions :column="2" border>
<el-descriptions-item label="登记类型" :span="2">
<el-descriptions :column="3" border>
<el-descriptions-item label="登记类型" :span="3">
<el-form-item prop="registrationType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-radio-group v-model="formData.registrationType">
@@ -20,39 +20,6 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="监护人(教工)姓名">
{{formData.userName}}
</el-descriptions-item>
<el-descriptions-item label="工号">
{{formData.loginName}}
</el-descriptions-item>
<el-descriptions-item label="手机号码">
<el-form-item prop="mobile"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.mobile" placeholder="请输入手机号码"
maxlength="20"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所在单位">
{{formData.unitName}}
</el-descriptions-item>
<el-descriptions-item label="监护人与学生关系">
<el-form-item prop="childRelationship"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select clearable placeholder="请选择监护人与学生关系"
style="width: 100%;"
v-model="formData.childRelationship">
<el-option :label="item.name" :value="item.code"
v-for="item in dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="子女姓名">
<el-form-item prop="childrenName"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
@@ -73,6 +40,19 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生日期">
<el-form-item prop="childrenBirthday"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-date-picker
v-model="formData.childrenBirthday"
type="date"
placeholder="请选择出生日期"
style="width: 100%;"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="身份证号">
<el-form-item prop="childrenIdCard"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
@@ -82,31 +62,27 @@ layout("/layouts/platform.html"){
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="子女出生年月">
<el-form-item prop="childrenBirthday"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-date-picker
v-model="formData.childrenBirthday"
type="date"
placeholder="请选择子女出生年月"
style="width: 100%;"
value-format="yyyy-MM-dd">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="现就读学校">
<el-descriptions-item label="读学校">
<el-form-item prop="childrenCurrentSchool"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.childrenCurrentSchool" placeholder="请输入现就读学校"
maxlength="30"></el-input>
<el-input v-model="formData.childrenCurrentSchool" placeholder="请输入读学校"
maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="拟报就读学校">
<el-descriptions-item label="户籍所在地">
<el-form-item prop="childrenHuKouAddress"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.childrenHuKouAddress" placeholder="请输入户籍所在地"
maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="拟选区域">
<el-form-item prop="childrenPlanSchool"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select clearable placeholder="请选择拟报就读学校"
<el-select clearable placeholder="请选择拟选区域"
style="width: 100%;"
v-model="formData.childrenPlanSchool">
<el-option :label="item.name" :value="item.code"
@@ -115,37 +91,103 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="子女户口所在地">
<el-form-item prop="childrenHuKouAddress"
<el-descriptions-item label="拟选学校">
<el-form-item prop="childrenPlanSchoolName"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.childrenHuKouAddress" placeholder="请输入子女户口所在地"
maxlength="30"></el-input>
<el-input v-model="formData.childrenPlanSchoolName" placeholder="请输入拟选学校"
maxlength="100"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="教职工姓名">
{{formData.userName}}
</el-descriptions-item>
<el-descriptions-item label="备注">
<el-form-item prop="note"
<el-descriptions-item label="工号">
{{formData.loginName}}
</el-descriptions-item>
<el-descriptions-item label="职务、职称">
<el-form-item prop="positionTitle"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.note" placeholder="请填写户籍所在地派出所"
maxlength="50"></el-input>
<el-input v-model="formData.positionTitle" placeholder="请输入职务、职称"
maxlength="100"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="户口簿照片" :span="2">
<el-descriptions-item label="手机号码">
<el-form-item prop="mobile"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="formData.mobile" placeholder="请输入手机号码"
maxlength="20"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="所在单位">
{{formData.unitName}}
</el-descriptions-item>
<el-descriptions-item label="用工方式">
<el-form-item prop="employmentType"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select clearable placeholder="请选择用工方式"
style="width: 100%;"
v-model="formData.employmentType">
<el-option label="老体制" value="老体制"></el-option>
<el-option label="人事代理" value="人事代理"></el-option>
<el-option label="年薪制" value="年薪制"></el-option>
<el-option label="二级单位自聘" value="二级单位自聘"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="备注" :span="3">
<el-form-item prop="note">
<el-input v-model="formData.note" placeholder="请输入备注"
type="textarea" maxlength="100" show-word-limit></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="户口簿图片" :span="3">
<el-form-item prop="huKouFiles"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<file-upload :upload_number="10" :value.sync="formData.huKouFiles"
upload_result_type="url"
upload_text="请上传户口首页户主页、父母和子女页"
upload_text="请上传首页户主子女页"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="子女出生证片" :span="2">
<el-form-item prop="birthCertificateFiles">
<el-descriptions-item label="子女出生证片" :span="3">
<el-form-item prop="birthCertificateFiles"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<file-upload :upload_number="10" :value.sync="formData.birthCertificateFiles"
upload_result_type="url"
upload_text="请上传子女出生证图片"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="学历学位证或教师资格证" :span="3">
<el-form-item prop="qualificationCertificateFiles"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<file-upload :upload_number="10" :value.sync="formData.qualificationCertificateFiles"
upload_result_type="url"
upload_text="请上传教职工学历学位证或教师资格证"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="聘用合同复印件" :span="3">
<el-form-item prop="employmentContractFiles"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<file-upload :upload_number="10" :value.sync="formData.employmentContractFiles"
upload_result_type="url"
upload_text="请上传聘用合同复印件"
complete_result upload_mode="drag"
upload_result_category="array"></file-upload>
</el-form-item>
@@ -153,33 +195,32 @@ layout("/layouts/platform.html"){
</el-descriptions>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交</el-button>
</el-row>
</el-card>
<template slot="footer">
<el-button type="primary" plain :loading="formLoading" @click="onSave">保存</el-button>
<el-button type="primary" :loading="formLoading" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" :loading="formLoading" @click="onFinishTask" v-else>提交</el-button>
</template>
</custom-card>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
dicts: ["ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
mixins: [initTableMixins],
data() {
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
registrationTypeOption: [],
childRelationshipOption: [],
}
},
methods: {
getEnrollmentRegistrationPlan() {
this.$axios.post("/platform/enrollmentRegistration/apply/getEnrollmentRegistrationPlan").then(res => {
if (res.code === 0) {
this.registrationTypeOption = res.data
this.$set(this, "registrationTypeOption", res.data)
}
})
},
@@ -188,7 +229,7 @@ layout("/layouts/platform.html"){
return "请选择登记类型"
}
if (!this.formData.childrenBirthday) {
return "请选择子女出生年月"
return "请选择出生日期"
}
const childrenBirthday = new Date(this.formData.childrenBirthday);
@@ -236,11 +277,14 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
this.$axios.post('/platform/enrollmentRegistration/apply/save', {data: JSON.stringify(this.formData)}).then(res => {
if (res.code === 0) {
this.$message.success("保存成功")
commonUtil.pjaxPush('/platform/enrollmentRegistration/applyList/index')
}
}).finally(() => {
this.formLoading = false
})
})
}
@@ -264,6 +308,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
this.$axios.post('/platform/enrollmentRegistration/apply/submit', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
@@ -272,6 +317,8 @@ layout("/layouts/platform.html"){
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/enrollmentRegistration/applyList/index')
}
}).finally(() => {
this.formLoading = false
})
})
}
@@ -297,6 +344,7 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.formLoading = true
this.$axios.post('/platform/enrollmentRegistration/apply/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
@@ -305,6 +353,8 @@ layout("/layouts/platform.html"){
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/enrollmentRegistration/applyList/index')
}
}).finally(() => {
this.formLoading = false
})
})
}
@@ -312,39 +362,45 @@ layout("/layouts/platform.html"){
}
})
},
async getIsRepeatByIdCard() {
// 校验参数:childrenIdCard 为子女身份证号,id 为当前登记主键;返回 Promise<boolean>true 表示本年度已存在重复登记。
getIsRepeatByIdCard() {
if (!this.formData.childrenIdCard) {
this.$message.error("请填写子女身份证号码")
return
return Promise.resolve(true)
}
const res = await this.$axios.post('/platform/enrollmentRegistration/apply/getIsRepeatByIdCard', {
return this.$axios.post('/platform/enrollmentRegistration/apply/getIsRepeatByIdCard', {
idCard: this.formData.childrenIdCard,
id: this.formData.id
})
if (res.code === 0) {
if (res.data > 0) {
this.$message.error("该身份证在本年度已填报!")
return true
} else {
}).then(res => {
if (res.code === 0) {
if (res.data > 0) {
this.$message.error("该身份证在本年度已填报!")
return true
}
this.$message.success("该身份证在本年度暂未填报!")
return false
}
}
return true
})
},
async findOne(id) {
const resp = await $.get('/platform/enrollmentRegistration/apply/findOne', {id})
if (resp.code === 0) {
return resp.data
}
// 查询参数:id 为登记主键;返回 Promise<EnrollmentRegistration|null>,用于草稿及退回申请回显。
findOne(id) {
return this.$axios.post('/platform/enrollmentRegistration/apply/findOne', {id}).then(resp => {
return resp.code === 0 ? resp.data : null
})
},
init() {
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
this.findOne(this.bizId).then(data => {
if (data) {
this.$set(this, "formData", data)
}
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
this.formData = {
const {id, username, loginname, mobile, union, unit, position, technicalTitle, preparedBy} = this.$store.state.user
// 旧表单将职务和职称作为一个必填项,新建登记时优先合并当前用户档案中的两项信息。
const positionTitle = [position, technicalTitle].filter(item => item).join("、")
this.$set(this, "formData", {
userId: id,
userName: username,
loginName: loginname,
@@ -353,13 +409,15 @@ layout("/layouts/platform.html"){
unionName: union.name,
unionId: union.id,
mobile: mobile,
}
positionTitle: positionTitle,
employmentType: preparedBy,
})
}
}
},
async created() {
created() {
this.init()
this.getEnrollmentRegistrationPlan()
@@ -7,14 +7,12 @@ const ENROLLMENT_REGISTRATION_INFO = {
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="3" border>
<el-descriptions-item label="监护人(教工)姓名">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="教职工姓名">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="工号">{{viewData.loginName}}</el-descriptions-item>
<el-descriptions-item label="职务、职称">{{viewData.positionTitle}}</el-descriptions-item>
<el-descriptions-item label="手机号码">{{viewData.mobile}}</el-descriptions-item>
<el-descriptions-item label="所在单位">{{viewData.unitName}}</el-descriptions-item>
<el-descriptions-item label="监护人与学生关系">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP"
:value="viewData.childRelationship"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="用工方式">{{viewData.employmentType}}</el-descriptions-item>
<el-descriptions-item label="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
:value="viewData.registrationType"></dict-tag>
@@ -31,26 +29,35 @@ const ENROLLMENT_REGISTRATION_INFO = {
<el-descriptions-item label="子女出生日期" >
{{viewData.childrenBirthday}}
</el-descriptions-item>
<el-descriptions-item label="现就读学校">
<el-descriptions-item label="读学校">
{{viewData.childrenCurrentSchool}}
</el-descriptions-item>
<el-descriptions-item label="拟报就读学校">
<el-descriptions-item label="户籍所在地">
{{viewData.childrenHuKouAddress}}
</el-descriptions-item>
<el-descriptions-item label="拟选区域">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"
:value="viewData.childrenPlanSchool"></dict-tag>
</el-descriptions-item>
<el-descriptions-item label="子女户口所在地">
{{viewData.childrenHuKouAddress}}
<el-descriptions-item label="拟选学校">
{{viewData.childrenPlanSchoolName}}
</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">
<el-descriptions-item label="备注" :span="3">
{{viewData.note}}
</el-descriptions-item>
<el-descriptions-item :span="3" label="户口簿片">
<el-descriptions-item :span="3" label="户口簿片">
<file-preview :files="viewData.huKouFiles" complete_result></file-preview>
</el-descriptions-item>
<el-descriptions-item :span="3" label="子女出生证片">
<el-descriptions-item :span="3" label="子女出生证片">
<file-preview :files="viewData.birthCertificateFiles" complete_result></file-preview>
</el-descriptions-item>
<el-descriptions-item :span="3" label="学历学位证或教师资格证">
<file-preview :files="viewData.qualificationCertificateFiles" complete_result></file-preview>
</el-descriptions-item>
<el-descriptions-item :span="3" label="聘用合同复印件">
<file-preview :files="viewData.employmentContractFiles" complete_result></file-preview>
</el-descriptions-item>
</el-descriptions>
<template v-for="(task,index) in doneTasks">
@@ -96,7 +103,7 @@ const ENROLLMENT_REGISTRATION_INFO = {
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
data() {
return {
viewData: {},
@@ -3,18 +3,21 @@ layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<snaker-start slot="header" label="职工慰问" define_key="ZGWW"></snaker-start>
<custom-card>
<snaker-start slot="header" label="补贴申请" define_key="ZGWW">
<template slot="header-right-label">
<el-button v-if="$auth.hasRole('SYSADMIN')" type="text" class="mr10"
@click="openApplyPeriodDialog">申报时间设置</el-button>
</template>
</snaker-start>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=""
class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="申请人姓名">{{formData.applyUserName}}</el-descriptions-item>
<el-descriptions-item label="申请人工号">{{formData.applyLoginName}}</el-descriptions-item>
<el-descriptions-item label="申请人单位">{{formData.applyUnitName}}</el-descriptions-item>
<el-descriptions-item label="申请人工会">{{formData.applyUnionName}}</el-descriptions-item>
<el-descriptions-item label="申请人">{{formData.applyUserName}}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{formData.createTime}}</el-descriptions-item>
<el-descriptions-item label="慰问对象">
<el-form-item prop="helpUserId" label="慰问对象">
<el-descriptions-item label="补贴对象">
<el-form-item prop="helpUserId" label="补贴对象">
<el-select
style="width: 100%"
v-model="formData.helpUserId"
@@ -34,48 +37,32 @@ layout("/layouts/platform.html"){
</el-select>
</el-form-item>
</el-descriptions-item>
<!-- <el-descriptions-item label="经办人">
<el-form-item prop="handlerUserId" label="经办人">
<el-select
style="width: 100%"
v-model="formData.handlerUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入姓名或工号查询"
:remote-method="createRemoteMethod(handlerUserOptions)"
@change="handlerUserChange">
<el-option
v-for="item in handlerUserOptions"
:key="item.id"
:label="item.userName+''+item.loginName+''+''+item.unitName+''"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>-->
<el-descriptions-item label="证明人">
<el-form-item prop="certifierUserId" label="证明人">
<el-select
style="width: 100%"
v-model="formData.certifierUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入姓名或工号查询"
:remote-method="createRemoteMethod(certifierUserOptions)"
@change="certifierUserChange">
<el-option
v-for="item in certifierUserOptions"
:key="item.id"
:label="item.userName+''+item.loginName+''+''+item.unitName+''"
:value="item.id">
</el-option>
</el-select>
<el-descriptions-item label="性别">
<el-form-item prop="sex" label="性别">
<el-input v-model="formData.sex" maxlength="10" placeholder="选择补贴对象后自动回填"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="联系电话">
<el-form-item prop="mobile" label="联系电话">
<el-input v-model="formData.mobile" maxlength="30" placeholder="请填写联系电话"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生年月">
<el-form-item prop="birthday" label="出生年月">
<el-date-picker
clearable
style="width: 100%"
v-model="formData.birthday"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出生年月">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="慰问类型">
<el-form-item prop="type" label="慰问类型">
<el-select v-model="formData.type" @change="typeChange" style="width: 100%"
@@ -84,94 +71,42 @@ layout("/layouts/platform.html"){
:value="item.id"
:key="item.id"
:disabled="!item.enable"
:label="item.name"></el-option>
:label="item.name+''+item.money+'元)'"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="慰问金额">
<el-form-item prop="money" label="慰问金额">
<el-input style="width: 100%" v-model="formData.money"
controls-position="right"
:controls="false"
precision="2"
placeholder="选择慰问类型自动匹配金额"
:min="0"
:max="10000"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="慰问时间">
<el-form-item label="慰问时间" prop="occurTime">
<el-date-picker
clearable
style="width: 100%"
v-model="formData.occurTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择慰问时间">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="收款账户">
<el-form-item prop="bankCardNumber" label="收款账户">
<el-input maxlength="20" v-model="formData.bankCardNumber" placeholder="请填写收款账户"
></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="户名">
<el-form-item prop="bankUserName" label="户名">
<el-input maxlength="20" v-model="formData.bankUserName"
placeholder="请填写户名"
></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="开户行" >
<el-form-item prop="bankOfDeposit" label="开户行">
<el-input maxlength="20" v-model="formData.bankOfDeposit"
placeholder="请填写开户行"
></el-input>
</el-form-item>
</el-descriptions-item>
<template v-if="['2'].includes(formData.typeCode)">
<el-descriptions-item label="入院时间">
<el-form-item label="入院时间" prop="hospitalizationTime">
<el-date-picker
clearable
<template v-if="showPayUserFields">
<el-descriptions-item label="收款">
<el-form-item prop="payUserId" label="收款人">
<el-select
style="width: 100%"
v-model="formData.hospitalizationTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择入院时间">
</el-date-picker>
v-model="formData.payUserId"
filterable
clearable
remote
reserve-keyword
placeholder="请输入姓名或工号查询"
:remote-method="createRemoteMethod(payUserOptions)"
@change="payUserChange">
<el-option
v-for="item in payUserOptions"
:key="item.id"
:label="item.userName+''+item.loginName+''+''+item.unitName+''"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出院时间">
<el-form-item label="出院时间" prop="leaveHospitalTime">
<el-date-picker
clearable
style="width: 100%"
v-model="formData.leaveHospitalTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出院时间">
</el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="当年第几次住院">
<el-form-item prop="thisYearHospitalizationNum" label="当年第几次住院">
<el-input-number style="width: 100%" v-model="formData.thisYearHospitalizationNum"
placeholder="请输入当年第几次住院"
:min="0"
:max="10000"></el-input-number>
<el-descriptions-item label="收款人银行卡">
<el-form-item prop="bankCardNumber" label="收款人银行卡">
<el-input v-model="formData.bankCardNumber" maxlength="30"
placeholder="请填写收款人银行卡"></el-input>
</el-form-item>
</el-descriptions-item>
</template>
<el-descriptions-item v-if="!showPayUserFields" :span="2"></el-descriptions-item>
<el-descriptions-item label="申请事由" :span="3">
<el-form-item prop="remark" label="申请事由">
@@ -180,15 +115,19 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item :span="3" v-if="chooseType.isUploadFile === true">
<template slot="label">
附件
<el-tooltip class="item" effect="dark" :content="'上传附件说明:' + chooseType.uploadFileDesc"
placement="top-start"
v-if="chooseType.isUploadFile && chooseType.uploadFileDesc">
<i class="el-icon-question"></i>
</el-tooltip>
</template>
<el-descriptions-item label="纸质申请表" :span="3">
<el-form-item prop="applyFiles" label="纸质申请表">
<file-upload
:value.sync="formData.applyFiles"
:upload_number="1"
upload_result_category="array"
complete_result
upload_mode="drag"
></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<el-form-item prop="files" label="附件">
<file-upload
:value.sync="formData.files"
@@ -199,20 +138,32 @@ layout("/layouts/platform.html"){
></file-upload>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-form-item prop="signature" label="签字">
<pc-signature v-model="formData.signature"></pc-signature>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<el-row type="flex" justify="end" class="mt20">
<el-button type="primary" plain @click="onSave">保存</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交</el-button>
</el-row>
</el-card>
<template slot="footer" v-if="bizId || !applyClosed">
<el-button type="primary" plain :loading="formLoading" @click="onSave">保存</el-button>
<el-button type="primary" :loading="formLoading" @click="onSubmit" v-if="!taskId">提交</el-button>
<el-button type="primary" :loading="formLoading" @click="onFinishTask" v-else>提交</el-button>
</template>
</custom-card>
<el-dialog title="申报时间设置" :visible.sync="applyPeriodDialogVisible" width="480px" append-to-body>
<el-form ref="applyPeriodFormRef" :model="applyPeriodForm" :rules="applyPeriodRules" label-width="120px">
<el-form-item label="申报截止日期" prop="endDate">
<el-date-picker
v-model="applyPeriodForm.endDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择申报截止日期"
style="width: 100%">
</el-date-picker>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="closeApplyPeriodDialog">取消</el-button>
<el-button type="primary" :loading="applyPeriodSaving" @click="saveApplyEndDate">保存</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
@@ -223,91 +174,143 @@ layout("/layouts/platform.html"){
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formLoading: false,
applyEndDate: "",
applyPeriodDialogVisible: false,
applyPeriodSaving: false,
applyPeriodForm: {
endDate: ""
},
applyPeriodRules: {
endDate: [{ required: true, message: "请选择申报截止日期", trigger: "change" }]
},
formData: {},
formRules: {
helpUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
mobile: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
birthday: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
way: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
money: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
occurTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
child: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
hospital: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
hospitalHouseNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
hospitalHouseBedNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
hospitalBy: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
deadImmediateFamily: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
bankCardNumber: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
thisYearHospitalizationNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
applyFiles: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
},
chooseType: {},
payUserOptions: [],
helpUserOptions: [],
payUserOptions: [],
typeOptions: [],
handlerUserOptions: [],
certifierUserOptions: []
// A、B 类型不需要维护收款人及银行卡信息。
noPayUserTypeCodes: ["A", "B"]
}
},
computed: {
// 历史申请缺少 typeCode 时,根据已保存的类型 ID 回查编码,保证重新提交显隐正确。
selectedTypeCode() {
if (this.formData.typeCode) {
return this.formData.typeCode
}
const selectedType = this.typeOptions.find(item => item.id === this.formData.type)
return selectedType ? selectedType.code : ""
},
showPayUserFields() {
return this.selectedTypeCode && !this.noPayUserTypeCodes.includes(this.selectedTypeCode)
},
// 复用旧系统判断规则:截止日期当天即停止新申报。
applyClosed() {
if (!this.applyEndDate || !this.$moment(this.applyEndDate).isValid()) {
return false
}
return this.$moment(this.applyEndDate).valueOf()
<= this.$moment(this.$moment().format("YYYY-MM-DD")).valueOf()
}
},
methods: {
/**
* 查询慰问申报截止日期。
* @returns {Promise<Object>} Axios 请求 Promise,响应 data 为 yyyy-MM-dd 日期字符串。
*/
queryApplyEndDate() {
return this.$axios.post("/platform/condolence/apply/getApplyEndDate").then((res) => {
if (res.code === 0) {
this.$set(this, "applyEndDate", res.data || "")
}
return res
})
},
openApplyPeriodDialog() {
this.$set(this.applyPeriodForm, "endDate", this.applyEndDate)
this.$set(this, "applyPeriodDialogVisible", true)
},
closeApplyPeriodDialog() {
this.$set(this, "applyPeriodDialogVisible", false)
},
/**
* 保存慰问申报截止日期。
* @returns {void} 保存成功后刷新截止日期并关闭弹框。
*/
saveApplyEndDate() {
this.$refs.applyPeriodFormRef.validate((valid) => {
if (!valid) {
return
}
this.$set(this, "applyPeriodSaving", true)
this.$axios.post("/platform/condolence/apply/saveApplyEndDate", {
endDate: this.applyPeriodForm.endDate
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.$set(this, "applyPeriodDialogVisible", false)
return this.queryApplyEndDate()
}
return res
}).finally(() => {
this.$set(this, "applyPeriodSaving", false)
})
})
},
showApplyClosedAlert() {
this.$alert("本次申报已截止请关注下次申报", "温馨提示", {
confirmButtonText: "确定",
callback: () => {}
})
},
createRemoteMethod(options) {
return (keyword) => {
this.selectQueryUser(keyword, options)
}
},
/**
* 查询可选择用户。
* @param {string} keyword 姓名或工号关键字。
* @param {Array} options 接收查询结果的下拉选项数组。
* @returns {Promise<Object>} Axios 请求 Promise,响应 data 为用户数组。
*/
selectQueryUser(keyword, options) {
options.length = 0
this.$axios.post("/platform/condolence/apply/listUser", { keyword: keyword }).then((res) => {
options.splice(0, options.length)
return this.$axios.post("/platform/condolence/apply/listUser", { keyword: keyword }).then((res) => {
if (res.code === 0) {
options.push(...res.data)
}
return res
})
},
// 选择补贴对象后保存人员快照,避免后续用户基础信息变化影响已提交申请。
helpUserChange(val) {
const user = this.helpUserOptions.find(o => o.id === val)
if (user) {
const { userName, loginName, unitId, unitName, unionId, unionName } = user
const { userName, loginName, unitId, unitName, unionId, unionName, sex, mobile, birthday } = user
this.$set(this.formData, "helpUserName", userName)
this.$set(this.formData, "helpLoginName", loginName)
this.$set(this.formData, "helpUnitId", unitId)
this.$set(this.formData, "helpUnitName", unitName)
this.$set(this.formData, "helpUnionId", unionId)
this.$set(this.formData, "helpUnionName", unionName)
this.$set(this.formData, "sex", sex)
this.$set(this.formData, "mobile", mobile)
this.$set(this.formData, "birthday", birthday ? this.$moment(birthday).format("YYYY-MM-DD") : "")
}
},
handlerUserChange(val) {
const user = this.handlerUserOptions.find(o => o.id === val)
if (user) {
const { userName, loginName, unitId, unitName, unionId, unionName } = user
this.$set(this.formData, "handlerUserName", userName)
this.$set(this.formData, "handlerLoginName", loginName)
this.$set(this.formData, "handlerUnitId", unitId)
this.$set(this.formData, "handlerUnitName", unitName)
this.$set(this.formData, "handlerUnionId", unionId)
this.$set(this.formData, "handlerUnionName", unionName)
}
},
certifierUserChange(val) {
const user = this.certifierUserOptions.find(o => o.id === val)
if (user) {
const { userName, loginName, unitId, unitName, unionId, unionName } = user
this.$set(this.formData, "certifierUserName", userName)
this.$set(this.formData, "certifierLoginName", loginName)
this.$set(this.formData, "certifierUnitId", unitId)
this.$set(this.formData, "certifierUnitName", unitName)
this.$set(this.formData, "certifierUnionId", unionId)
this.$set(this.formData, "certifierUnionName", unionName)
}
},
// 收款人同时保存姓名和工号,供重新提交及详情展示使用。
payUserChange(val) {
const user = this.payUserOptions.find(o => o.id === val)
if (user) {
@@ -317,12 +320,37 @@ layout("/layouts/platform.html"){
}
},
typeChange(id) {
this.chooseType = this.typeOptions.find(o => o.id === id)
if (this.chooseType) {
this.$set(this.formData, "money", this.chooseType.money)
this.$set(this.formData, "way", this.chooseType.way)
this.$set(this.formData, "typeCode", this.chooseType.code)
const chooseType = this.typeOptions.find(o => o.id === id)
if (chooseType) {
this.$set(this.formData, "money", chooseType.money)
this.$set(this.formData, "way", chooseType.way)
this.$set(this.formData, "typeCode", chooseType.code)
}
// 切换到无需收款人的类型时清除历史输入,防止隐藏字段随申请提交。
if (!this.showPayUserFields) {
this.$set(this.formData, "payUserId", "")
this.$set(this.formData, "payUserName", "")
this.$set(this.formData, "payLoginName", "")
this.$set(this.formData, "bankCardNumber", "")
}
},
/**
* 保存或提交申请。
* @param {string} url 保存、首次提交或重新提交接口地址。
* @param {Object} params data 为表单 JSON;重新提交时同时包含 taskId。
* @returns {Promise<Object>} Axios 请求 Promise,成功后跳转到我的申请。
*/
sendApplyRequest(url, params) {
this.formLoading = true
return this.$axios.post(url, params).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/condolence/mine")
}
return res
}).finally(() => {
this.formLoading = false
})
},
onSave() {
this.$confirm("您确定保存吗?", "提示", {
@@ -330,11 +358,8 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/condolence/apply/save", { data: JSON.stringify(this.formData) }).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/condolence/mine")
}
this.sendApplyRequest("/platform/condolence/apply/save", {
data: JSON.stringify(this.formData)
})
})
},
@@ -346,13 +371,8 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/condolence/apply/submit", {
this.sendApplyRequest("/platform/condolence/apply/submit", {
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/condolence/mine")
}
})
})
}
@@ -366,14 +386,9 @@ layout("/layouts/platform.html"){
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/condolence/apply/submitAgain", {
this.sendApplyRequest("/platform/condolence/apply/submitAgain", {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success(res.msg)
commonUtil.pjaxPush("/platform/condolence/mine")
}
taskId: this.taskId
})
})
}
@@ -383,36 +398,67 @@ layout("/layouts/platform.html"){
if (this.bizId) {
this.$axios.post("/platform/condolence/mine/info", { id: this.bizId }).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.$set(this, "formData", res.data)
this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions)
this.selectQueryUser(this.formData.certifierLoginName, this.certifierUserOptions)
this.selectQueryUser(this.formData.handlerLoginName, this.handlerUserOptions)
this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
if (this.formData.payLoginName) {
this.selectQueryUser(this.formData.payLoginName, this.payUserOptions)
}
}
})
} else {
const { username, loginname, id, unit, union, mobile } = this.$store.state.user
this.formData = {
const { username, loginname, id, unit, union, mobile, sex, birthday } = this.$store.state.user
this.$set(this, "formData", {
applyUserName: username,
applyLoginName: loginname,
applyUserId: id,
applyUnitId: unit?.id,
applyUnitName: unit?.name,
applyUnionId: union?.id,
applyUnionName: union?.name
}
applyUnionName: union?.name,
createTime: this.$moment().format("YYYY-MM-DD"),
helpUserId: id,
helpUserName: username,
helpLoginName: loginname,
helpUnitId: unit?.id,
helpUnitName: unit?.name,
helpUnionId: union?.id,
helpUnionName: union?.name,
sex: sex,
mobile: mobile,
birthday: birthday ? this.$moment(birthday).format("YYYY-MM-DD") : "",
applyFiles: [],
files: []
})
this.selectQueryUser(loginname, this.helpUserOptions)
}
},
/**
* 按当前用户角色过滤可申请的慰问类型。
* @param {Array} options 接口返回的全部启用慰问类型。
* @returns {Array} 系统管理员、校工会管理员返回全部类型,其他角色仅返回编码 A、B 的类型。
*/
filterTypeOptions(options) {
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
return options
}
return options.filter(item => ["A", "B"].includes(item.code))
},
queryCondolenceType() {
this.$axios.post("/platform/condolence/type/queryCondolenceType")
.then((resp) => {
this.typeOptions = resp.data
return this.$axios.post("/platform/condolence/type/queryCondolenceType")
.then((res) => {
const options = this.filterTypeOptions(res.data)
this.typeOptions.splice(0, this.typeOptions.length, ...options)
return res
})
}
},
created() {
this.queryCondolenceType()
this.init()
Promise.all([this.queryCondolenceType(), this.queryApplyEndDate()]).then(() => {
if (!this.bizId && this.applyClosed) {
this.showApplyClosedAlert()
}
this.init()
})
}
})
</script>
@@ -5,40 +5,34 @@ const condolenceInfo = {
申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="3" border>
<el-descriptions-item label="申请人姓名">{{ viewData.applyUserName }}</el-descriptions-item>
<el-descriptions-item label="申请人工号">{{ viewData.applyLoginName }}</el-descriptions-item>
<el-descriptions-item label="申请人单位">{{ viewData.applyUnitName }}</el-descriptions-item>
<el-descriptions-item label="申请人工会">{{ viewData.applyUnionName }}</el-descriptions-item>
<el-descriptions-item label="慰问对象">{{ viewData.helpUserName }}</el-descriptions-item>
<!-- <el-descriptions-item label="经办人">{{ viewData.handlerUserName }}</el-descriptions-item>-->
<el-descriptions-item label="证明人">{{ viewData.certifierUserName }}</el-descriptions-item>
<el-descriptions-item label="慰问类型">{{ viewData.typeName }}</el-descriptions-item>
<el-descriptions-item label="慰问金额">{{ viewData.money }}</el-descriptions-item>
<el-descriptions-item label="慰问时间">{{ viewData.occurTime }}</el-descriptions-item>
<el-descriptions-item label="收款账户">{{ viewData.bankCardNumber }}</el-descriptions-item>
<el-descriptions-item label="户名">{{ viewData.bankUserName }}</el-descriptions-item>
<el-descriptions-item label="开户行">{{ viewData.bankOfDeposit }}</el-descriptions-item>
<template v-if="['2'].includes(viewData.typeCode)">
<el-descriptions-item label="入院时间">{{ viewData.hospitalizationTime }}</el-descriptions-item>
<el-descriptions-item label="出院时间">{{ viewData.leaveHospitalTime }}</el-descriptions-item>
<el-descriptions-item label="当年第几次住院">{{ viewData.thisYearHospitalizationNum }}
</el-descriptions-item>
</template>
<el-descriptions-item label="申请事由" :span="3">
<el-descriptions :column="2" border>
<el-descriptions-item label="申请人">{{ viewData.applyUserName }}</el-descriptions-item>
<el-descriptions-item label="申请时间">{{ viewData.createTime }}</el-descriptions-item>
<el-descriptions-item label="补贴对象">{{ viewData.helpUserName }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ viewData.mobile }}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{ viewData.birthday }}</el-descriptions-item>
<el-descriptions-item label="补贴类型">{{ viewData.typeName }}</el-descriptions-item>
<el-descriptions-item label="补贴金额">{{ viewData.money }}</el-descriptions-item>
<el-descriptions-item label="收款人" v-if="viewData.payUserName">
{{ viewData.payUserName }}
</el-descriptions-item>
<el-descriptions-item label="收款人卡号" v-if="viewData.bankCardNumber">
{{ viewData.bankCardNumber }}
</el-descriptions-item>
<el-descriptions-item label="申请事由" :span="2">
<div style="white-space: pre-line">{{ viewData.remark }}</div>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="3">
<el-descriptions-item label="纸质申请表" :span="2">
<file-preview v-if="viewData.applyFiles && viewData.applyFiles.length > 0"
:files="viewData.applyFiles" complete_result></file-preview>
<span v-else>暂无纸质申请表</span>
</el-descriptions-item>
<el-descriptions-item label="附件" :span="2">
<file-preview v-if="viewData.files && viewData.files.length > 0" :files="viewData.files"
complete_result></file-preview>
<span v-else>暂无附件</span>
</el-descriptions-item>
<el-descriptions-item label="签字" :span="3">
<el-image :src="viewData.signature"
v-if="viewData.signature"
class="signature-image"></el-image>
<span v-else>暂无签字</span>
</el-descriptions-item>
</el-descriptions>
<template v-for="task in doneTasks">
@@ -6,14 +6,16 @@ layout("/layouts/platform.html"){
<guava ref="guava">
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<search-item label="月份">
<el-date-picker
v-model="pageForm.year"
type="year"
value-format="yyyy"
placeholder="请选择年度"
v-model="monthRange"
type="monthrange"
value-format="yyyy-MM"
range-separator=""
start-placeholder="开始月份"
end-placeholder="结束月份"
style="width: 100%"
@change="doSearch"
@change="onMonthRangeChange"
></el-date-picker>
</search-item>
<search-item label="姓名/工号">
@@ -55,7 +57,12 @@ layout("/layouts/platform.html"){
<el-card shadow="never">
<table-tool label="申请列表">
<el-button @click="onExport" icon="el-icon-s-promotion" type="primary" size="small">导出</el-button>
<el-button @click="onExportZip" icon="el-icon-folder-opened" type="primary" size="small">
导出压缩包
</el-button>
<el-button @click="onExport" icon="el-icon-s-promotion" type="primary" size="small">
导出申报人汇总
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
@@ -74,9 +81,23 @@ layout("/layouts/platform.html"){
<enum-tag :value="row.instanceState" name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="180">
<el-table-column label="操作" fixed="right" width="280">
<template slot-scope="{row}">
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
<el-button
v-if="row.instanceState === 20 && !['A', 'B'].includes(row.exportTypeCode)"
@click="onExportReceipt(row)"
size="mini"
type="primary">
导出工会领条
</el-button>
<el-button
v-if="row.instanceState === 20 && ['A', 'B'].includes(row.exportTypeCode)"
@click="onExportSubsidyRegistration(row)"
size="mini"
type="primary">
导出补贴登记表
</el-button>
<el-button v-if="$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')" @click="onDelete(row.id)" size="mini" type="danger">
删除
</el-button>
@@ -104,6 +125,11 @@ layout("/layouts/platform.html"){
data() {
return {
typeOptions: [],
monthRange: [],
pageForm: {
startMonth: "",
endMonth: ""
},
tableColumns: [
{prop: 'helpUserName', label: '慰问对象'},
{prop: 'helpLoginName', label: '慰问对象工号'},
@@ -119,6 +145,28 @@ layout("/layouts/platform.html"){
}
},
methods: {
/**
* 将月份范围拆分为后端查询参数;清空选择时同步清空两个参数。
* @param {Array<string>} monthRange 开始月份、结束月份,格式均为 yyyy-MM。
* @returns {void} 更新 pageForm 后重新查询第一页。
*/
onMonthRangeChange(monthRange) {
const hasCompleteRange = monthRange && monthRange.length === 2
this.$set(this.pageForm, "startMonth", hasCompleteRange ? monthRange[0] : "")
this.$set(this.pageForm, "endMonth", hasCompleteRange ? monthRange[1] : "")
this.doSearch()
},
/**
* 校验批量导出必须选择完整月份范围。
* @returns {boolean} true 表示可以导出,false 表示已提示并阻止导出。
*/
validateExportMonthRange() {
if (!this.pageForm.startMonth || !this.pageForm.endMonth) {
this.$message.warning("请选择需要导出的月份")
return false
}
return true
},
onDelete(id) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
@@ -134,8 +182,23 @@ layout("/layouts/platform.html"){
})
},
onExport() {
if (!this.validateExportMonthRange()) {
return
}
this.$downLoad(loc() + '/onExport', this.pageForm)
},
onExportZip() {
if (!this.validateExportMonthRange()) {
return
}
this.$downLoad(loc() + '/onExportZip', this.pageForm)
},
onExportReceipt(row) {
this.$downLoad(loc() + '/onExportReceipt', {id: row.id})
},
onExportSubsidyRegistration(row) {
this.$downLoad(loc() + '/onExportSubsidyRegistration', {id: row.id})
},
onView(row) {
this.$refs.guava.edit(()=>{
this.$refs.condolenceInfoRef.onOpen(row)
@@ -39,39 +39,6 @@ layout("/layouts/platform_h5.html"){
</van-popup>
</van-cell-group>
<!-- 教职工信息 -->
<van-cell-group title="教职工信息">
<van-field label="监护人(教工)姓名" :rules="[{ required: true }]" v-model="formData.userName" readonly
required></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required></van-field>
<van-field label="手机号码" name="mobile" :rules="[{ required: true }]" v-model="formData.mobile"
required
placeholder="请输入手机号码"></van-field>
<van-field label="所在单位" :rules="[{ required: true }]" v-model="formData.unitName" readonly
required></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.childRelationshipName"
label="监护人与学生关系"
name="childRelationshipName"
placeholder="请选择监护人与学生关系"
required
is-link
readonly
@click="showChildRelationshipPopup = true"
></van-field>
<van-popup v-model="showChildRelationshipPopup" position="bottom">
<van-picker
show-toolbar
:columns="childRelationshipOption.map(i => i.name)"
@confirm="onChildRelationshipConfirm"
@cancel="showChildRelationshipPopup = false"
></van-picker>
</van-popup>
</van-cell-group>
<!-- 子女信息 -->
<van-cell-group title="子女信息">
<van-field label="子女姓名" name="childrenName" :rules="[{ required: true }]"
@@ -98,27 +65,20 @@ layout("/layouts/platform_h5.html"){
></van-picker>
</van-popup>
<van-field label="身份证号"
name="childrenIdCard"
:rules="[{ required: true }]"
v-model="formData.childrenIdCard"
placeholder="请输入身份证号"
required
></van-field>
<van-field label="出生年月"
<van-field label="出生日期"
name="childrenBirthday"
:rules="[{ required: true }]"
:value="formData.childrenBirthday"
readonly
is-link
placeholder="请填写出生年月"
placeholder="请选择出生日期"
required
@click="childrenBirthdayPopup = true"></van-field>
<van-popup v-model="childrenBirthdayPopup" position="bottom">
<van-datetime-picker
v-model="formData.childrenBirthdayDate"
type="date"
title="选择出生年月"
title="选择出生日期"
:min-date="childrenBirthdayMinDate"
:max-date="childrenBirthdayMaxDate"
@confirm="childrenBirthdayConfirm"
@@ -126,18 +86,37 @@ layout("/layouts/platform_h5.html"){
></van-datetime-picker>
</van-popup>
<van-field label="现就读学校"
<van-field label="身份证号"
name="childrenIdCard"
:rules="[{ required: true }]"
v-model="formData.childrenIdCard"
placeholder="请输入身份证号"
required
></van-field>
<van-field label="正读学校"
:rules="[{ required: true }]"
v-model="formData.childrenCurrentSchool"
required
placeholder="请输入现就读学校"></van-field>
placeholder="请输入读学校"></van-field>
<van-field label="户籍所在地"
:rules="[{ required: true }]"
v-model="formData.childrenHuKouAddress"
required
type="textarea"
name="childrenHuKouAddress"
rows="2"
autosize
class="more-text"
placeholder="请输入户籍所在地"></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.childrenPlanSchoolName"
label="拟报就读学校"
name="childrenPlanSchoolName"
placeholder="请选择拟报就读学校"
v-model="formData.childrenPlanRegionName"
label="拟选区域"
name="childrenPlanRegionName"
placeholder="请选择拟选区域"
required
is-link
readonly
@@ -154,32 +133,65 @@ layout("/layouts/platform_h5.html"){
></van-picker>
</van-popup>
<van-field label="子女户口所在地"
<van-field label="拟选学校"
:rules="[{ required: true }]"
v-model="formData.childrenHuKouAddress"
v-model="formData.childrenPlanSchoolName"
required
type="textarea"
name="childrenHuKouAddress"
rows="4"
autosize
class="more-text"
placeholder="请输入子女户口所在地"></van-field>
<van-field label="备注"
:rules="[{ required: true }]"
v-model="formData.note"
required
type="textarea"
name="note"
rows="4"
autosize
class="more-text"
placeholder="请填写户籍所在地派出所"></van-field>
name="childrenPlanSchoolName"
placeholder="请输入拟选学校"></van-field>
</van-cell-group>
<!-- 户口簿照片 -->
<van-cell-group title="户口簿照片">
<van-field class="more-text" name="huKouFiles" :rules="[{ required: true,message:'请上传户口簿照片' }]"
<!-- 教职工信息 -->
<van-cell-group title="教职工信息">
<van-field label="教职工姓名" :rules="[{ required: true }]" v-model="formData.userName" readonly
required></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required></van-field>
<van-field label="职务、职称"
name="positionTitle"
:rules="[{ required: true }]"
v-model="formData.positionTitle"
required
placeholder="请输入职务、职称"></van-field>
<van-field label="手机号码" name="mobile" :rules="[{ required: true }]" v-model="formData.mobile"
required
placeholder="请输入手机号码"></van-field>
<van-field label="所在单位" :rules="[{ required: true }]" v-model="formData.unitName" readonly
required></van-field>
<van-field
:rules="[{ required: true }]"
v-model="formData.employmentType"
label="用工方式"
name="employmentType"
placeholder="请选择用工方式"
required
is-link
readonly
@click="showEmploymentTypePopup = true"
></van-field>
<van-popup v-model="showEmploymentTypePopup" position="bottom">
<van-picker
show-toolbar
:columns="employmentTypeOption"
@confirm="onEmploymentTypeConfirm"
@cancel="showEmploymentTypePopup = false"
></van-picker>
</van-popup>
<van-field label="备注"
v-model="formData.note"
type="textarea"
name="note"
rows="2"
autosize
class="more-text"
placeholder="请输入备注"></van-field>
</van-cell-group>
<!-- 户口簿图片 -->
<van-cell-group title="户口簿图片">
<van-field class="more-text" name="huKouFiles" :rules="[{ required: true,message:'请上传户口簿图片' }]"
label="" required>
<template #input>
<h5-file-upload
@@ -195,9 +207,10 @@ layout("/layouts/platform_h5.html"){
</van-field>
</van-cell-group>
<!-- 子女出生证-->
<van-cell-group title="子女出生证片">
<van-field class="more-text" name="birthCertificateFiles" label="">
<!-- 子女出生证-->
<van-cell-group title="子女出生证片">
<van-field class="more-text" name="birthCertificateFiles"
:rules="[{ required: true,message:'请上传子女出生证图片' }]" label="" required>
<template #input>
<h5-file-upload
slot="input"
@@ -212,6 +225,42 @@ layout("/layouts/platform_h5.html"){
</van-field>
</van-cell-group>
<!-- 学历学位证或教师资格证 -->
<van-cell-group title="学历学位证或教师资格证">
<van-field class="more-text" name="qualificationCertificateFiles"
:rules="[{ required: true,message:'请上传学历学位证或教师资格证' }]" label="" required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.qualificationCertificateFiles"
:upload_number="10"
upload_mode="image"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 聘用合同复印件 -->
<van-cell-group title="聘用合同复印件">
<van-field class="more-text" name="employmentContractFiles"
:rules="[{ required: true,message:'请上传聘用合同复印件' }]" label="" required>
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.employmentContractFiles"
:upload_number="10"
upload_mode="image"
upload_result_category="array"
upload_result_type="url"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<!-- 按钮区域 -->
<div class="form-actions">
<van-button native-type="button" plain type="info" @click="onSave">保存</van-button>
@@ -226,7 +275,7 @@ layout("/layouts/platform_h5.html"){
const vue = new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
dicts: ["ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
components: {},
data() {
return {
@@ -236,12 +285,12 @@ layout("/layouts/platform_h5.html"){
registrationTypeOption: [],
showRegistrationTypePopup: false,
childRelationshipOption: [],
showChildRelationshipPopup: false,
sexOption: ["男", "女"],
showSexPopup: false,
employmentTypeOption: ["老体制", "人事代理", "年薪制", "二级单位自聘"],
showEmploymentTypePopup: false,
childrenBirthdayMinDate: new Date(1900, 0, 1),
childrenBirthdayMaxDate: new Date(),
childrenBirthdayPopup: false,
@@ -251,45 +300,43 @@ layout("/layouts/platform_h5.html"){
}
},
methods: {
async getEnrollmentRegistrationPlan() {
const res = await this.$axios.post("/platform/enrollmentRegistration/apply/getEnrollmentRegistrationPlan")
if (res.code === 0) {
this.registrationTypeOption = res.data
}
getEnrollmentRegistrationPlan() {
return this.$axios.post("/platform/enrollmentRegistration/apply/getEnrollmentRegistrationPlan").then(res => {
if (res.code === 0) {
this.$set(this, "registrationTypeOption", res.data)
}
})
},
init() {
setTimeout(() => {
this.childRelationshipOption = this.dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP
this.childrenPlanSchoolOption = this.dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL
const options = this.dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL || []
this.$set(this, "childrenPlanSchoolOption", options)
this.setChildrenPlanRegionName()
}, 300)
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
this.findOne(this.bizId).then(data => {
if (!data) {
return
}
this.$set(this, "formData", data)
//登记类型回显
const registrationType = this.registrationTypeOption.find(v => v.registrationType === data.registrationType)
if (registrationType) {
this.$set(this.formData, "registrationTypeName", registrationType.registrationTypeName)
}
//监护人与学生关系回显
const childRelationship = this.dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP.find(v => v.code === data.childRelationship)
if (childRelationship) {
this.$set(this.formData, "childRelationshipName", childRelationship.name)
}
//出生年月回显
if (data.childrenBirthday) {
this.$set(this.formData, "childrenBirthdayDate", new Date(data.childrenBirthday))
}
//拟报就读学校
const childrenPlanSchool = this.dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL.find(v => v.code === data.childrenPlanSchool)
if (childrenPlanSchool) {
this.$set(this.formData, "childrenPlanSchoolName", childrenPlanSchool.name)
}
this.setChildrenPlanRegionName()
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
this.formData = {
const {id, username, loginname, mobile, union, unit, position, technicalTitle, preparedBy} = this.$store.state.user
// 旧表单将职务和职称作为一个必填项,新建登记时优先合并当前用户档案中的两项信息。
const positionTitle = [position, technicalTitle].filter(item => item).join("、")
this.$set(this, "formData", {
userId: id,
userName: username,
loginName: loginname,
@@ -298,32 +345,40 @@ layout("/layouts/platform_h5.html"){
unionName: union.name,
unionId: union.id,
mobile: mobile,
}
positionTitle: positionTitle,
employmentType: preparedBy,
})
}
},
// childrenPlanSchool 保存拟选区域编码,本方法将字典名称写入移动端只读选择框用于回显。
setChildrenPlanRegionName() {
const childrenPlanSchool = this.childrenPlanSchoolOption.find(item => item.code === this.formData.childrenPlanSchool)
if (childrenPlanSchool) {
this.$set(this.formData, "childrenPlanRegionName", childrenPlanSchool.name)
}
},
onChildrenPlanSchoolConfirm(value, index) {
this.formData.childrenPlanSchool = this.childrenPlanSchoolOption[index].code;
this.formData.childrenPlanSchoolName = value;
this.$set(this.formData, "childrenPlanSchool", this.childrenPlanSchoolOption[index].code)
this.$set(this.formData, "childrenPlanRegionName", value)
this.showChildrenPlanSchoolPopup = false;
},
childrenBirthdayConfirm(value) {
this.formData.childrenBirthdayDate = value
this.formData.childrenBirthday = this.$moment(value).format("YYYY-MM-DD")
this.$set(this.formData, "childrenBirthdayDate", value)
this.$set(this.formData, "childrenBirthday", this.$moment(value).format("YYYY-MM-DD"))
this.childrenBirthdayPopup = false
},
onSexConfirm(value) {
this.formData.sex = value;
this.$set(this.formData, "sex", value)
this.showSexPopup = false;
},
onChildRelationshipConfirm(value, index) {
this.formData.childRelationship = this.childRelationshipOption[index].code;
this.formData.childRelationshipName = value;
this.showChildRelationshipPopup = false;
onEmploymentTypeConfirm(value) {
this.$set(this.formData, "employmentType", value)
this.showEmploymentTypePopup = false
},
onRegistrationTypeConfirm(value, index) {
this.formData.registrationType = this.registrationTypeOption[index].registrationType;
this.formData.registrationTypeName = value;
this.$set(this.formData, "registrationType", this.registrationTypeOption[index].registrationType)
this.$set(this.formData, "registrationTypeName", value)
this.showRegistrationTypePopup = false;
},
validateBirthday() {
@@ -331,7 +386,7 @@ layout("/layouts/platform_h5.html"){
return "请选择登记类型"
}
if (!this.formData.childrenBirthday) {
return "请选择子女出生年月"
return "请选择出生日期"
}
const childrenBirthday = new Date(this.formData.childrenBirthday);
@@ -363,30 +418,32 @@ layout("/layouts/platform_h5.html"){
return null; // 表示通过
},
async getIsRepeatByIdCard() {
// 校验参数:childrenIdCard 为子女身份证号,id 为当前登记主键;返回 Promise<boolean>true 表示本年度已存在重复登记。
getIsRepeatByIdCard() {
if (!this.formData.childrenIdCard) {
this.$toast.fail("请填写子女身份证号码")
return
return Promise.resolve(true)
}
const res = await this.$axios.post('/platform/enrollmentRegistration/apply/getIsRepeatByIdCard', {
return this.$axios.post('/platform/enrollmentRegistration/apply/getIsRepeatByIdCard', {
idCard: this.formData.childrenIdCard,
id: this.formData.id
})
if (res.code === 0) {
if (res.data > 0) {
this.$toast.fail("该身份证在本年度已填报!")
return true
} else {
}).then(res => {
if (res.code === 0) {
if (res.data > 0) {
this.$toast.fail("该身份证在本年度已填报!")
return true
}
this.$toast.success("该身份证在本年度暂未填报!")
return false
}
}
return true
})
},
async findOne(id) {
const resp = await $.get('/platform/enrollmentRegistration/apply/findOne', {id})
if (resp.code === 0) {
return resp.data
}
// 查询参数:id 为登记主键;返回 Promise<EnrollmentRegistration|null>,用于草稿及退回申请回显。
findOne(id) {
return this.$axios.post('/platform/enrollmentRegistration/apply/findOne', {id}).then(resp => {
return resp.code === 0 ? resp.data : null
})
},
onSave() {
const msg = this.validateBirthday()
@@ -402,7 +459,7 @@ layout("/layouts/platform_h5.html"){
data: JSON.stringify(this.formData)
}).then(res => {
if (res.code === 0) {
this.$toast.success("提交成功")
this.$toast.success("保存成功")
pjaxReplace("/platform/enrollmentRegistration/applyList/h5")
}
})
@@ -465,10 +522,10 @@ layout("/layouts/platform_h5.html"){
}
},
async created() {
await this.getEnrollmentRegistrationPlan()
this.init()
created() {
this.getEnrollmentRegistrationPlan().then(() => {
this.init()
})
}
})
</script>
@@ -4,21 +4,23 @@ const H5_ENROLLMENT_REGISTRATION_INFO = {
<div>
<div class="process-title">教职工信息</div>
<van-cell-group>
<van-cell title="监护人(教工)姓名">
<van-cell title="教职工姓名">
{{ viewData.userName }}
</van-cell>
<van-cell title="工号">
{{ viewData.loginName }}
</van-cell>
<van-cell title="职务、职称">
{{ viewData.positionTitle }}
</van-cell>
<van-cell title="手机号码">
{{ viewData.mobile }}
</van-cell>
<van-cell title="所在单位">
{{ viewData.unitName }}
</van-cell>
<van-cell title="监护人与学生关系">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP"
:value="viewData.childRelationship"></dict-tag>
<van-cell title="用工方式">
{{ viewData.employmentType }}
</van-cell>
<van-cell title="登记类型">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_TYPE"
@@ -41,20 +43,23 @@ const H5_ENROLLMENT_REGISTRATION_INFO = {
<van-cell title="出生日期">
{{viewData.childrenBirthday}}
</van-cell>
<van-cell title="现就读学校">
<van-cell title="读学校">
{{viewData.childrenCurrentSchool}}
</van-cell>
<van-cell title="拟报就读学校">
<van-cell title="户籍所在地">
{{viewData.childrenHuKouAddress}}
</van-cell>
<van-cell title="拟选区域">
<dict-tag :options="dict.type.ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"
:value="viewData.childrenPlanSchool"></dict-tag>
</van-cell>
<van-cell title="子女户口所在地">
{{viewData.childrenHuKouAddress}}
<van-cell title="拟选学校">
{{viewData.childrenPlanSchoolName}}
</van-cell>
<van-cell title="备注">
{{viewData.note}}
</van-cell>
<van-cell title="户口簿片">
<van-cell title="户口簿片">
<template #label>
<template v-for="(item,index) in viewData.huKouFiles">
<van-image :src="item.url"
@@ -64,7 +69,7 @@ const H5_ENROLLMENT_REGISTRATION_INFO = {
</template>
</template>
</van-cell>
<van-cell title="子女出生证片">
<van-cell title="子女出生证片">
<template #label>
<template v-for="(item,index) in viewData.birthCertificateFiles">
<van-image :src="item.url"
@@ -74,6 +79,26 @@ const H5_ENROLLMENT_REGISTRATION_INFO = {
</template>
</template>
</van-cell>
<van-cell title="学历学位证或教师资格证">
<template #label>
<template v-for="(item,index) in viewData.qualificationCertificateFiles">
<van-image :src="item.url"
v-if="item.url"
class="signature-image"
@click="previewOptionImg(viewData.qualificationCertificateFiles,index)"></van-image>
</template>
</template>
</van-cell>
<van-cell title="聘用合同复印件">
<template #label>
<template v-for="(item,index) in viewData.employmentContractFiles">
<van-image :src="item.url"
v-if="item.url"
class="signature-image"
@click="previewOptionImg(viewData.employmentContractFiles,index)"></van-image>
</template>
</template>
</van-cell>
</van-cell-group>
<template v-for="(task,index) in doneTasks">
@@ -122,7 +147,7 @@ const H5_ENROLLMENT_REGISTRATION_INFO = {
</div>
</van-action-sheet>
`,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL", "PROCESS_TASK_SUBMIT_TYPE"],
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL", "PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible: false,
@@ -2,135 +2,85 @@
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.search-dialog {
height: 80%;
}
</style>
<div id="app">
<!-- 导航栏 -->
<van-nav-bar title="职工慰问申请" left-text="返回" left-arrow @click-left="historyBack" fixed
<van-nav-bar title="填写慰问申请" left-text="返回" left-arrow @click-left="historyBack" fixed
placeholder></van-nav-bar>
<!-- 表单容器 -->
<van-form ref="formRef" class="form-container">
<!-- 基本信息 -->
<van-cell-group title="基本信息" class="form-section">
<van-field label="申请人姓名" :rules="[{ required: true }]" v-model="formData.applyUserName" readonly
required name="applyUserName"></van-field>
<van-field label="申请人工号" :rules="[{ required: true }]" v-model="formData.applyLoginName" readonly
required name="applyLoginName"></van-field>
<van-field label="申请人单位" :rules="[{ required: true }]" v-model="formData.applyUnitName" readonly
required name="applyUnitName"></van-field>
<van-field label="申请人工会" :rules="[{ required: true }]" v-model="formData.applyUnionName" readonly
required name="applyUnionName"></van-field>
<van-cell-group title="申请信息" class="form-section">
<van-field label="申请人" v-model="formData.applyUserName" readonly name="applyUserName"></van-field>
<van-field label="申请时间" v-model="formData.createTime" readonly name="createTime"></van-field>
<van-field
v-model="formData.helpUserName"
name="helpUserName"
label="慰问对象"
label="补贴对象"
required
readonly
:rules="[{ required: true }]"
placeholder="请点击选择慰问对象"
@click="helpUserSelectShow = true"
:rules="[{ required: true, message: '请选择补贴对象' }]"
placeholder="请点击选择补贴对象"
@click="openUserSelect('help')"
is-link
></van-field>
<van-action-sheet v-model="helpUserSelectShow" title="慰问对象" class="height100">
<van-action-sheet v-model="helpUserSelectShow" title="补贴对象" class="height100">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择慰问对象"
placeholder="请输入工号或姓名选择补贴对象"
@input="(val) => {userRemoteMethod(val, 'help')}"
@clear="(val) => {userRemoteMethod(val, 'help')}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length>0">
<template>
<template v-for="item in userOptions">
<van-button native-type="button" @click="helpUserChange(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">{{item.userName}}{{item.loginName}}</span>
</van-button>
</template>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length > 0">
<template v-for="item in userOptions">
<van-button :key="item.id" native-type="button" @click="helpUserChange(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">
{{item.userName}}{{item.loginName}}{{item.unitName}}
</span>
</van-button>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>
<!-- <van-field
v-model="formData.handlerUserName"
name="handlerUserName"
label="经办人"
<van-field label="性别" v-model="formData.sex" readonly name="sex"></van-field>
<van-field
v-model="formData.mobile"
name="mobile"
label="联系电话"
required
readonly
:rules="[{ required: true }]"
placeholder="请点击选择经办人"
@click="handlerUserSelectShow = true"
is-link
clearable
maxlength="30"
placeholder="请填写联系电话"
:rules="[{ required: true, message: '请填写联系电话' }]"
></van-field>
<van-action-sheet v-model="handlerUserSelectShow" title="经办人" class="height100">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择经办人"
@input="(val) => {userRemoteMethod(val, 'handler')}"
@clear="(val) => {userRemoteMethod(val, 'handler')}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length>0">
<template>
<template v-for="item in userOptions">
<van-button native-type="button" @click="handlerUserChange(item)"
class="van-action-sheet__item van-hairline&#45;&#45;bottom">
<span class="van-action-sheet__name">{{item.userName}}{{item.loginName}}</span>
</van-button>
</template>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>-->
<van-field
v-model="formData.certifierUserName"
name="certifierUserName"
label="证明人"
v-model="formData.birthday"
name="birthday"
label="出生年月"
required
readonly
:rules="[{ required: true }]"
placeholder="请点击选择证明人"
@click="certifierUserSelectShow = true"
clickable
is-link
placeholder="请点击选择出生年月"
:rules="[{ required: true, message: '请选择出生年月' }]"
@click="showBirthdayPickerClick"
></van-field>
<van-action-sheet v-model="certifierUserSelectShow" title="证明人" class="height100">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择证明人"
@input="(val) => {userRemoteMethod(val, 'certifier')}"
@clear="(val) => {userRemoteMethod(val, 'certifier')}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length>0">
<template>
<template v-for="item in userOptions">
<van-button native-type="button" @click="certifierUserChange(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">{{item.userName}}{{item.loginName}}</span>
</van-button>
</template>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>
<van-popup position="bottom" round v-model:show="showBirthdayPicker">
<van-datetime-picker
v-model="birthdayDate"
type="date"
:min-date="minDate"
:max-date="maxDate"
title="请选择出生年月"
@confirm="onBirthdayConfirm"
@cancel="closeBirthdayPicker"
></van-datetime-picker>
</van-popup>
<van-field
v-model="formData.typeName"
@@ -138,148 +88,64 @@ layout("/layouts/platform_h5.html"){
label="慰问类型"
required
readonly
:rules="[{ required: true }]"
:rules="[{ required: true, message: '请选择慰问类型' }]"
placeholder="请点击选择慰问类型"
@click="showTypePickerClick"
clickable
is-link
></van-field>
<van-popup position="bottom" round v-model:show="showTypePicker">
<van-picker :columns="typeColumns" @cancel="showTypePicker = false" @confirm="onTypeConfirm"
<van-picker :columns="typeColumns" @cancel="closeTypePicker" @confirm="onTypeConfirm"
show-toolbar :default-index="typeDefaultIndex"></van-picker>
</van-popup>
<!--<van-field
v-model="formData.way"
name="way"
label="慰问方式"
required
readonly
:rules="[{ required: true }]"
placeholder="请选择慰问类型"
clickable
></van-field>-->
<van-field
v-model="formData.money"
name="money"
label="慰问金额"
required
:rules="[{ required: true }]"
placeholder="选择慰问类型自动匹配金额"
clickable
type="number"
></van-field>
<van-field
v-model="formData.occurTime"
name="occurTime"
label="慰问时间"
required
:rules="[{ required: true }]"
placeholder="请点击选择慰问时间"
clickable
is-link
readonly
@click="showTimePickerClick"
></van-field>
<van-popup position="bottom" round v-model:show="showTimePicker">
<van-datetime-picker
v-model="formData.occurDate"
type="date"
:min-date="minDate"
:max-date="maxDate"
title="请选择慰问时间"
@confirm="(val) => {formData.occurTime = $moment(val).format('YYYY-MM-DD'); showTimePicker = false}"
@cancel="showTimePicker = false"
></van-datetime-picker>
</van-popup>
<van-field
v-model="formData.bankCardNumber"
label="收款账户"
maxlength="20"
clearable
name="bankCardNumber"
placeholder="请填写收款账户"
:rules="[{ required: true }]"
required
></van-field>
<van-field
v-model="formData.bankUserName"
label="户名"
placeholder="请填写户名"
:rules="[{ required: true }]"
required
maxlength="20"
name="bankUserName"
></van-field>
<van-field
v-model="formData.bankOfDeposit"
label="开户行"
maxlength="30"
type="textarea"
rows="4"
autosize
placeholder="请填写开户行"
:rules="[{ required: true }]"
required
name="bankOfDeposit"
></van-field>
<template v-if="['2'].includes(formData.typeCode)">
<template v-if="showPayUserFields">
<van-field
v-model="formData.hospitalizationTime"
name="hospitalizationTime"
label="入院时间"
v-model="formData.payUserName"
name="payUserName"
label="收款人"
required
:rules="[{ required: true }]"
placeholder="请点击选择入院时间"
clickable
is-link
readonly
@click="showHospitalizationTimePickerClick"
></van-field>
<van-popup position="bottom" round v-model:show="showHospitalizationTimePicker">
<van-datetime-picker
v-model="formData.hospitalizationDate"
type="date"
:min-date="minDate"
:max-date="maxDate"
title="请选择入院时间"
@confirm="(val) => {formData.hospitalizationTime = $moment(val).format('YYYY-MM-DD'); showHospitalizationTimePicker = false}"
@cancel="showHospitalizationTimePicker = false"
></van-datetime-picker>
</van-popup>
<van-field
v-model="formData.leaveHospitalTime"
name="leaveHospitalTime"
label="出院时间"
required
:rules="[{ required: true }]"
placeholder="请点击选择出院时间"
clickable
:rules="[{ required: true, message: '请选择收款人' }]"
placeholder="请点击选择收款人"
@click="openUserSelect('pay')"
is-link
readonly
@click="showLeaveHospitalTimePickerClick"
></van-field>
<van-popup position="bottom" round v-model:show="showLeaveHospitalTimePicker">
<van-datetime-picker
v-model="formData.leaveHospitalDate"
type="date"
:min-date="minDate"
:max-date="maxDate"
title="请选择出院时间"
@confirm="(val) => {formData.leaveHospitalTime = $moment(val).format('YYYY-MM-DD'); showLeaveHospitalTimePicker = false}"
@cancel="showLeaveHospitalTimePicker = false"
></van-datetime-picker>
</van-popup>
<van-action-sheet v-model="payUserSelectShow" title="收款人" class="height100">
<van-search
v-model="searchKeyword"
:show-action="false"
:reverse-color="false"
input-align="left"
placeholder="请输入工号或姓名选择收款人"
@input="(val) => {userRemoteMethod(val, 'pay')}"
@clear="(val) => {userRemoteMethod(val, 'pay')}"
shape="round"
></van-search>
<div class="van-action-sheet__content mt5" v-if="userOptions && userOptions.length > 0">
<template v-for="item in userOptions">
<van-button :key="item.id" native-type="button" @click="payUserChange(item)"
class="van-action-sheet__item van-hairline--bottom">
<span class="van-action-sheet__name">
{{item.userName}}{{item.loginName}})({{item.unitName}}
</span>
</van-button>
</template>
</div>
<van-empty description="暂无数据" v-else></van-empty>
</van-action-sheet>
<van-field type="digit" label="当年第几次住院"
:rules="[{ required: true }]"
required
placeholder="请输入当年第几次住院"
v-model="formData.thisYearHospitalizationNum"></van-field>
<van-field
v-model="formData.bankCardNumber"
name="bankCardNumber"
label="收款人银行卡"
required
clearable
maxlength="30"
type="digit"
placeholder="请填写收款人银行卡"
:rules="[{ required: true, message: '请填写收款人银行卡' }]"
></van-field>
</template>
<van-field
@@ -289,20 +155,30 @@ layout("/layouts/platform_h5.html"){
type="textarea"
rows="4"
autosize
placeholder="请输入申请事由"
:rules="[{ required: true }]"
maxlength="500"
show-word-limit
placeholder="请填写申请事由"
:rules="[{ required: true, message: '请填写申请事由' }]"
required
></van-field>
</van-cell-group>
<van-cell-group class="form-section" v-if="chooseType.isUploadFile === true">
<template #title>
<span>附件</span>
<span v-if="chooseType.isUploadFile && chooseType.uploadFileDesc" style="color: orangered">
{{ '(附件说明:' + chooseType.uploadFileDesc + '' }}
</span>
</template>
<van-field class="direction-column-field" name="avatar" label="">
<van-cell-group title="纸质申请表" class="form-section">
<van-field class="direction-column-field" name="applyFiles" label="">
<template #input>
<h5-file-upload
slot="input"
:value.sync="formData.applyFiles"
:upload_number="1"
upload_result_category="array"
complete_result
></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<van-cell-group title="附件" class="form-section">
<van-field class="direction-column-field" name="files" label="">
<template #input>
<h5-file-upload
slot="input"
@@ -315,19 +191,14 @@ layout("/layouts/platform_h5.html"){
</van-field>
</van-cell-group>
<van-cell-group title="签字" class="form-section">
<van-field class="direction-column-field" name="signature" label="">
<template #input>
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
</template>
</van-field>
</van-cell-group>
<!-- 提交按钮 -->
<div class="form-actions">
<van-button native-type="button" @click="onSave" round type="info" plain>保存申请</van-button>
<van-button @click="onSubmit" round type="info" v-if="!taskId">提交申请</van-button>
<van-button @click="onFinishTask" round type="info" v-else>提交申请</van-button>
<div v-if="bizId || !applyClosed" class="form-actions">
<van-button native-type="button" :loading="formLoading" @click="onSave" round type="info" plain>
保存申请
</van-button>
<van-button native-type="button" :loading="formLoading" @click="onSubmit" round type="info"
v-if="!taskId">提交申请</van-button>
<van-button native-type="button" :loading="formLoading" @click="onFinishTask" round type="info"
v-else>提交申请</van-button>
</div>
</van-form>
</div>
@@ -341,111 +212,116 @@ layout("/layouts/platform_h5.html"){
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formLoading: false,
applyEndDate: "",
formData: {},
chooseType: {},
userOptions: [],
typeOptions: [],
helpUserSelectShow: false,
payUserSelectShow: false,
showTypePicker: false,
typeColumns: [],
searchKeyword: "",
showTimePicker: false,
showChildPicker: false,
showFamilyPicker: false,
certifierUserSelectShow: false,
handlerUserSelectShow: false,
showHospitalizationTimePicker: false,
showLeaveHospitalTimePicker: false,
minDate: new Date(2024, 0, 1),
helpUserSelectShow: false,
payUserSelectShow: false,
showBirthdayPicker: false,
showTypePicker: false,
birthdayDate: new Date(),
minDate: new Date(1959, 0, 1),
maxDate: new Date(),
typeDefaultIndex: 0
typeDefaultIndex: 0,
// A、B 类型不需要维护收款人及银行卡信息。
noPayUserTypeCodes: ["A", "B"]
}
},
computed: {
// 历史申请缺少 typeCode 时,根据已保存的类型 ID 回查编码,保证重新提交显隐正确。
selectedTypeCode() {
if (this.formData.typeCode) {
return this.formData.typeCode
}
const selectedType = this.typeOptions.find(item => item.id === this.formData.type)
return selectedType ? selectedType.code : ""
},
showPayUserFields() {
return this.selectedTypeCode && !this.noPayUserTypeCodes.includes(this.selectedTypeCode)
},
// 与 PC、旧系统保持一致:截止日期当天不再显示新申请的保存和提交按钮。
applyClosed() {
if (!this.applyEndDate || !this.$moment(this.applyEndDate).isValid()) {
return false
}
return this.$moment(this.applyEndDate).valueOf()
<= this.$moment(this.$moment().format("YYYY-MM-DD")).valueOf()
}
},
methods: {
// 选择出院时间
showLeaveHospitalTimePickerClick() {
if (this.formData.leaveHospitalTime) {
this.formData.leaveHospitalDate = new Date(this.formData.leaveHospitalTime)
}
this.showLeaveHospitalTimePicker = true
/**
* 查询慰问申报截止日期。
* @returns {Promise<Object>} Axios 请求 Promise,响应 data 为 yyyy-MM-dd 日期字符串。
*/
queryApplyEndDate() {
return this.$axios.post("/platform/condolence/apply/getApplyEndDate").then((res) => {
if (res.code === 0) {
this.$set(this, "applyEndDate", res.data || "")
}
return res
})
},
// 选择住院时间
showHospitalizationTimePickerClick() {
if (this.formData.hospitalizationTime) {
this.formData.hospitalizationDate = new Date(this.formData.hospitalizationTime)
}
this.showHospitalizationTimePicker = true
showBirthdayPickerClick() {
this.birthdayDate = this.formData.birthday ? new Date(this.formData.birthday) : new Date()
this.showBirthdayPicker = true
},
// 选择慰问时间
showTimePickerClick() {
if (this.formData.occurTime) {
this.formData.occurDate = new Date(this.formData.occurTime)
}else{
this.formData.occurDate = new Date()
}
this.showTimePicker = true
onBirthdayConfirm(val) {
this.$set(this.formData, "birthday", this.$moment(val).format("YYYY-MM-DD"))
this.showBirthdayPicker = false
},
closeBirthdayPicker() {
this.showBirthdayPicker = false
},
// 选择慰问类型
showTypePickerClick() {
if (this.formData.type) {
this.typeDefaultIndex = this.typeOptions.findIndex(item => item.id === this.formData.type)
}
this.showTypePicker = true
},
//经办人
handlerUserChange(user) {
const { id, userName, loginName, unitId, unitName, unionId, unionName } = user
this.$set(this.formData, "handlerUserId", id)
this.$set(this.formData, "handlerUserName", userName)
this.$set(this.formData, "handlerLoginName", loginName)
this.$set(this.formData, "handlerUnitId", unitId)
this.$set(this.formData, "handlerUnitName", unitName)
this.$set(this.formData, "handlerUnionId", unionId)
this.$set(this.formData, "handlerUnionName", unionName)
this.handlerUserSelectShow = false
this.searchKeyword = ""
this.userOptions = []
closeTypePicker() {
this.showTypePicker = false
},
//证明人
certifierUserChange(user) {
const { id, userName, loginName, unitId, unitName, unionId, unionName } = user
this.$set(this.formData, "certifierUserId", id)
this.$set(this.formData, "certifierUserName", userName)
this.$set(this.formData, "certifierLoginName", loginName)
this.$set(this.formData, "certifierUnitId", unitId)
this.$set(this.formData, "certifierUnitName", unitName)
this.$set(this.formData, "certifierUnionId", unionId)
this.$set(this.formData, "certifierUnionName", unionName)
this.certifierUserSelectShow = false
openUserSelect(type) {
this.searchKeyword = ""
this.userOptions = []
},
async userRemoteMethod(event, type) {
if (event) {
this.userOptions = await this.selectQueryUser(event)
if (type === "help") {
this.helpUserSelectShow = true
} else if (type === "certifier") {
this.certifierUserSelectShow = true
} else if (type === "handler") {
this.handlerUserSelectShow = true
}
this.userOptions.splice(0, this.userOptions.length)
if (type === "help") {
this.helpUserSelectShow = true
} else {
this.payUserSelectShow = true
}
},
async selectQueryUser(keyword) {
const res = await this.$axios.post("/platform/condolence/apply/listUser", { keyword: keyword })
return res.data
/**
* 根据姓名或工号查询补贴对象、收款人候选项。
* @param {string} keyword 姓名或工号关键字;空值时清空候选项。
* @returns {Promise<Array>} Promise 结果为用户数组,字段包含人员、单位和工会信息。
*/
selectQueryUser(keyword) {
if (!keyword) {
this.userOptions.splice(0, this.userOptions.length)
return Promise.resolve([])
}
return this.$axios.post("/platform/condolence/apply/listUser", { keyword: keyword }).then((res) => {
const users = res.code === 0 ? res.data : []
this.userOptions.splice(0, this.userOptions.length, ...users)
return users
})
},
userRemoteMethod(keyword, type) {
this.selectQueryUser(keyword).then(() => {
if (type === "help") {
this.helpUserSelectShow = true
} else {
this.payUserSelectShow = true
}
})
},
// 选择补贴对象后保存人员快照,重新提交时仍展示申请时的信息。
helpUserChange(user) {
const { id, userName, loginName, unitId, unitName, unionId, unionName } = user
const { id, userName, loginName, unitId, unitName, unionId, unionName, sex, mobile, birthday } = user
this.$set(this.formData, "helpUserId", id)
this.$set(this.formData, "helpUserName", userName)
this.$set(this.formData, "helpLoginName", loginName)
@@ -453,10 +329,14 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "helpUnitName", unitName)
this.$set(this.formData, "helpUnionId", unionId)
this.$set(this.formData, "helpUnionName", unionName)
this.$set(this.formData, "sex", sex)
this.$set(this.formData, "mobile", mobile)
this.$set(this.formData, "birthday", birthday ? this.$moment(birthday).format("YYYY-MM-DD") : "")
this.helpUserSelectShow = false
this.searchKeyword = ""
this.userOptions = []
this.userOptions.splice(0, this.userOptions.length)
},
// 收款人同时保存姓名和工号,用于详情展示及重新提交回显。
payUserChange(user) {
const { id, userName, loginName } = user
this.$set(this.formData, "payUserId", id)
@@ -464,72 +344,95 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "payLoginName", loginName)
this.payUserSelectShow = false
this.searchKeyword = ""
this.userOptions = []
this.userOptions.splice(0, this.userOptions.length)
},
typeChange(id) {
this.chooseType = this.typeOptions.find(o => o.id === id)
if (this.chooseType) {
this.$set(this.formData, "money", this.chooseType.money)
this.$set(this.formData, "way", this.chooseType.way)
this.$set(this.formData, "typeCode", this.chooseType.code)
const chooseType = this.typeOptions.find(item => item.id === id)
if (chooseType) {
this.$set(this.formData, "money", chooseType.money)
this.$set(this.formData, "way", chooseType.way)
this.$set(this.formData, "typeCode", chooseType.code)
}
// 切换到无需收款人的类型时清除隐藏字段,避免旧收款信息被提交。
if (!this.showPayUserFields) {
this.$set(this.formData, "payUserId", "")
this.$set(this.formData, "payUserName", "")
this.$set(this.formData, "payLoginName", "")
this.$set(this.formData, "bankCardNumber", "")
}
},
onTypeConfirm(o) {
this.$set(this.formData, "typeName", o.text)
this.$set(this.formData, "type", o.value)
this.typeChange(o.value)
onTypeConfirm(option) {
this.$set(this.formData, "typeName", option.text)
this.$set(this.formData, "type", option.value)
this.typeChange(option.value)
this.showTypePicker = false
},
validateUploadFiles() {
if (!this.formData.applyFiles || this.formData.applyFiles.length === 0) {
this.$toast.fail("请上传纸质申请表")
return false
}
if (!this.formData.files || this.formData.files.length === 0) {
this.$toast.fail("请上传附件")
return false
}
return true
},
/**
* 保存或提交申请。
* @param {string} url 保存、首次提交或重新提交接口地址。
* @param {Object} params data 为表单 JSON;重新提交时同时包含 taskId。
* @returns {Promise<Object>} Axios 请求 Promise,成功后跳转到移动端我的申请。
*/
sendApplyRequest(url, params) {
this.formLoading = true
return this.$axios.post(url, params).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/condolence/mine/h5")
}
return res
}).finally(() => {
this.formLoading = false
})
},
onSave() {
this.$dialog.confirm({
title: "提示",
message: "您确定保存吗?"
}).then(() => {
this.$axios.post("/platform/condolence/apply/save", { data: JSON.stringify(this.formData) }).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/condolence/mine/h5")
}
this.sendApplyRequest("/platform/condolence/apply/save", {
data: JSON.stringify(this.formData)
})
})
},
async onSubmit() {
onSubmit() {
this.$refs.formRef.validate().then(() => {
if (!this.formData.signature){
this.$toast.fail("请填写签字")
if (!this.validateUploadFiles()) {
return
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交申请吗?"
}).then(() => {
this.$axios.post("/platform/condolence/apply/submit", { data: JSON.stringify(this.formData) }).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/condolence/mine/h5")
}
this.sendApplyRequest("/platform/condolence/apply/submit", {
data: JSON.stringify(this.formData)
})
})
})
},
async onFinishTask() {
onFinishTask() {
this.$refs.formRef.validate().then(() => {
if (!this.formData.signature){
this.$toast.fail("请填写签字")
if (!this.validateUploadFiles()) {
return
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交申请吗?"
}).then(() => {
this.$axios.post("/platform/condolence/apply/submitAgain", {
this.sendApplyRequest("/platform/condolence/apply/submitAgain", {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/condolence/mine/h5")
}
taskId: this.taskId
})
})
})
@@ -538,38 +441,61 @@ layout("/layouts/platform_h5.html"){
if (this.bizId) {
this.$axios.post("/platform/condolence/mine/info", { id: this.bizId }).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.selectQueryUser(this.formData.helpLoginName, this.helpUserOptions)
this.selectQueryUser(this.formData.payLoginName, this.payUserOptions)
this.chooseType = this.typeOptions.find(o => o.id === this.formData.type)
this.$set(this, "formData", res.data)
}
})
} else {
const { username, loginname, id, unit, union, mobile } = this.$store.state.user
this.formData = {
const { username, loginname, id, unit, union, mobile, sex, birthday } = this.$store.state.user
this.$set(this, "formData", {
applyUserName: username,
applyLoginName: loginname,
applyUserId: id,
applyUnitId: unit?.id,
applyUnitName: unit?.name,
applyUnionId: union?.id,
applyUnionName: union?.name
}
applyUnionName: union?.name,
createTime: this.$moment().format("YYYY-MM-DD"),
helpUserId: id,
helpUserName: username,
helpLoginName: loginname,
helpUnitId: unit?.id,
helpUnitName: unit?.name,
helpUnionId: union?.id,
helpUnionName: union?.name,
sex: sex,
mobile: mobile,
birthday: birthday ? this.$moment(birthday).format("YYYY-MM-DD") : "",
applyFiles: [],
files: []
})
}
},
/**
* 按当前用户角色过滤可申请的慰问类型。
* @param {Array} options 接口返回的全部启用慰问类型。
* @returns {Array} 系统管理员、校工会管理员返回全部类型,其他角色仅返回编码 A、B 的类型。
*/
filterTypeOptions(options) {
if (this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])) {
return options
}
return options.filter(item => ["A", "B"].includes(item.code))
},
queryCondolenceType() {
this.$axios.post("/platform/condolence/type/queryCondolenceType")
.then((res) => {
this.typeOptions = JSON.parse(JSON.stringify(res.data))
res.data.forEach((v) => {
this.typeColumns.push({ value: v.id, text: v.name })
})
})
return this.$axios.post("/platform/condolence/type/queryCondolenceType").then((res) => {
const options = this.filterTypeOptions(res.data)
this.typeOptions.splice(0, this.typeOptions.length, ...options)
this.typeColumns.splice(0, this.typeColumns.length, ...options.map(item => {
return { value: item.id, text: item.name + "" + item.money + "元)" }
}))
return res
})
}
},
created() {
this.queryCondolenceType()
this.init()
Promise.all([this.queryCondolenceType(), this.queryApplyEndDate()]).then(() => {
this.init()
})
}
})
</script>
@@ -4,37 +4,31 @@ const condolenceInfo = {
`
<van-action-sheet v-model="visible" title="查看详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="申请人姓名">{{ viewData.applyUserName }}</van-cell>
<van-cell title="申请人工号">{{ viewData.applyLoginName }}</van-cell>
<van-cell title="申请人单位">{{ viewData.applyUnitName }}</van-cell>
<van-cell title="申请人工会">{{ viewData.applyUnionName }}</van-cell>
<van-cell title="慰问对象">{{ viewData.helpUserName }}</van-cell>
<!-- <van-cell title="经办人">{{ viewData.handlerUserName }}</van-cell>-->
<van-cell title="证明人">{{ viewData.certifierUserName }}</van-cell>
<van-cell title="慰问类型">{{ viewData.typeName }}</van-cell>
<van-cell title="慰问金额">{{ viewData.money }}</van-cell>
<van-cell title="慰问时间">{{ viewData.occurTime }}</van-cell>
<van-cell title="收款账户">{{ viewData.bankCardNumber }}</van-cell>
<van-cell title="户名">{{ viewData.bankUserName }}</van-cell>
<van-cell class="direction-column-cell" title="开户行">
{{ viewData.bankOfDeposit || '暂无' }}
<van-cell-group title="申请信息">
<van-cell title="申请人">{{ viewData.applyUserName }}</van-cell>
<van-cell title="申请时间">{{ viewData.createTime }}</van-cell>
<van-cell title="补贴对象">{{ viewData.helpUserName }}</van-cell>
<van-cell title="性别">{{ viewData.sex }}</van-cell>
<van-cell title="联系电话">{{ viewData.mobile }}</van-cell>
<van-cell title="出生年月">{{ viewData.birthday }}</van-cell>
<van-cell title="补贴类型">{{ viewData.typeName }}</van-cell>
<van-cell title="补贴金额">{{ viewData.money }}</van-cell>
<van-cell title="收款人" v-if="viewData.payUserName">{{ viewData.payUserName }}</van-cell>
<van-cell title="收款人卡号" v-if="viewData.bankCardNumber">
{{ viewData.bankCardNumber }}
</van-cell>
<template v-if="['2'].includes(viewData.typeCode)">
<van-cell title="入院时间">{{ viewData.hospitalizationTime }}</van-cell>
<van-cell title="出院时间">{{ viewData.leaveHospitalTime }}</van-cell>
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum }}</van-cell>
</template>
<van-cell class="direction-column-cell" title="申请事由">
{{ viewData.remark || '暂无' }}
</van-cell>
<van-cell class="direction-column-cell" title="附件">
<file-preview :files="viewData.files" complete_result></file-preview>
<van-cell class="direction-column-cell" title="纸质申请表">
<file-preview v-if="viewData.applyFiles && viewData.applyFiles.length > 0"
:files="viewData.applyFiles" complete_result></file-preview>
<span v-else>暂无纸质申请表</span>
</van-cell>
<van-cell class="direction-column-cell" title="签字">
<van-image :src="viewData.signature" v-if="viewData.signature"
class="signature-image"></van-image>
<span v-else>暂无签字</span>
<van-cell class="direction-column-cell" title="附件">
<file-preview v-if="viewData.files && viewData.files.length > 0"
:files="viewData.files" complete_result></file-preview>
<span v-else>暂无附件</span>
</van-cell>
</van-cell-group>
<template v-for="task in doneTasks">