Compare commits
10
Commits
9c17925b60
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
790e8e9f50 | ||
|
|
81fd5cb773 | ||
|
|
efad953710 | ||
|
|
e0004e410f | ||
|
|
f8457386fd | ||
|
|
16cae3ed2b | ||
|
|
29260423d5 | ||
|
|
d8e7adfe9a | ||
|
|
bc1b3bf7fe | ||
|
|
59fd83ba24 |
@@ -6,6 +6,8 @@ import com.budwk.app.base.exception.BaseException;
|
|||||||
import com.budwk.app.sys.models.Sys_file;
|
import com.budwk.app.sys.models.Sys_file;
|
||||||
import com.budwk.app.sys.models.Sys_office_template;
|
import com.budwk.app.sys.models.Sys_office_template;
|
||||||
import com.budwk.app.sys.utils.SysFileMinIoUtil;
|
import com.budwk.app.sys.utils.SysFileMinIoUtil;
|
||||||
|
import com.deepoove.poi.XWPFTemplate;
|
||||||
|
import com.deepoove.poi.config.Configure;
|
||||||
import com.deepoove.poi.data.ByteArrayPictureRenderData;
|
import com.deepoove.poi.data.ByteArrayPictureRenderData;
|
||||||
import com.deepoove.poi.data.PictureRenderData;
|
import com.deepoove.poi.data.PictureRenderData;
|
||||||
import com.deepoove.poi.data.PictureType;
|
import com.deepoove.poi.data.PictureType;
|
||||||
@@ -18,6 +20,12 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -66,6 +74,88 @@ public class SysOfficeTemplateUtil {
|
|||||||
return new ByteArrayInputStream(fileBytes);
|
return new ByteArrayInputStream(fileBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一渲染 DOC/DOCX 模板,保留调用方的循环表格等策略;模板输入流由调用方关闭。
|
||||||
|
*/
|
||||||
|
public byte[] renderTemplate(InputStream input, Object data, Configure config, boolean pdf, String context) throws Exception {
|
||||||
|
if (input == null) throw new BaseException("模板文件不存在");
|
||||||
|
byte[] templateBytes = input.readAllBytes();
|
||||||
|
try (ByteArrayInputStream formatInput = new ByteArrayInputStream(templateBytes)) {
|
||||||
|
if (com.aspose.words.FileFormatUtil.detectFileFormat(formatInput).getLoadFormat() != com.aspose.words.LoadFormat.DOCX) {
|
||||||
|
try (ByteArrayInputStream source = new ByteArrayInputStream(templateBytes);
|
||||||
|
ByteArrayOutputStream converted = new ByteArrayOutputStream()) {
|
||||||
|
new com.aspose.words.Document(source).save(converted, com.aspose.words.SaveFormat.DOCX);
|
||||||
|
templateBytes = converted.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte[] wordBytes;
|
||||||
|
try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateBytes);
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
XWPFTemplate template = XWPFTemplate.compile(templateInput, config == null ? Configure.builder().build() : config)) {
|
||||||
|
template.render(data).write(output);
|
||||||
|
wordBytes = output.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[Office模板渲染] Word模板渲染失败,context={}", context, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.info("[Office模板渲染] Word渲染完成,context={}, templateBytes={}, outputBytes={}", context, templateBytes.length, wordBytes.length);
|
||||||
|
if (!pdf) return wordBytes;
|
||||||
|
try (ByteArrayInputStream wordInput = new ByteArrayInputStream(wordBytes);
|
||||||
|
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||||
|
com.aspose.words.Document document = new com.aspose.words.Document(wordInput);
|
||||||
|
configureDocumentFonts(document, context);
|
||||||
|
com.aspose.words.PdfSaveOptions options = new com.aspose.words.PdfSaveOptions();
|
||||||
|
options.setFontEmbeddingMode(com.aspose.words.PdfFontEmbeddingMode.EMBED_ALL);
|
||||||
|
document.save(output, options);
|
||||||
|
log.info("[Office模板渲染] PDF转换完成,context={}, outputBytes={}", context, output.size());
|
||||||
|
return output.toByteArray();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[Office模板渲染] PDF转换失败,context={}", context, e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureDocumentFonts(com.aspose.words.Document document, String context) throws Exception {
|
||||||
|
com.aspose.words.FontSettings settings = new com.aspose.words.FontSettings();
|
||||||
|
List<com.aspose.words.FontSourceBase> sources = new ArrayList<>(List.of(settings.getFontsSources()));
|
||||||
|
Set<String> folders = new LinkedHashSet<>();
|
||||||
|
String windowsDir = System.getenv("WINDIR");
|
||||||
|
if (StrUtil.isNotBlank(windowsDir)) folders.add(new File(windowsDir, "Fonts").getPath());
|
||||||
|
String localAppData = System.getenv("LOCALAPPDATA");
|
||||||
|
if (StrUtil.isNotBlank(localAppData)) folders.add(new File(localAppData, "Microsoft/Windows/Fonts").getPath());
|
||||||
|
folders.add(new File(System.getProperty("user.dir"), "fonts").getPath());
|
||||||
|
for (String folder : folders) {
|
||||||
|
File directory = new File(folder);
|
||||||
|
log.info("[Office模板渲染] 字体目录,context={}, path={}, readable={}", context, folder, directory.isDirectory() && directory.canRead());
|
||||||
|
if (directory.isDirectory() && directory.canRead()) sources.add(new com.aspose.words.FolderFontSource(folder, true));
|
||||||
|
}
|
||||||
|
settings.setFontsSources(sources.toArray(new com.aspose.words.FontSourceBase[0]));
|
||||||
|
Set<String> availableFonts = new LinkedHashSet<>();
|
||||||
|
for (com.aspose.words.FontSourceBase source : sources) {
|
||||||
|
for (com.aspose.words.PhysicalFontInfo font : source.getAvailableFonts()) availableFonts.add(font.getFontFamilyName());
|
||||||
|
}
|
||||||
|
String chineseFont = null;
|
||||||
|
for (String candidate : List.of("SimSun", "宋体", "Microsoft YaHei", "微软雅黑", "DengXian", "等线", "SimHei", "黑体", "FangSong", "仿宋", "Noto Serif CJK SC", "Noto Sans CJK SC")) {
|
||||||
|
if (availableFonts.contains(candidate)) {
|
||||||
|
chineseFont = candidate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("[Office模板渲染] 中文字体选择,context={}, fontCount={}, chineseFont={}", context, availableFonts.size(), chineseFont);
|
||||||
|
if (chineseFont != null) {
|
||||||
|
settings.getSubstitutionSettings().getDefaultFontSubstitution().setDefaultFontName(chineseFont);
|
||||||
|
for (String name : List.of("宋体", "SimSun", "新宋体", "NSimSun", "黑体", "SimHei", "仿宋", "FangSong", "楷体", "KaiTi", "微软雅黑", "Microsoft YaHei")) {
|
||||||
|
if (!availableFonts.contains(name)) settings.getSubstitutionSettings().getTableSubstitution().setSubstitutes(name, chineseFont);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.warn("[Office模板渲染] 未发现常用中文字体,context={}, availableFonts={}", context, availableFonts);
|
||||||
|
}
|
||||||
|
settings.getFallbackSettings().loadMsOfficeFallbackSettings();
|
||||||
|
document.setFontSettings(settings);
|
||||||
|
document.setWarningCallback(warning -> log.warn("[Office模板渲染] 字体或排版警告,context={}, type={}, detail={}", context, warning.getWarningType(), warning.getDescription()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 签字url转换为poi的图片对象
|
* 签字url转换为poi的图片对象
|
||||||
*
|
*
|
||||||
@@ -77,13 +167,7 @@ public class SysOfficeTemplateUtil {
|
|||||||
public PictureRenderData createPictureRenderData(int width, int height, String url) {
|
public PictureRenderData createPictureRenderData(int width, int height, String url) {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = getFileBytesByUrl(url);
|
byte[] bytes = getFileBytesByUrl(url);
|
||||||
// if (StrUtil.isBlank(url)) {
|
log.info("[Office图片读取] 创建图片渲染数据,referenceLength={}, byteCount={}, width={}, height={}", StrUtil.nullToEmpty(url).length(), bytes == null ? null : bytes.length, width, height);
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// int startIndex = url.indexOf("id=") + "id=".length();
|
|
||||||
// String id = url.substring(startIndex);
|
|
||||||
// Sys_file sysFile = dao.fetch(Sys_file.class, id);
|
|
||||||
// byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
|
||||||
ByteArrayPictureRenderData pictureRenderData = new ByteArrayPictureRenderData(bytes, PictureType.PNG);
|
ByteArrayPictureRenderData pictureRenderData = new ByteArrayPictureRenderData(bytes, PictureType.PNG);
|
||||||
PictureStyle pictureStyle = new PictureStyle();
|
PictureStyle pictureStyle = new PictureStyle();
|
||||||
pictureStyle.setWidth(width);
|
pictureStyle.setWidth(width);
|
||||||
@@ -91,7 +175,7 @@ public class SysOfficeTemplateUtil {
|
|||||||
pictureRenderData.setPictureStyle(pictureStyle);
|
pictureRenderData.setPictureStyle(pictureStyle);
|
||||||
return pictureRenderData;
|
return pictureRenderData;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("文件转换PictureRenderData错误,文件路径:{},{}", url, e.getMessage());
|
log.error("[Office图片读取] 创建图片渲染数据失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,13 +224,20 @@ public class SysOfficeTemplateUtil {
|
|||||||
public byte[] getFileBytesByUrl(String url) {
|
public byte[] getFileBytesByUrl(String url) {
|
||||||
try {
|
try {
|
||||||
if (StrUtil.isBlank(url)) {
|
if (StrUtil.isBlank(url)) {
|
||||||
|
log.warn("[Office图片读取] 图片引用为空");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int startIndex = url.indexOf("id=") + "id=".length();
|
int startIndex = url.indexOf("id=") + "id=".length();
|
||||||
String id = url.substring(startIndex);
|
String id = url.substring(startIndex);
|
||||||
|
String logFileId = url.contains("id=") ? id : "未识别id参数";
|
||||||
|
log.info("[Office图片读取] 解析文件引用,fileId={}, hasIdParameter={}", logFileId, url.contains("id="));
|
||||||
Sys_file sysFile = dao.fetch(Sys_file.class, id);
|
Sys_file sysFile = dao.fetch(Sys_file.class, id);
|
||||||
return SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
log.info("[Office图片读取] 查询文件记录,fileId={}, found={}, bucket={}, storagePathPresent={}", logFileId, sysFile != null, sysFile == null ? null : sysFile.getBucket(), sysFile != null && StrUtil.isNotBlank(sysFile.getStoragePath()));
|
||||||
|
byte[] bytes = SysFileMinIoUtil.getFileBytes(sysFile.getBucket(), sysFile.getStoragePath());
|
||||||
|
log.info("[Office图片读取] 读取存储文件完成,fileId={}, byteCount={}", logFileId, bytes == null ? null : bytes.length);
|
||||||
|
return bytes;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
log.error("[Office图片读取] 读取图片失败,referenceLength={}", StrUtil.nullToEmpty(url).length(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ public class FlowRecipientUnitSchoolLeaderHandler implements AssignmentHandler {
|
|||||||
throw new BaseException("未找到申请记录。");
|
throw new BaseException("未找到申请记录。");
|
||||||
}
|
}
|
||||||
unitId = condolence.getHelpUnitId();
|
unitId = condolence.getHelpUnitId();
|
||||||
|
} else if ("TSWW".equals(processName)) {
|
||||||
|
com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence info = dao.fetch(
|
||||||
|
com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence.class, businessNo);
|
||||||
|
if (info == null) throw new BaseException("未找到申请记录。");
|
||||||
|
unitId = info.getHelpUnitId();
|
||||||
} else {
|
} else {
|
||||||
throw new BaseException("当前流程不支持获取受助人所在单位分管校领导。");
|
throw new BaseException("当前流程不支持获取受助人所在单位分管校领导。");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,80 @@
|
|||||||
package com.budwk.app.flow.listenter;
|
package com.budwk.app.flow.listenter;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.flow.constant.FlowConst;
|
||||||
import com.budwk.app.flow.engine.event.ProcessEvent;
|
import com.budwk.app.flow.engine.event.ProcessEvent;
|
||||||
import com.budwk.app.flow.engine.event.ProcessEventListener;
|
import com.budwk.app.flow.engine.event.ProcessEventListener;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||||
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
|
import com.budwk.app.flow.enums.ProcessEventTypeEnum;
|
||||||
import com.budwk.app.flow.service.FlowTaskMessageService;
|
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.difficulthelp.service.DifficultHelpCommonService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.json.Json;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
/** 普通节点、首次会签及转办任务统一从开始事件进入待办消息 service。 */
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程任务开始监听器
|
||||||
|
*/
|
||||||
@IocBean
|
@IocBean
|
||||||
|
@Slf4j
|
||||||
public class ProcessTaskStartEventListener implements ProcessEventListener {
|
public class ProcessTaskStartEventListener implements ProcessEventListener {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Dao dao;
|
private Dao dao;
|
||||||
@Inject
|
@Inject
|
||||||
private FlowTaskMessageService flowTaskMessageService;
|
private GlobalMessageSendService globalMessageSendService;
|
||||||
|
@Inject
|
||||||
|
private DifficultHelpCommonService difficultHelpCommonService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEvent(ProcessEvent event) {
|
public void onEvent(ProcessEvent event) {
|
||||||
if (event.getEventType() == ProcessEventTypeEnum.PROCESS_TASK_START) {
|
if (event.getEventType() == ProcessEventTypeEnum.PROCESS_TASK_START) {
|
||||||
ProcessTask task = dao.fetch(ProcessTask.class, event.getSourceId());
|
Long sourceId = event.getSourceId();
|
||||||
flowTaskMessageService.notifyTask(task, false);
|
ProcessTask task = dao.fetch(ProcessTask.class, sourceId);
|
||||||
|
if (task == null) return;
|
||||||
|
sendMessage(task);
|
||||||
|
// 节点及接收人判断集中在业务 service;通知失败不向流程提交接口抛出异常。
|
||||||
|
try {
|
||||||
|
difficultHelpCommonService.notifyOfficeApproval(task);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("困难帮扶企业微信待办通知异常,taskId={}", sourceId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void sendMessage(ProcessTask task) {
|
||||||
|
// 说明是流程开始 用户首次完成任务
|
||||||
|
if (task.getTaskParentId() == 0 && task.getTaskName().equals("startTask")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 节点名称
|
||||||
|
String taskDisplayName = task.getDisplayName();
|
||||||
|
// 实例名称
|
||||||
|
Long instanceId = task.getProcessInstanceId();
|
||||||
|
ProcessInstance instance = dao.fetch(ProcessInstance.class, instanceId);
|
||||||
|
String instanceName = Json.fromJson(NutMap.class, instance.getVariable()).getString(FlowConst.PROCESS_INSTANCE_NAME);
|
||||||
|
|
||||||
|
// 任务接收人
|
||||||
|
List<ProcessTaskActor> taskActors = dao.query(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
|
||||||
|
|
||||||
|
for (ProcessTaskActor taskActor : taskActors) {
|
||||||
|
// 模拟发送消息
|
||||||
|
String message = StrUtil.format("您有一条待办任务,实例:{},处理环节:{}", taskActor.getActorName(), instanceName, taskDisplayName);
|
||||||
|
log.info(message);
|
||||||
|
globalMessageSendService.sendMessage(taskDisplayName, message, 2, List.of(taskActor.getActorId()), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +0,0 @@
|
|||||||
package com.budwk.app.flow.service;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
|
||||||
import com.budwk.app.flow.constant.FlowConst;
|
|
||||||
import com.budwk.app.flow.entity.ProcessDefine;
|
|
||||||
import com.budwk.app.flow.entity.ProcessInstance;
|
|
||||||
import com.budwk.app.flow.entity.ProcessTask;
|
|
||||||
import com.budwk.app.flow.entity.ProcessTaskActor;
|
|
||||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
|
||||||
import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
|
||||||
import org.nutz.dao.Cnd;
|
|
||||||
import org.nutz.dao.Dao;
|
|
||||||
import org.nutz.ioc.aop.Aop;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/** WF 待办统一消息入口;站内消息、短信和企业微信沿用全局消息渠道。 */
|
|
||||||
@IocBean
|
|
||||||
@Slf4j
|
|
||||||
public class FlowTaskMessageService {
|
|
||||||
private static final String HOME = "/platform/home";
|
|
||||||
private static final Set<String> TASK_PARAMS = Set.of("taskId", "bizId", "taskKey", "tab");
|
|
||||||
@Inject
|
|
||||||
private Dao dao;
|
|
||||||
@Inject
|
|
||||||
private GlobalMessageSendService globalMessageSendService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* task 为参与人已落库的 WF 任务;includeStartTask 仅驳回重建时传 true,
|
|
||||||
* 使退回申请人的 startTask 也收到通知,首次提交的申请节点不通知本人。
|
|
||||||
* 无返回值:仅通知进行中的任务,异常记录 taskId,不中断业务审核。
|
|
||||||
* config 的 wfTaskId 标识流程通知,wfLoginNames 为办理人的 loginname,
|
|
||||||
* wxWorkLink 为卡片地址;微信策略据此切换到官方企业微信接口。
|
|
||||||
*/
|
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
|
||||||
public void notifyTask(ProcessTask task, boolean includeStartTask) {
|
|
||||||
if (task == null || task.getId() == null || task.getProcessInstanceId() == null
|
|
||||||
|| !ProcessTaskStateEnum.DOING.getCode().equals(task.getTaskState())) return;
|
|
||||||
if (!includeStartTask && "startTask".equals(task.getTaskName())
|
|
||||||
&& (task.getTaskParentId() == null || task.getTaskParentId() == 0L)) return;
|
|
||||||
try {
|
|
||||||
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
|
|
||||||
if (instance == null) {
|
|
||||||
log.warn("WF 待办通知跳过:实例不存在,taskId={}", task.getId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ProcessDefine define = instance.getProcessDefineId() == null ? null
|
|
||||||
: dao.fetch(ProcessDefine.class, instance.getProcessDefineId());
|
|
||||||
List<ProcessTaskActor> actors = dao.query(ProcessTaskActor.class,
|
|
||||||
Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
|
|
||||||
List<String> receiverIds = actors.stream().map(ProcessTaskActor::getActorId)
|
|
||||||
.filter(StrUtil::isNotBlank).distinct().toList();
|
|
||||||
if (receiverIds.isEmpty()) {
|
|
||||||
log.warn("WF 待办通知跳过:任务没有实际办理人,taskId={}", task.getId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 只用实际参与人的账号,不按角色扩大范围,不以内部用户 ID 代替企业微信 userid。
|
|
||||||
List<String> loginNames = actors.stream().filter(actor -> StrUtil.isNotBlank(actor.getActorId()))
|
|
||||||
.map(ProcessTaskActor::getActorAccount).filter(StrUtil::isNotBlank)
|
|
||||||
.map(String::trim).distinct().toList();
|
|
||||||
if (actors.stream().anyMatch(actor -> StrUtil.isBlank(actor.getActorAccount()))) {
|
|
||||||
log.warn("WF 待办存在未绑定 loginname 的办理人,taskId={}", task.getId());
|
|
||||||
}
|
|
||||||
String instanceName = define == null ? "流程审批" : StrUtil.blankToDefault(define.getDisplayName(), "流程审批");
|
|
||||||
if (StrUtil.isNotBlank(instance.getVariable())) {
|
|
||||||
try {
|
|
||||||
instanceName = StrUtil.blankToDefault(JSONUtil.parseObj(instance.getVariable())
|
|
||||||
.getStr(FlowConst.PROCESS_INSTANCE_NAME), instanceName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("WF 实例名称解析失败,使用流程定义名称,taskId={}", task.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String nodeName = StrUtil.blankToDefault(task.getDisplayName(), "待办审核");
|
|
||||||
String content = "您有一条待办任务,实例:" + instanceName + ",处理环节:" + nodeName;
|
|
||||||
JSONObject config = JSONUtil.createObj().set("wfTaskId", task.getId())
|
|
||||||
.set("wfLoginNames", loginNames).set("wxWorkLink", buildLink(task, instance, define));
|
|
||||||
// 系统发送身份兼容定时推进等没有当前登录会话的流程入口。
|
|
||||||
globalMessageSendService.sendSystemMessage(nodeName, content, 2, receiverIds, config);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("WF 待办通知异常,taskId={}", task.getId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 优先节点手机表单;缺失或非法时回首页。保留原查询参数和锚点,替换过期任务参数。 */
|
|
||||||
private String buildLink(ProcessTask task, ProcessInstance instance, ProcessDefine define) {
|
|
||||||
String form = task.getH5FormKey();
|
|
||||||
// KNBF 历史定义中的办公室地址过时,沿用已经验证的实际审核入口。
|
|
||||||
if (define != null && "KNBF".equals(define.getName())
|
|
||||||
&& "36ebafda-44c2-4bd3-bd7f-10839a575a0d".equals(task.getTaskName())) {
|
|
||||||
form = "/platform/difficultHelp/branchUnionApproval/h5";
|
|
||||||
}
|
|
||||||
if (StrUtil.isBlank(form) || "null".equalsIgnoreCase(form.trim())
|
|
||||||
|| StrUtil.isBlank(instance.getBusinessNo()) || StrUtil.isBlank(task.getTaskName())) return HOME;
|
|
||||||
try {
|
|
||||||
form = form.trim();
|
|
||||||
URI uri = URI.create(form);
|
|
||||||
if (uri.getUserInfo() != null || (uri.isAbsolute()
|
|
||||||
? !("https".equalsIgnoreCase(uri.getScheme()) || "http".equalsIgnoreCase(uri.getScheme()))
|
|
||||||
|| uri.getHost() == null
|
|
||||||
: !form.startsWith("/") || uri.getRawAuthority() != null)) return HOME;
|
|
||||||
List<String> params = new ArrayList<>();
|
|
||||||
if (StrUtil.isNotBlank(uri.getRawQuery())) {
|
|
||||||
for (String param : uri.getRawQuery().split("&")) {
|
|
||||||
String key = URLDecoder.decode(param.split("=", 2)[0], StandardCharsets.UTF_8);
|
|
||||||
if (!TASK_PARAMS.contains(key)) params.add(param);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.add("taskId=" + task.getId());
|
|
||||||
params.add("bizId=" + URLEncoder.encode(instance.getBusinessNo(), StandardCharsets.UTF_8));
|
|
||||||
params.add("taskKey=" + URLEncoder.encode(task.getTaskName(), StandardCharsets.UTF_8));
|
|
||||||
params.add("tab=todo");
|
|
||||||
String base = form.split("[?#]", 2)[0];
|
|
||||||
return base + "?" + String.join("&", params)
|
|
||||||
+ (uri.getRawFragment() == null ? "" : "#" + uri.getRawFragment());
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
log.warn("WF 手机表单地址无效,卡片回退首页,taskId={}", task.getId());
|
|
||||||
return HOME;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,6 @@ import com.budwk.app.flow.entity.ProcessInstance;
|
|||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
import com.budwk.app.flow.entity.ProcessTaskActor;
|
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||||
import com.budwk.app.flow.enums.*;
|
import com.budwk.app.flow.enums.*;
|
||||||
import com.budwk.app.flow.service.FlowTaskMessageService;
|
|
||||||
import com.budwk.app.flow.service.ProcessDefineService;
|
import com.budwk.app.flow.service.ProcessDefineService;
|
||||||
import com.budwk.app.flow.service.ProcessInstanceService;
|
import com.budwk.app.flow.service.ProcessInstanceService;
|
||||||
import com.budwk.app.flow.service.ProcessTaskService;
|
import com.budwk.app.flow.service.ProcessTaskService;
|
||||||
@@ -61,9 +60,6 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
|||||||
@Inject
|
@Inject
|
||||||
private SchoolOaTodoService schoolOaTodoService;
|
private SchoolOaTodoService schoolOaTodoService;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private FlowTaskMessageService flowTaskMessageService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean save(ProcessTask param) {
|
public boolean save(ProcessTask param) {
|
||||||
param.setId(null);
|
param.setId(null);
|
||||||
@@ -296,8 +292,6 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
|||||||
addTaskActor(clone.getId(), CollectionUtil.newArrayList(actor));
|
addTaskActor(clone.getId(), CollectionUtil.newArrayList(actor));
|
||||||
// 并行加签绕过普通节点创建入口,需要为新增的个人任务同步待办。
|
// 并行加签绕过普通节点创建入口,需要为新增的个人任务同步待办。
|
||||||
schoolOaTodoService.createTodo(clone);
|
schoolOaTodoService.createTodo(clone);
|
||||||
// 并行加签不经过 CreateTaskHandler,只为本次新增任务通知一次。
|
|
||||||
flowTaskMessageService.notifyTask(clone, false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -368,8 +362,6 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
|||||||
addTaskActor(task.getId(), CollectionUtil.newArrayList(task.getOperator()));
|
addTaskActor(task.getId(), CollectionUtil.newArrayList(task.getOperator()));
|
||||||
// 驳回创建了新的任务 ID,按新任务推送,避免复用历史待办。
|
// 驳回创建了新的任务 ID,按新任务推送,避免复用历史待办。
|
||||||
schoolOaTodoService.createTodo(task);
|
schoolOaTodoService.createTodo(task);
|
||||||
// 驳回重建不发布开始事件;退回申请节点时也通知申请人重新办理。
|
|
||||||
flowTaskMessageService.notifyTask(task, true);
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,12 +441,6 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
|||||||
ProcessInstanceService processInstanceService = ServiceContext.find(ProcessInstanceService.class);
|
ProcessInstanceService processInstanceService = ServiceContext.find(ProcessInstanceService.class);
|
||||||
// 更新会签变量到流程实例参数中
|
// 更新会签变量到流程实例参数中
|
||||||
processInstanceService.updateCountersignVariable(taskModel, execution, taskActors);
|
processInstanceService.updateCountersignVariable(taskModel, execution, taskActors);
|
||||||
// 串行会签后续办理人由 CountersignHandler 直接创建,不经过开始事件;首次会签仍由监听器通知。
|
|
||||||
String counterPrefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + taskModel.getName() + "_";
|
|
||||||
if (CountersignTypeEnum.SEQUENTIAL.equals(taskModel.getCountersignType())
|
|
||||||
&& execution.getArgs().get(counterPrefix + FlowConst.LOOP_COUNTER, -1) >= 0) {
|
|
||||||
processTaskList.forEach(task -> flowTaskMessageService.notifyTask(task, false));
|
|
||||||
}
|
|
||||||
return processTaskList;
|
return processTaskList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,12 +84,10 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
|||||||
task.getId(), task.getProcessInstanceId(), task.getTaskState());
|
task.getId(), task.getProcessInstanceId(), task.getTaskState());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 系统参数优先于文件配置,只有明确为 true 才启用;未配置不访问数据库或 OA。 */
|
||||||
* OA 待办接口联调尚未完成,暂时在代码中固定关闭,避免远端异常阻断内部 WF 流转。
|
|
||||||
* 不受 AppSchoolOa 或 enabled 配置影响;恢复对接时需显式恢复配置开关逻辑。
|
|
||||||
*/
|
|
||||||
private boolean isEnabled() {
|
private boolean isEnabled() {
|
||||||
return false;
|
Object enabled = Globals.MyConfig.get("AppSchoolOa");
|
||||||
|
return Boolean.parseBoolean(enabled == null ? conf.get(PREFIX + "enabled", "false") : enabled.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requireTask(ProcessTask task) {
|
private void requireTask(ProcessTask task) {
|
||||||
|
|||||||
+1
-2
@@ -193,8 +193,7 @@ public class GlobalMessageSendService {
|
|||||||
try {
|
try {
|
||||||
strategy.send(request.getTitle(), request.getContent(), request.getType(),
|
strategy.send(request.getTitle(), request.getContent(), request.getType(),
|
||||||
request.getReceiverIds(), request.getConfig());
|
request.getReceiverIds(), request.getConfig());
|
||||||
// 策略可能因开关关闭而跳过,实际发送结果由策略日志记录。
|
log.info("异步发送消息成功,渠道:{}", strategy.getChannel().getValue());
|
||||||
log.info("异步消息策略执行完成,渠道:{}", strategy.getChannel().getValue());
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("异步发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e);
|
log.error("异步发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|||||||
-72
@@ -1,23 +1,16 @@
|
|||||||
package com.budwk.app.zhgh.dayofficework.message.strategy.impl;
|
package com.budwk.app.zhgh.dayofficework.message.strategy.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.hutool.http.HtmlUtil;
|
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.budwk.app.base.sms.SmsService;
|
import com.budwk.app.base.sms.SmsService;
|
||||||
import com.budwk.app.base.wxwork.WxWorkMessageService;
|
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import com.budwk.app.sys.models.Sys_user;
|
||||||
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel;
|
||||||
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
|
import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.ioc.aop.Aop;
|
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.lang.util.NutMap;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,8 +24,6 @@ public class WechatMessageSendStrategy implements GlobalMessageSendStrategy {
|
|||||||
private Dao dao;
|
private Dao dao;
|
||||||
@Inject
|
@Inject
|
||||||
private SmsService smsService;
|
private SmsService smsService;
|
||||||
@Inject
|
|
||||||
private WxWorkMessageService wxWorkMessageService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlobalMessageChannel getChannel() {
|
public GlobalMessageChannel getChannel() {
|
||||||
@@ -45,13 +36,7 @@ public class WechatMessageSendStrategy implements GlobalMessageSendStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
|
||||||
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
|
public void send(String title, String content, Integer type, List<String> receiverIds, JSONObject config) {
|
||||||
// WF 的接收账号已在任务事务内取得,异步线程不再反查尚未提交的任务数据。
|
|
||||||
if (config != null && config.getLong("wfTaskId") != null) {
|
|
||||||
sendFlowCard(title, content, config);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
log.info("开始发送微信消息,标题:{},接收人数量:{}", title, receiverIds.size());
|
log.info("开始发送微信消息,标题:{},接收人数量:{}", title, receiverIds.size());
|
||||||
|
|
||||||
@@ -67,12 +52,7 @@ public class WechatMessageSendStrategy implements GlobalMessageSendStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Aop(TransAop.READ_COMMITTED)
|
|
||||||
public void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config) {
|
public void sendByLoginName(String title, String content, Integer type, List<String> receiverLoginNames, JSONObject config) {
|
||||||
if (config != null && config.getLong("wfTaskId") != null) {
|
|
||||||
sendFlowCard(title, content, config);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
log.info("开始发送微信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size());
|
log.info("开始发送微信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size());
|
||||||
|
|
||||||
@@ -87,58 +67,6 @@ public class WechatMessageSendStrategy implements GlobalMessageSendStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* WF 专用分支:wfTaskId 为任务ID,wfLoginNames 为实际办理人的 loginname 列表,
|
|
||||||
* wxWorkLink 为非空手机入口。无返回值;关闭开关或无账号时跳过,失败抛给全局异步日志处理,
|
|
||||||
* 不回退旧微信通道,避免双发。非流程消息继续沿用原有通讯平台。
|
|
||||||
*/
|
|
||||||
private void sendFlowCard(String title, String content, JSONObject config) {
|
|
||||||
Long taskId = config.getLong("wfTaskId");
|
|
||||||
List<String> loginNames = config.getJSONArray("wfLoginNames") == null ? List.of()
|
|
||||||
: config.getJSONArray("wfLoginNames").toList(String.class);
|
|
||||||
if (loginNames.isEmpty()) {
|
|
||||||
log.warn("WF 企业微信卡片跳过:办理人 loginname 为空,taskId={}", taskId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String link = StrUtil.blankToDefault(config.getStr("wxWorkLink"), "/platform/home");
|
|
||||||
NutMap result;
|
|
||||||
try {
|
|
||||||
result = wxWorkMessageService.massSend(loginNames, cardText(title, 128, false),
|
|
||||||
cardText(content, 512, true), link);
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
// 异步线程已脱离任务调用栈,保留任务 ID 便于从错误日志定位具体待办。
|
|
||||||
throw new IllegalStateException("WF 企业微信卡片接口异常,taskId=" + taskId, e);
|
|
||||||
}
|
|
||||||
if (result != null && result.getBoolean("skipped", false)) {
|
|
||||||
log.info("WF 企业微信卡片跳过:消息开关关闭,taskId={}", taskId);
|
|
||||||
} else if (result != null && result.getBoolean("success", false)) {
|
|
||||||
log.info("WF 企业微信卡片发送成功,taskId={},接收账号数={}", taskId, loginNames.size());
|
|
||||||
} else {
|
|
||||||
log.error("WF 企业微信卡片发送失败或部分失败,taskId={},result={}", taskId, result);
|
|
||||||
throw new IllegalStateException("WF 企业微信卡片发送失败或部分失败,taskId=" + taskId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 卡片有 UTF-8 字节上限;按 Unicode 码点缩短摘要,并计入正文 HTML 转义后的长度。 */
|
|
||||||
private String cardText(String value, int limit, boolean description) {
|
|
||||||
String text = HtmlUtil.unescape(HtmlUtil.cleanHtmlTag(StrUtil.blankToDefault(value, "流程待办")))
|
|
||||||
.replace('\r', ' ').replace('\n', ' ');
|
|
||||||
if (text.isBlank()) text = "流程待办";
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
int bytes = 0;
|
|
||||||
for (int offset = 0; offset < text.length();) {
|
|
||||||
int codePoint = text.codePointAt(offset);
|
|
||||||
String character = new String(Character.toChars(codePoint));
|
|
||||||
int size = (description ? HtmlUtil.escape(character) : character).getBytes(StandardCharsets.UTF_8).length;
|
|
||||||
// 留出省略号的三个 UTF-8 字节,避免长流程名称使整条通知发送失败。
|
|
||||||
if (bytes + size > limit - 3) return result.append("…").toString();
|
|
||||||
result.append(character);
|
|
||||||
bytes += size;
|
|
||||||
offset += Character.charCount(codePoint);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送微信文本消息。
|
* 发送微信文本消息。
|
||||||
* 接收人来自全局消息服务传入的用户ID或登录名,方法内部转换为 Sys_user 后取工号发送;
|
* 接收人来自全局消息服务传入的用户ID或登录名,方法内部转换为 Sys_user 后取工号发送;
|
||||||
|
|||||||
+32
-26
@@ -28,10 +28,10 @@ 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.model.Condolence;
|
||||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType;
|
import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType;
|
||||||
import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceService;
|
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.PictureRenderData;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
@@ -47,8 +47,6 @@ import org.nutz.mvc.annotation.Ok;
|
|||||||
import org.nutz.mvc.annotation.Param;
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -59,6 +57,7 @@ import java.util.List;
|
|||||||
* @Version 1.0
|
* @Version 1.0
|
||||||
* @Description TODO
|
* @Description TODO
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/condolence/mine")
|
@At("/platform/condolence/mine")
|
||||||
@Api("职工慰问我的")
|
@Api("职工慰问我的")
|
||||||
@@ -157,6 +156,7 @@ public class CondolenceMineController {
|
|||||||
@ApiOperation("导出职工慰问申请表")
|
@ApiOperation("导出职工慰问申请表")
|
||||||
@SaCheckPermission("condolence.mine")
|
@SaCheckPermission("condolence.mine")
|
||||||
public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception {
|
public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception {
|
||||||
|
log.info("[职工慰问导出] 开始,applyId={}, userId={}, format={}", id, SecurityUtil.getUserId(), Boolean.TRUE.equals(print) ? "PDF" : "Word");
|
||||||
Condolence condolence = condolenceService.fetch(id);
|
Condolence condolence = condolenceService.fetch(id);
|
||||||
if (condolence == null) throw new BaseException("该条记录不存在");
|
if (condolence == null) throw new BaseException("该条记录不存在");
|
||||||
if (!SecurityUtil.getUserId().equals(condolence.getCreatedBy())) {
|
if (!SecurityUtil.getUserId().equals(condolence.getCreatedBy())) {
|
||||||
@@ -167,36 +167,32 @@ public class CondolenceMineController {
|
|||||||
if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) {
|
if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) {
|
||||||
throw new BaseException("只能导出已完成的申请");
|
throw new BaseException("只能导出已完成的申请");
|
||||||
}
|
}
|
||||||
|
log.info("[职工慰问导出] 流程已完成,applyId={}, instanceId={}, state={}, applicantSignPresent={}", id, instance.getId(), instance.getState(), StrUtil.isNotBlank(condolence.getSignature()));
|
||||||
NutMap docData = Lang.obj2nutmap(condolence);
|
NutMap docData = Lang.obj2nutmap(condolence);
|
||||||
docData.put("payUserName", StrUtil.nullToEmpty(condolence.getBankUserName()));
|
docData.put("payUserName", StrUtil.nullToEmpty(condolence.getBankUserName()));
|
||||||
CondolenceType type = condolenceService.dao().fetch(CondolenceType.class, condolence.getType());
|
CondolenceType type = condolenceService.dao().fetch(CondolenceType.class, condolence.getType());
|
||||||
docData.put("typeName", type == null ? "" : type.getName());
|
docData.put("typeName", type == null ? "" : type.getName());
|
||||||
docData.put("signature", "");
|
docData.put("signature", null);
|
||||||
if (StrUtil.isNotBlank(condolence.getSignature())) {
|
if (StrUtil.isNotBlank(condolence.getSignature())) {
|
||||||
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, condolence.getSignature());
|
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, condolence.getSignature());
|
||||||
if (signature == null) throw new BaseException("申请人签字图片读取失败");
|
if (signature == null) throw new BaseException("申请人签字图片读取失败");
|
||||||
docData.put("signature", signature);
|
docData.put("signature", signature);
|
||||||
}
|
}
|
||||||
fillApplyApprovals(docData, instance);
|
fillApplyApprovals(docData, instance);
|
||||||
|
for (String field : List.of("signature", "firstApprovalSign", "secondApprovalSign", "thirdApprovalSign", "fourthApprovalSign")) {
|
||||||
|
Object value = docData.get(field);
|
||||||
|
log.info("[职工慰问导出] 渲染前图片字段,applyId={}, instanceId={}, field={}, valueType={}", id, instance.getId(), field, value == null ? "null" : value.getClass().getName());
|
||||||
|
}
|
||||||
String fileName = "重庆工贸职业技术学院职工慰问申请表_" + StrUtil.nullToEmpty(condolence.getHelpUserName());
|
String fileName = "重庆工贸职业技术学院职工慰问申请表_" + StrUtil.nullToEmpty(condolence.getHelpUserName());
|
||||||
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc");
|
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc")) {
|
||||||
ByteArrayOutputStream templateOutput = new ByteArrayOutputStream();
|
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
|
||||||
if (input == null) throw new BaseException("职工慰问申请表模板不存在");
|
if (input == null) throw new BaseException("职工慰问申请表模板不存在");
|
||||||
com.aspose.words.Document document = new com.aspose.words.Document(input);
|
boolean pdf = Boolean.TRUE.equals(print);
|
||||||
document.save(templateOutput, com.aspose.words.SaveFormat.DOCX);
|
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, null, pdf, "condolence:" + id);
|
||||||
try (ByteArrayInputStream templateInput = new ByteArrayInputStream(templateOutput.toByteArray())) {
|
log.info("[职工慰问导出] 渲染完成,applyId={}, format={}, outputBytes={}", id, pdf ? "PDF" : "Word", bytes.length);
|
||||||
XWPFTemplate.compile(templateInput).render(docData).writeAndClose(output);
|
CommonDownloadUtil.download(fileName + (pdf ? ".pdf" : ".docx"), bytes, response);
|
||||||
}
|
} catch (Exception e) {
|
||||||
if (Boolean.TRUE.equals(print)) {
|
log.error("[职工慰问导出] 模板渲染或文件输出失败,applyId={}, instanceId={}, format={}", id, instance.getId(), Boolean.TRUE.equals(print) ? "PDF" : "Word", e);
|
||||||
try (ByteArrayInputStream wordInput = new ByteArrayInputStream(output.toByteArray());
|
throw e;
|
||||||
ByteArrayOutputStream pdfOutput = new ByteArrayOutputStream()) {
|
|
||||||
new com.aspose.words.Document(wordInput).save(pdfOutput, com.aspose.words.SaveFormat.PDF);
|
|
||||||
CommonDownloadUtil.download(fileName + ".pdf", pdfOutput.toByteArray(), response);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CommonDownloadUtil.download(fileName + ".docx", output.toByteArray(), response);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,29 +202,39 @@ public class CondolenceMineController {
|
|||||||
String[] fields = {"firstApproval", "secondApproval", "thirdApproval", "fourthApproval"};
|
String[] fields = {"firstApproval", "secondApproval", "thirdApproval", "fourthApproval"};
|
||||||
List<String> suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day");
|
List<String> suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day");
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
for (String suffix : suffixes) docData.put(field + suffix, "");
|
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
}
|
}
|
||||||
List<ProcessTask> tasks = condolenceService.dao().query(ProcessTask.class,
|
List<ProcessTask> tasks = condolenceService.dao().query(ProcessTask.class,
|
||||||
Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
||||||
|
log.info("[职工慰问导出] 查询审批记录,applyId={}, instanceId={}, taskCount={}, expectedTaskKeys={}", instance.getBusinessNo(), instance.getId(), tasks.size(), List.of(taskKeys));
|
||||||
for (ProcessTask task : tasks) {
|
for (ProcessTask task : tasks) {
|
||||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
||||||
if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
log.info("[职工慰问导出] 审批记录,instanceId={}, taskId={}, taskKey={}, displayName={}, state={}, finishTime={}, isFirstTaskNode={}, matchedApproval={}", instance.getId(), task.getId(), task.getTaskName(), task.getDisplayName(), task.getTaskState(), task.getFinishTime(), taskVO.getExt() == null ? null : taskVO.getExt().get("isFirstTaskNode"), List.of(taskKeys).contains(task.getTaskName()));
|
||||||
|
if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName())
|
||||||
|
&& taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||||
|
log.info("[职工慰问导出] 申请节点重置本轮审批字段,instanceId={}, taskId={}, taskKey={}", instance.getId(), task.getId(), task.getTaskName());
|
||||||
// 重新申请后,仅导出本轮审批记录。
|
// 重新申请后,仅导出本轮审批记录。
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
for (String suffix : suffixes) docData.put(field + suffix, "");
|
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < taskKeys.length; i++) {
|
for (int i = 0; i < taskKeys.length; i++) {
|
||||||
if (!taskKeys[i].equals(task.getTaskName())) continue;
|
if (!taskKeys[i].equals(task.getTaskName())) continue;
|
||||||
for (String suffix : suffixes) docData.put(fields[i] + suffix, "");
|
for (String suffix : suffixes) docData.put(fields[i] + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) continue;
|
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) {
|
||||||
|
log.info("[职工慰问导出] 跳过未完成审批,instanceId={}, taskId={}, field={}, state={}", instance.getId(), task.getId(), fields[i], task.getTaskState());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData();
|
Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData();
|
||||||
|
log.info("[职工慰问导出] 读取审批表单,instanceId={}, taskId={}, field={}, formKeys={}, signPresent={}, signReferenceLength={}", instance.getId(), task.getId(), fields[i], data.keySet(), StrUtil.isNotBlank(data.getStr("sign")), StrUtil.nullToEmpty(data.getStr("sign")).length());
|
||||||
|
if (StrUtil.isBlank(data.getStr("sign"))) log.warn("[职工慰问导出] 已完成审批缺少签名字段,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i]);
|
||||||
docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion")));
|
docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion")));
|
||||||
if (StrUtil.isNotBlank(data.getStr("sign"))) {
|
if (StrUtil.isNotBlank(data.getStr("sign"))) {
|
||||||
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign"));
|
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign"));
|
||||||
if (signature == null) throw new BaseException("审批签字图片读取失败");
|
if (signature == null) throw new BaseException("审批签字图片读取失败");
|
||||||
docData.put(fields[i] + "Sign", signature);
|
docData.put(fields[i] + "Sign", signature);
|
||||||
|
log.info("[职工慰问导出] 审批签名填充完成,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i] + "Sign");
|
||||||
}
|
}
|
||||||
docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy"));
|
docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy"));
|
||||||
docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));
|
docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));
|
||||||
|
|||||||
+25
-12
@@ -6,14 +6,13 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
|||||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.constant.RoleConstant;
|
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.param.PageForm;
|
import com.budwk.app.base.param.PageForm;
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||||
import com.budwk.app.base.utils.PageUtil;
|
import com.budwk.app.base.utils.PageUtil;
|
||||||
import com.budwk.app.flow.entity.ProcessInstance;
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||||
import com.budwk.app.sys.param.SysMsgSummaryPageForm;
|
import com.budwk.app.sys.param.SysMsgSummaryPageForm;
|
||||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
@@ -94,10 +93,12 @@ public class CondolenceReadController {
|
|||||||
$condition
|
$condition
|
||||||
""");
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||||
cnd.andEX("info.type", "=", type);
|
cnd.andEX("info.type", "=", type);
|
||||||
cnd.andEX("YEAR(info.createTime)", "=", year);
|
cnd.andEX("YEAR(info.createTime)", "=", year);
|
||||||
cnd.andEX("info.applyUnionId", "=", unionId);
|
cnd.andEX("info.applyUnionId", "=", unionId);
|
||||||
cnd.andEX("info.applyUnitId", "=", unitId);
|
cnd.andEX("info.applyUnitId", "=", unitId);
|
||||||
|
applyReadScope(cnd, "info");
|
||||||
|
|
||||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
@@ -106,9 +107,6 @@ public class CondolenceReadController {
|
|||||||
cnd.and(seg);
|
cnd.and(seg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CHAIRMAN.name())) {
|
|
||||||
cnd.and("info.applyUnionId", "=", SecurityUtil.getUnionId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||||
cnd.desc("info.createTime");
|
cnd.desc("info.createTime");
|
||||||
@@ -142,20 +140,18 @@ public class CondolenceReadController {
|
|||||||
$condition
|
$condition
|
||||||
""");
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
cnd.and(ProcessInstance::getState, "=", ProcessTaskStateEnum.FINISHED.getCode());
|
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||||
cnd.andEX("con.type", "=", type);
|
cnd.andEX("con.type", "=", type);
|
||||||
cnd.andEX("YEAR(info.createTime)", "=", year);
|
cnd.andEX("YEAR(con.createTime)", "=", year);
|
||||||
cnd.andEX("con.applyUnionId", "=", unionId);
|
cnd.andEX("con.applyUnionId", "=", unionId);
|
||||||
cnd.andEX("con.applyUnitId", "=", unitId);
|
cnd.andEX("con.applyUnitId", "=", unitId);
|
||||||
|
applyReadScope(cnd, "con");
|
||||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
seg.or("info.helpUserName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
seg.or("con.helpUserName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
seg.or("info.helpLoginName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
seg.or("con.helpLoginName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
cnd.and(seg);
|
cnd.and(seg);
|
||||||
}
|
}
|
||||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CHAIRMAN.name())) {
|
|
||||||
cnd.and("con.applyUnionId", "=", SecurityUtil.getUnionId());
|
|
||||||
}
|
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
List<NutMap> list = condolenceService.listMap(sql);
|
List<NutMap> list = condolenceService.listMap(sql);
|
||||||
|
|
||||||
@@ -174,4 +170,21 @@ public class CondolenceReadController {
|
|||||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
|
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
|
||||||
CommonDownloadUtil.download("申报人汇总.xlsx", workbook, response);
|
CommonDownloadUtil.download("申报人汇总.xlsx", workbook, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyReadScope(Cnd cnd, String alias) {
|
||||||
|
if (AuthUtil.hasPermission("all_school")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (AuthUtil.hasPermission("branch_union")) {
|
||||||
|
String unionId = SecurityUtil.getUnionId();
|
||||||
|
if (StrUtil.isNotBlank(unionId)) {
|
||||||
|
cnd.and(alias + ".applyUnionId", "=", unionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (AuthUtil.hasPermission("self")) {
|
||||||
|
cnd.and(alias + ".createdBy", "=", SecurityUtil.getUserId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cnd.and("1", "=", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-8
@@ -43,9 +43,9 @@ public class DifficultHelpApprovalController {
|
|||||||
}
|
}
|
||||||
ProcessTask task = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
ProcessTask task = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||||
if (task == null) throw new BaseException("审批任务不存在");
|
if (task == null) throw new BaseException("审批任务不存在");
|
||||||
boolean amountApproval = "36ebafda-44c2-4bd3-bd7f-10839a575a0d".equals(task.getTaskName())
|
boolean amountApproval = "715ece82-4ae3-433c-ad18-ed875f45d1e3".equals(task.getTaskName());
|
||||||
|| "715ece82-4ae3-433c-ad18-ed875f45d1e3".equals(task.getTaskName());
|
if (!amountApproval && !"36ebafda-44c2-4bd3-bd7f-10839a575a0d".equals(task.getTaskName())
|
||||||
if (!amountApproval && !"e405f96c-5fc0-4f63-b323-e69dfe853253".equals(task.getTaskName())) {
|
&& !"e405f96c-5fc0-4f63-b323-e69dfe853253".equals(task.getTaskName())) {
|
||||||
throw new BaseException("当前任务不是困难帮扶审批任务");
|
throw new BaseException("当前任务不是困难帮扶审批任务");
|
||||||
}
|
}
|
||||||
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
|
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
|
||||||
@@ -54,20 +54,23 @@ public class DifficultHelpApprovalController {
|
|||||||
if (StrUtil.isBlank(args.getStr("tf_sign"))) throw new BaseException("请完成审批签字");
|
if (StrUtil.isBlank(args.getStr("tf_sign"))) throw new BaseException("请完成审批签字");
|
||||||
if (StrUtil.isBlank(args.getStr("tf_opinion"))) throw new BaseException("请填写审批意见");
|
if (StrUtil.isBlank(args.getStr("tf_opinion"))) throw new BaseException("请填写审批意见");
|
||||||
|
|
||||||
String level = args.getStr("level");
|
args.remove("level");
|
||||||
|
args.remove("tf_level");
|
||||||
Double money = amountApproval ? args.getDouble("money") : null;
|
Double money = amountApproval ? args.getDouble("money") : null;
|
||||||
if (amountApproval) {
|
if (amountApproval) {
|
||||||
if (StrUtil.isBlank(level) || money == null || !Double.isFinite(money) || money < 0) {
|
if (money == null || !Double.isFinite(money) || money < 0) {
|
||||||
throw new BaseException("请填写完整的级别和帮扶金额");
|
throw new BaseException("请填写有效的帮扶金额");
|
||||||
}
|
}
|
||||||
args.put("tf_level", level);
|
|
||||||
args.put("tf_money", money);
|
args.put("tf_money", money);
|
||||||
|
} else {
|
||||||
|
args.remove("money");
|
||||||
|
args.remove("tf_money");
|
||||||
}
|
}
|
||||||
// 参与者权限由流程引擎校验,业务入口不接受客户端指定管理员代办。
|
// 参与者权限由流程引擎校验,业务入口不接受客户端指定管理员代办。
|
||||||
args.remove(FlowConst.EXT_ENABLE_OPERATOR);
|
args.remove(FlowConst.EXT_ENABLE_OPERATOR);
|
||||||
flowCommonService.executeTask(args);
|
flowCommonService.executeTask(args);
|
||||||
if (amountApproval && Integer.valueOf(ProcessSubmitTypeEnum.AGREE.getCode()).equals(args.getInt(FlowConst.SUBMIT_TYPE))) {
|
if (amountApproval && Integer.valueOf(ProcessSubmitTypeEnum.AGREE.getCode()).equals(args.getInt(FlowConst.SUBMIT_TYPE))) {
|
||||||
dao.update(DifficultHelpInfo.class, Chain.make("level", level).add("money", money), Cnd.where("id", "=", info.getId()));
|
dao.update(DifficultHelpInfo.class, Chain.make("money", money), Cnd.where("id", "=", info.getId()));
|
||||||
}
|
}
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
package com.budwk.app.zhgh.staffbenefit.difficulthelp.controller;
|
package com.budwk.app.zhgh.staffbenefit.difficulthelp.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.budwk.app.base.annotation.SLog;
|
import com.budwk.app.base.annotation.SLog;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
@@ -137,7 +138,7 @@ public class DifficultHelpMineController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@ApiModelProperty("获取困难补助申请")
|
@ApiModelProperty("获取困难补助申请")
|
||||||
@SaCheckPermission("difficultHelp.mine")
|
@SaCheckPermission(value = {"difficultHelp.mine", "difficultHelp.reading"}, mode = SaMode.OR)
|
||||||
public Result findOne(String id) {
|
public Result findOne(String id) {
|
||||||
DifficultHelpInfo helpInfo = dao.fetch(DifficultHelpInfo.class, id);
|
DifficultHelpInfo helpInfo = dao.fetch(DifficultHelpInfo.class, id);
|
||||||
return Result.success().addData(helpInfo);
|
return Result.success().addData(helpInfo);
|
||||||
|
|||||||
+21
-42
@@ -9,7 +9,6 @@ import cn.dev33.satoken.annotation.SaCheckLogin;
|
|||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.io.IoUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.excel.EasyExcel;
|
import com.alibaba.excel.EasyExcel;
|
||||||
@@ -18,7 +17,6 @@ import com.budwk.app.base.page.Pagination;
|
|||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||||
import com.budwk.app.base.utils.MoneyUtil;
|
import com.budwk.app.base.utils.MoneyUtil;
|
||||||
import com.budwk.app.base.utils.OfficePlusUtil;
|
|
||||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||||
import com.budwk.app.flow.engine.FlowEngine;
|
import com.budwk.app.flow.engine.FlowEngine;
|
||||||
import com.budwk.app.flow.entity.ProcessInstance;
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
@@ -39,7 +37,6 @@ import com.budwk.app.zhgh.staffbenefit.difficulthelp.service.DifficultHelpCommon
|
|||||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.DifficultHelpPageParam;
|
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.DifficultHelpPageParam;
|
||||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.moneyImportVo;
|
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.moneyImportVo;
|
||||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||||
import com.deepoove.poi.XWPFTemplate;
|
|
||||||
import com.deepoove.poi.config.Configure;
|
import com.deepoove.poi.config.Configure;
|
||||||
import com.deepoove.poi.data.PictureRenderData;
|
import com.deepoove.poi.data.PictureRenderData;
|
||||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||||
@@ -74,8 +71,6 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -159,7 +154,7 @@ public class DifficultHelpReadingController {
|
|||||||
""");
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
cnd.and("ins.state", "=", 20);
|
cnd.and("ins.state", "=", 20);
|
||||||
pageParam.buildSearch(cnd, "info.");
|
pageParam.buildSearch(cnd, "info.", false);
|
||||||
cnd.groupBy("info.id");
|
cnd.groupBy("info.id");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination<NutMap> pagination = difficultHelpCommonService.listPageMap(pageParam.getPageNumber(), pageParam.getPageSize(), sql);
|
Pagination<NutMap> pagination = difficultHelpCommonService.listPageMap(pageParam.getPageNumber(), pageParam.getPageSize(), sql);
|
||||||
@@ -243,6 +238,7 @@ public class DifficultHelpReadingController {
|
|||||||
|
|
||||||
@At
|
@At
|
||||||
@Ok("void")
|
@Ok("void")
|
||||||
|
@SaCheckPermission("difficultHelp.reading")
|
||||||
public void doExportAllApply(DifficultHelpPageParam pageParam, HttpServletResponse response) throws Exception {
|
public void doExportAllApply(DifficultHelpPageParam pageParam, HttpServletResponse response) throws Exception {
|
||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
@@ -273,7 +269,7 @@ public class DifficultHelpReadingController {
|
|||||||
$condition
|
$condition
|
||||||
""");
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
pageParam.buildSearch(cnd, "info.");
|
pageParam.buildSearch(cnd, "info.", false);
|
||||||
cnd.groupBy("info.id");
|
cnd.groupBy("info.id");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
List<NutMap> list = difficultHelpCommonService.listMap(sql);
|
List<NutMap> list = difficultHelpCommonService.listMap(sql);
|
||||||
@@ -319,9 +315,9 @@ public class DifficultHelpReadingController {
|
|||||||
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
|
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
|
||||||
Configure config = Configure.builder().bind("familyList", policy).build();
|
Configure config = Configure.builder().bind("familyList", policy).build();
|
||||||
|
|
||||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate("difficulty_apply"), config)
|
try (InputStream input = sysOfficeTemplateUtil.getTemplate("difficulty_apply")) {
|
||||||
.render(docData)
|
zipOutputStream.write(sysOfficeTemplateUtil.renderTemplate(input, docData, config, false, "difficulthelp:batch:" + record.getString("id")));
|
||||||
.write(zipOutputStream);
|
}
|
||||||
zipOutputStream.closeEntry();
|
zipOutputStream.closeEntry();
|
||||||
}
|
}
|
||||||
zipOutputStream.flush();
|
zipOutputStream.flush();
|
||||||
@@ -379,17 +375,18 @@ public class DifficultHelpReadingController {
|
|||||||
String[] taskKeys = {"36ebafda-44c2-4bd3-bd7f-10839a575a0d", "715ece82-4ae3-433c-ad18-ed875f45d1e3", "e405f96c-5fc0-4f63-b323-e69dfe853253"};
|
String[] taskKeys = {"36ebafda-44c2-4bd3-bd7f-10839a575a0d", "715ece82-4ae3-433c-ad18-ed875f45d1e3", "e405f96c-5fc0-4f63-b323-e69dfe853253"};
|
||||||
String[] fields = {"firstApproval", "secondApproval", "thirdApproval"};
|
String[] fields = {"firstApproval", "secondApproval", "thirdApproval"};
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "");
|
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
}
|
}
|
||||||
ProcessInstance instance = dao.fetch(ProcessInstance.class, Cnd.where("businessNo", "=", businessId).desc("id"));
|
ProcessInstance instance = dao.fetch(ProcessInstance.class, Cnd.where("businessNo", "=", businessId).desc("id"));
|
||||||
if (instance == null) return;
|
if (instance == null) return;
|
||||||
List<ProcessTask> tasks = dao.query(ProcessTask.class, Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
List<ProcessTask> tasks = dao.query(ProcessTask.class, Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
||||||
for (ProcessTask task : tasks) {
|
for (ProcessTask task : tasks) {
|
||||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
||||||
if ("startTask".equals(task.getTaskName()) || (taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName())
|
||||||
|
&& taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||||
// 重新申请后,仅导出本轮审批,避免混入上一次退回或撤销前的意见。
|
// 重新申请后,仅导出本轮审批,避免混入上一次退回或撤销前的意见。
|
||||||
for (String field : fields) {
|
for (String field : fields) {
|
||||||
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "");
|
for (String suffix : List.of("", "Opinion", "User", "Date", "Year", "Month", "Day", "Sign")) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -453,22 +450,9 @@ public class DifficultHelpReadingController {
|
|||||||
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
||||||
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".pdf";
|
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".pdf";
|
||||||
|
|
||||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
|
try (InputStream input = getApplyTemplate(templateName)) {
|
||||||
XWPFTemplate.compile(getApplyTemplate(templateName),config)
|
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, config, true, "difficulthelp:" + difficultHelp.getId());
|
||||||
.render(docData)
|
CommonDownloadUtil.download(fileName, bytes, response);
|
||||||
.writeAndClose(byteArrayOutputStream);
|
|
||||||
byte[] bytes = byteArrayOutputStream.toByteArray();
|
|
||||||
File sourceFile = File.createTempFile("file_convert_origin", ".docx");
|
|
||||||
Files.write(sourceFile.toPath(), bytes, StandardOpenOption.WRITE);
|
|
||||||
|
|
||||||
File pdfFile = File.createTempFile("file_convert", ".pdf");
|
|
||||||
OfficePlusUtil.convert(sourceFile.getPath(), pdfFile.getPath());
|
|
||||||
CommonDownloadUtil.download(fileName, IoUtil.readBytes(FileUtil.getInputStream(pdfFile)), response);
|
|
||||||
// 删除临时文件
|
|
||||||
FileUtil.del(sourceFile);
|
|
||||||
FileUtil.del(pdfFile.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("困难慰问申请表导出PDF失败,id:{},错误信息:{}", difficultHelp.getId(), e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,18 +462,15 @@ public class DifficultHelpReadingController {
|
|||||||
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
String fileName = FileUtil.mainName(sysOfficeTemplateUtil.getTemplateFileName(templateName)) + "_" + difficultHelp.getUserName() + "_" +
|
||||||
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".docx";
|
DateUtil.format(difficultHelp.getApplyTime(), "yyyyMMdd") + ".docx";
|
||||||
|
|
||||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
|
try (InputStream input = getApplyTemplate(templateName)) {
|
||||||
XWPFTemplate.compile(getApplyTemplate(templateName),config)
|
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, docData, config, false, "difficulthelp:" + difficultHelp.getId());
|
||||||
.render(docData)
|
CommonDownloadUtil.download(fileName, bytes, response);
|
||||||
.writeAndClose(byteArrayOutputStream);
|
|
||||||
CommonDownloadUtil.download(fileName, byteArrayOutputStream.toByteArray(), response);
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("困难慰问申请表导出Word失败,id:{},错误信息:{}", difficultHelp.getId(), e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
@Ok("void")
|
@Ok("void")
|
||||||
|
@SaCheckPermission("difficultHelp.reading")
|
||||||
public void exportSummary(DifficultHelpPageParam pageParam,String flag,
|
public void exportSummary(DifficultHelpPageParam pageParam,String flag,
|
||||||
HttpServletResponse response) throws Exception {
|
HttpServletResponse response) throws Exception {
|
||||||
NutMap result = new NutMap();
|
NutMap result = new NutMap();
|
||||||
@@ -519,7 +500,7 @@ public class DifficultHelpReadingController {
|
|||||||
$condition
|
$condition
|
||||||
""");
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
Cnd cnd = Cnd.NEW();
|
||||||
pageParam.buildSearch(cnd, "info.");
|
pageParam.buildSearch(cnd, "info.", false);
|
||||||
cnd.groupBy("info.id");
|
cnd.groupBy("info.id");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
List<NutMap> list = difficultHelpCommonService.listMap(sql);
|
List<NutMap> list = difficultHelpCommonService.listMap(sql);
|
||||||
@@ -562,15 +543,13 @@ public class DifficultHelpReadingController {
|
|||||||
throw new RuntimeException("导出Excel汇总表失败:" + e.getMessage());
|
throw new RuntimeException("导出Excel汇总表失败:" + e.getMessage());
|
||||||
}
|
}
|
||||||
} else if ("docx".equals(flag)) {
|
} else if ("docx".equals(flag)) {
|
||||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
try (InputStream input = sysOfficeTemplateUtil.getTemplate(resource)) {
|
||||||
Configure config = Configure.builder()
|
Configure config = Configure.builder()
|
||||||
.bind("da", new LoopRowTableRenderPolicy())
|
.bind("da", new LoopRowTableRenderPolicy())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(resource), config)
|
byte[] bytes = sysOfficeTemplateUtil.renderTemplate(input, result, config, false, "difficulthelp:summary:" + resource);
|
||||||
.render(result)
|
CommonDownloadUtil.download(fileName + ".docx", bytes, response);
|
||||||
.writeAndClose(out);
|
|
||||||
CommonDownloadUtil.download(fileName + ".docx", out.toByteArray(), response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
@@ -1,6 +1,7 @@
|
|||||||
package com.budwk.app.zhgh.staffbenefit.difficulthelp.service;
|
package com.budwk.app.zhgh.staffbenefit.difficulthelp.service;
|
||||||
|
|
||||||
import com.budwk.app.base.service.BaseService;
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.models.DifficultHelpInfo;
|
import com.budwk.app.zhgh.staffbenefit.difficulthelp.models.DifficultHelpInfo;
|
||||||
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.DifficultHelpPageParam;
|
import com.budwk.app.zhgh.staffbenefit.difficulthelp.vo.DifficultHelpPageParam;
|
||||||
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPageForm;
|
||||||
@@ -21,6 +22,14 @@ public interface DifficultHelpCommonService extends BaseService<DifficultHelpInf
|
|||||||
|
|
||||||
void validateApplyUser(DifficultHelpInfo difficultHelpInfo);
|
void validateApplyUser(DifficultHelpInfo difficultHelpInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 困难帮扶进入校工会办公室主任审批时,通知本次任务的实际参与人。
|
||||||
|
* @param task WF 已创建且参与人已落库的任务;仅 KNBF 办公室审批待办触发,
|
||||||
|
* 接收人使用任务参与人的 actorAccount(系统 loginname)
|
||||||
|
* @return 无返回值;开关关闭或非目标节点不发送,发送失败记录日志而不阻断流程
|
||||||
|
*/
|
||||||
|
void notifyOfficeApproval(ProcessTask task);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入实际金额数据处理
|
* 导入实际金额数据处理
|
||||||
* @param file 文件
|
* @param file 文件
|
||||||
|
|||||||
+59
@@ -6,6 +6,12 @@ import cn.hutool.json.JSONUtil;
|
|||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.base.constant.RoleConstant;
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
import com.budwk.app.base.exception.BaseException;
|
import com.budwk.app.base.exception.BaseException;
|
||||||
|
import com.budwk.app.base.wxwork.WxWorkMessageService;
|
||||||
|
import com.budwk.app.flow.entity.ProcessDefine;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
import com.budwk.app.base.utils.ManyAddOrRenewUtil;
|
import com.budwk.app.base.utils.ManyAddOrRenewUtil;
|
||||||
@@ -31,6 +37,8 @@ import org.nutz.ioc.loader.annotation.IocBean;
|
|||||||
import org.nutz.lang.Lang;
|
import org.nutz.lang.Lang;
|
||||||
import org.nutz.lang.random.R;
|
import org.nutz.lang.random.R;
|
||||||
import org.nutz.lang.util.NutMap;
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.log.Log;
|
||||||
|
import org.nutz.log.Logs;
|
||||||
import org.nutz.mvc.upload.TempFile;
|
import org.nutz.mvc.upload.TempFile;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -46,6 +54,8 @@ import java.util.stream.IntStream;
|
|||||||
*/
|
*/
|
||||||
@IocBean(args = {"refer:dao"})
|
@IocBean(args = {"refer:dao"})
|
||||||
public class DifficultHelpCommonServiceImpl extends BaseServiceImpl<DifficultHelpInfo> implements DifficultHelpCommonService {
|
public class DifficultHelpCommonServiceImpl extends BaseServiceImpl<DifficultHelpInfo> implements DifficultHelpCommonService {
|
||||||
|
private static final Log log = Logs.get();
|
||||||
|
private static final String OFFICE_APPROVAL_TASK = "36ebafda-44c2-4bd3-bd7f-10839a575a0d";
|
||||||
|
|
||||||
public DifficultHelpCommonServiceImpl(Dao dao) {
|
public DifficultHelpCommonServiceImpl(Dao dao) {
|
||||||
super(dao);
|
super(dao);
|
||||||
@@ -53,6 +63,55 @@ public class DifficultHelpCommonServiceImpl extends BaseServiceImpl<DifficultHel
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ManyAddOrRenewUtil manyAddOrRenewUtil;
|
private ManyAddOrRenewUtil manyAddOrRenewUtil;
|
||||||
|
@Inject
|
||||||
|
private WxWorkMessageService wxWorkMessageService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只通知 KNBF 办公室待办的实际审核人;重新提交生成的新任务沿用同一入口。
|
||||||
|
* task 为任务开始事件对应的 WF 任务,actorAccount 为学校企业微信 userid。
|
||||||
|
* 无返回值;服务返回 skipped 表示开关关闭,success=false 表示接口失败或部分接收人无效。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public void notifyOfficeApproval(ProcessTask task) {
|
||||||
|
if (task == null || task.getId() == null || task.getProcessInstanceId() == null
|
||||||
|
|| !OFFICE_APPROVAL_TASK.equals(task.getTaskName())
|
||||||
|
|| !ProcessTaskStateEnum.DOING.getCode().equals(task.getTaskState())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ProcessInstance instance = dao().fetch(ProcessInstance.class, task.getProcessInstanceId());
|
||||||
|
if (instance == null || instance.getProcessDefineId() == null) return;
|
||||||
|
ProcessDefine define = dao().fetch(ProcessDefine.class, instance.getProcessDefineId());
|
||||||
|
// 使用实例所属定义核验流程 KEY,避免其他流程复用同一个节点 ID 时误发。
|
||||||
|
if (define == null || !"KNBF".equals(define.getName())) return;
|
||||||
|
DifficultHelpInfo info = StrUtil.isBlank(instance.getBusinessNo()) ? null : fetch(instance.getBusinessNo());
|
||||||
|
if (info == null) {
|
||||||
|
log.warnf("困难帮扶企业微信通知跳过:申请不存在,taskId=%s", task.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<ProcessTaskActor> actors = dao().query(ProcessTaskActor.class,
|
||||||
|
Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
|
||||||
|
List<String> loginNames = actors.stream().map(ProcessTaskActor::getActorAccount)
|
||||||
|
.filter(StrUtil::isNotBlank).map(String::trim).distinct().toList();
|
||||||
|
// 不按角色扩大接收范围,未绑定工号时不以内部用户 ID 代替企业微信 userid。
|
||||||
|
if (loginNames.isEmpty()) {
|
||||||
|
log.warnf("困难帮扶企业微信通知跳过:审核人 loginname 为空,taskId=%s", task.getId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String content = "您有一条困难帮扶申请待审核,受助人:"
|
||||||
|
+ StrUtil.blankToDefault(info.getUserName(), "未填写") + ",请进入校工会办公室审批页面办理。";
|
||||||
|
// 流程定义中仍保留旧的 unionLeaderApproval 链接,本节点实际办理入口为 branchUnionApproval。
|
||||||
|
NutMap result = wxWorkMessageService.massSend(loginNames, "困难帮扶待办提醒", content,
|
||||||
|
"/platform/difficultHelp/branchUnionApproval/h5");
|
||||||
|
if (!result.getBoolean("skipped", false) && !result.getBoolean("success", false)) {
|
||||||
|
log.warnf("困难帮扶企业微信通知发送失败或部分失败,taskId=%s,result=%s", task.getId(), result);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 外部消息不改变审批结果;日志保留任务 ID,便于定位接口、账号或配置问题。
|
||||||
|
log.error("困难帮扶企业微信通知异常,taskId=" + task.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateApplyUser(DifficultHelpInfo difficultHelpInfo) {
|
public void validateApplyUser(DifficultHelpInfo difficultHelpInfo) {
|
||||||
|
|||||||
+252
@@ -0,0 +1,252 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.annotation.SLog;
|
||||||
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
|
import com.budwk.app.base.page.Pagination;
|
||||||
|
import com.budwk.app.base.result.Result;
|
||||||
|
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||||
|
import com.budwk.app.flow.constant.FlowConst;
|
||||||
|
import com.budwk.app.flow.engine.FlowEngine;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||||
|
import com.budwk.app.flow.service.FlowCommonService;
|
||||||
|
import com.budwk.app.sys.views.View_user;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.democratic.suggestionBox.models.SuggestionBox;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
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;
|
||||||
|
import org.nutz.ioc.aop.Aop;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceApplyController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/8/20 15:40
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@SaCheckRole("BRANCH_UNION_CHAIRMAN")
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/special_condolence/apply")
|
||||||
|
@Api("特殊慰问申请")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class SpecialCondolenceApplyController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private FlowEngine flowEngine;
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
@Inject
|
||||||
|
private FlowCommonService flowCommonService;
|
||||||
|
@Inject
|
||||||
|
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
|
||||||
|
|
||||||
|
@At("/")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/apply/index.html")
|
||||||
|
@SaCheckPermission("special_condolence.apply")
|
||||||
|
public void index() {}
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/staffbenefit/specialcondolence/apply/index.html")
|
||||||
|
@SaCheckPermission("h5.special_condolence.apply")
|
||||||
|
public void h5Index() {}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("保存申请")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
@SLog(tag = "特殊慰问系统-慰问申请", msg = "保存申请")
|
||||||
|
public Result save(@Param("data") SpecialCondolence specialcondolence) {
|
||||||
|
if(StrUtil.isBlank(specialcondolence.getId())) specialcondolence.setCreateTime(DateUtil.now());
|
||||||
|
prepareApplication(specialcondolence);
|
||||||
|
specialcondolenceService.saveDraftApplication(specialcondolence);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("提交申请")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
@SLog(tag = "特殊慰问系统-慰问申请", msg = "提交申请")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public Result submit(@Param("data") SpecialCondolence specialcondolence) {
|
||||||
|
if (StrUtil.isBlank(specialcondolence.getRemark()) || specialcondolence.getRemark().trim().length() > 500) throw new com.budwk.app.base.exception.BaseException("请填写500字以内的申请事由");
|
||||||
|
if (StrUtil.isBlank(specialcondolence.getSignature())) throw new com.budwk.app.base.exception.BaseException("请完成申请人签字");
|
||||||
|
if(StrUtil.isBlank(specialcondolence.getId())) specialcondolence.setCreateTime(DateUtil.now());
|
||||||
|
prepareApplication(specialcondolence);
|
||||||
|
specialcondolenceService.saveApplication(specialcondolence);
|
||||||
|
// 开启流程实例
|
||||||
|
Dict args = Dict.create();
|
||||||
|
args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||||
|
args.set(FlowConst.FORM_DATA, specialcondolence);
|
||||||
|
ProcessInstance instance = flowEngine.startProcessInstanceByKey("TSWW", specialcondolence.getId(), SecurityUtil.getUserId(), args);
|
||||||
|
|
||||||
|
// 自动完成第一个申请任务
|
||||||
|
List<ProcessTask> doingTaskList = flowEngine.processTaskService().getDoingTaskList(instance.getId(), null);
|
||||||
|
for (ProcessTask task : doingTaskList) {
|
||||||
|
flowEngine.executeProcessTask(task.getId(), SecurityUtil.getUserId(), args);
|
||||||
|
}
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("重新提交申请")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
public Result submitAgain(@Param("data") SpecialCondolence specialcondolence, @Param("taskId") Long taskId) {
|
||||||
|
if (StrUtil.isBlank(specialcondolence.getRemark()) || specialcondolence.getRemark().trim().length() > 500) throw new com.budwk.app.base.exception.BaseException("请填写500字以内的申请事由");
|
||||||
|
if (StrUtil.isBlank(specialcondolence.getSignature())) throw new com.budwk.app.base.exception.BaseException("请完成申请人签字");
|
||||||
|
ProcessTask task = taskId == null ? null : dao.fetch(ProcessTask.class, taskId);
|
||||||
|
ProcessInstance instance = task == null ? null : dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
|
||||||
|
if (instance == null || !StrUtil.equals(instance.getBusinessNo(), specialcondolence.getId())
|
||||||
|
|| !"startTask".equals(task.getTaskName()) || !SecurityUtil.getUserId().equals(instance.getOperator())) {
|
||||||
|
throw new com.budwk.app.base.exception.BaseException("申请任务不匹配");
|
||||||
|
}
|
||||||
|
prepareApplication(specialcondolence);
|
||||||
|
specialcondolenceService.saveApplication(specialcondolence);
|
||||||
|
|
||||||
|
Dict dict = Dict.create();
|
||||||
|
dict.set(FlowConst.PROCESS_TASK_ID_KEY, taskId);
|
||||||
|
dict.set(FlowConst.FORM_DATA, specialcondolence);
|
||||||
|
dict.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.RE_APPLY.getCode());
|
||||||
|
flowCommonService.executeTask(dict);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("查询用户")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
public Object listUser(String keyword) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
select
|
||||||
|
u.id,
|
||||||
|
u.idCard,
|
||||||
|
u.personType,
|
||||||
|
bank.bankOfDeposit,
|
||||||
|
bank.bankUserName,
|
||||||
|
bank.bankCardNumber,
|
||||||
|
username as userName,
|
||||||
|
loginname as loginName,
|
||||||
|
sex,
|
||||||
|
mobile,
|
||||||
|
technicalTitle,
|
||||||
|
IFNULL(unitname, '暂无') as unitName,
|
||||||
|
unitid as unitId,
|
||||||
|
unionid as unionId,
|
||||||
|
unionname as unionName
|
||||||
|
from
|
||||||
|
vw_user u
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT idCard, bankOfDeposit, bankUserName, bankCardNumber,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY idCard ORDER BY createdAt DESC, id DESC) rn
|
||||||
|
FROM special_condolence_recipient WHERE delFlag = false
|
||||||
|
) bank ON bank.idCard = u.idCard AND bank.rn = 1 AND u.idCard <> ''
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
if (StrUtil.isNotBlank(keyword)) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(View_user::getLoginname, "like", "%" + keyword + "%");
|
||||||
|
seg.or(View_user::getUsername, "like", "%" + keyword + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
if (StrUtil.isBlank(SecurityUtil.getUnionId())) throw new com.budwk.app.base.exception.BaseException("申请人未关联分工会");
|
||||||
|
cnd.and("u.unionId", "=", SecurityUtil.getUnionId());
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination pagination = specialcondolenceService.listPageMap(1, 50, sql);
|
||||||
|
return Result.success(pagination.getList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@Ok("void")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
public void importTemplate(javax.servlet.http.HttpServletResponse response) throws Exception {
|
||||||
|
String templateCode = "special_condolence_import";
|
||||||
|
try (java.io.InputStream input = sysOfficeTemplateUtil.getTemplate(templateCode)) {
|
||||||
|
com.budwk.app.base.utils.CommonDownloadUtil.download(
|
||||||
|
sysOfficeTemplateUtil.getTemplateFileName(templateCode), input.readAllBytes(), response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission(value = {"special_condolence.apply", "h5.special_condolence.apply"}, mode = SaMode.OR)
|
||||||
|
@org.nutz.mvc.annotation.AdaptBy(type = org.nutz.mvc.upload.UploadAdaptor.class, args = {"ioc:fileUpload"})
|
||||||
|
public Result importRecipients(@Param("file") org.nutz.mvc.upload.TempFile file) throws Exception {
|
||||||
|
if (file == null) throw new com.budwk.app.base.exception.BaseException("请选择Excel文件");
|
||||||
|
if (!file.getSubmittedFileName().toLowerCase(java.util.Locale.ROOT).matches(".*\\.(xlsx|xls)$")) throw new com.budwk.app.base.exception.BaseException("仅支持xlsx、xls文件");
|
||||||
|
String[] headers = {"慰问对象", "工号", "身份证号码", "开户行", "户名", "收款账户"};
|
||||||
|
String[] fields = {"helpUserName", "helpLoginName", "idCard", "bankOfDeposit", "bankUserName", "bankCardNumber"};
|
||||||
|
java.util.List<cn.hutool.json.JSONObject> result = new java.util.ArrayList<>();
|
||||||
|
try (java.io.InputStream input = new java.io.FileInputStream(file.getFile());
|
||||||
|
org.apache.poi.ss.usermodel.Workbook workbook = org.apache.poi.ss.usermodel.WorkbookFactory.create(input)) {
|
||||||
|
if (workbook.getNumberOfSheets() == 0) throw new com.budwk.app.base.exception.BaseException("Excel中没有工作表");
|
||||||
|
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(0);
|
||||||
|
org.apache.poi.ss.usermodel.DataFormatter formatter = new org.apache.poi.ss.usermodel.DataFormatter();
|
||||||
|
org.apache.poi.ss.usermodel.Row header = sheet.getRow(0);
|
||||||
|
for (int c = 0; c < headers.length; c++) {
|
||||||
|
if (header == null || !headers[c].equals(formatter.formatCellValue(header.getCell(c)).trim())) throw new com.budwk.app.base.exception.BaseException("表头不正确,请下载导入模板");
|
||||||
|
}
|
||||||
|
if (sheet.getLastRowNum() > 1000) throw new com.budwk.app.base.exception.BaseException("最多导入1000行");
|
||||||
|
for (int r = 1; r <= sheet.getLastRowNum(); r++) {
|
||||||
|
org.apache.poi.ss.usermodel.Row excelRow = sheet.getRow(r);
|
||||||
|
if (excelRow == null) continue;
|
||||||
|
String prefix = "慰问对象" + (result.size() + 1) + " ";
|
||||||
|
cn.hutool.json.JSONObject row = new cn.hutool.json.JSONObject();
|
||||||
|
boolean empty = true;
|
||||||
|
for (int c = 0; c < fields.length; c++) {
|
||||||
|
org.apache.poi.ss.usermodel.Cell cell = excelRow.getCell(c);
|
||||||
|
String value = formatter.formatCellValue(cell).trim();
|
||||||
|
if (c != 1 && cell != null && cell.getCellType() == org.apache.poi.ss.usermodel.CellType.FORMULA) throw new com.budwk.app.base.exception.BaseException(prefix + "不支持公式,请填写实际值");
|
||||||
|
if ((c == 2 || c == 5) && cell != null && cell.getCellType() == org.apache.poi.ss.usermodel.CellType.NUMERIC) throw new com.budwk.app.base.exception.BaseException(prefix + "工号、身份证和收款账户请使用文本格式,避免数字失真");
|
||||||
|
row.set(fields[c], value);
|
||||||
|
empty = empty && value.isEmpty();
|
||||||
|
}
|
||||||
|
if (empty) continue;
|
||||||
|
if (!com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceRecipients.validIdCard(row.getStr("idCard"))) throw new com.budwk.app.base.exception.BaseException(prefix + "身份证号码格式不正确");
|
||||||
|
if (!row.getStr("bankCardNumber").matches("[0-9]{6,30}")) throw new com.budwk.app.base.exception.BaseException(prefix + "收款账户格式不正确");
|
||||||
|
result.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.isEmpty()) throw new com.budwk.app.base.exception.BaseException("没有可导入的数据");
|
||||||
|
return Result.success(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareApplication(SpecialCondolence info) {
|
||||||
|
if (StrUtil.isNotBlank(info.getId())) {
|
||||||
|
SpecialCondolence existing = dao.fetch(SpecialCondolence.class, info.getId());
|
||||||
|
if (existing == null || !SecurityUtil.getUserId().equals(existing.getCreatedBy())) {
|
||||||
|
throw new com.budwk.app.base.exception.BaseException("只能修改本人申请");
|
||||||
|
}
|
||||||
|
info.setCreatedBy(existing.getCreatedBy());
|
||||||
|
}
|
||||||
|
info.setApplyUserId(SecurityUtil.getUserId());
|
||||||
|
info.setApplyUserName(SecurityUtil.getUserUsername());
|
||||||
|
info.setApplyLoginName(SecurityUtil.getUserLoginname());
|
||||||
|
info.setApplyUnionId(SecurityUtil.getUnionId());
|
||||||
|
info.setApplyUnitId(SecurityUtil.getUnitId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.exception.BaseException;
|
||||||
|
import com.budwk.app.base.result.Result;
|
||||||
|
import com.budwk.app.flow.constant.FlowConst;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.service.FlowCommonService;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.ioc.aop.Aop;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.json.Json;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
@IocBean
|
||||||
|
@Ok("json")
|
||||||
|
@At("/platform/special_condolence/approval")
|
||||||
|
public class SpecialCondolenceApprovalController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private FlowCommonService flowCommonService;
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckLogin
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public Result executeTask(@Param("data") String data) {
|
||||||
|
Dict args = Json.fromJson(Dict.class, data);
|
||||||
|
if (args == null || args.getLong(FlowConst.PROCESS_TASK_ID_KEY) == null) {
|
||||||
|
throw new BaseException("审批任务不能为空");
|
||||||
|
}
|
||||||
|
ProcessTask task = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||||
|
if (task == null) throw new BaseException("审批任务不存在");
|
||||||
|
if (!"c438972e-2f67-4907-b229-cb7aa17da147".equals(task.getTaskName())
|
||||||
|
&& !"7f560675-aeea-4254-a57e-957d03d6b786".equals(task.getTaskName())
|
||||||
|
&& !"af363a4e-fc56-42a0-9906-8c7a2814006b".equals(task.getTaskName())) {
|
||||||
|
throw new BaseException("当前任务不是特殊慰问审批任务");
|
||||||
|
}
|
||||||
|
ProcessInstance instance = dao.fetch(ProcessInstance.class, task.getProcessInstanceId());
|
||||||
|
com.budwk.app.flow.entity.ProcessDefine define = instance == null ? null : dao.fetch(com.budwk.app.flow.entity.ProcessDefine.class, instance.getProcessDefineId());
|
||||||
|
SpecialCondolence info = define == null || !"TSWW".equals(define.getName()) ? null : dao.fetch(SpecialCondolence.class, instance.getBusinessNo());
|
||||||
|
if (info == null) throw new BaseException("特殊慰问申请不存在");
|
||||||
|
if (StrUtil.isBlank(args.getStr("tf_sign"))) throw new BaseException("请完成审批签字");
|
||||||
|
if (StrUtil.isBlank(args.getStr("tf_opinion"))) throw new BaseException("请填写审批意见");
|
||||||
|
|
||||||
|
// 参与者权限由流程引擎校验,业务入口不接受客户端指定管理员代办。
|
||||||
|
args.remove(FlowConst.EXT_ENABLE_OPERATOR);
|
||||||
|
flowCommonService.executeTask(args);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
+168
@@ -0,0 +1,168 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
|
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.PageUtil;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
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.dao.util.cri.Static;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceFourthApprovalController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 16:23
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/special_condolence/fourthApproval")
|
||||||
|
@Api("特殊慰问四级审核")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class SpecialCondolenceFourthApprovalController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
|
||||||
|
@At("/")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/fourthApproval/index.html")
|
||||||
|
@SaCheckPermission("special_condolence.fourthApproval")
|
||||||
|
public void index() {}
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/staffbenefit/specialcondolence/fourthApproval/index.html")
|
||||||
|
@SaCheckPermission("h5.special_condolence.fourthApproval")
|
||||||
|
public void h5Index() {}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.fourthApproval", "h5.special_condolence.fourthApproval"}, mode = SaMode.OR)
|
||||||
|
public Result pageData(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type,
|
||||||
|
@Param(value = "unionId") String unionId,
|
||||||
|
@Param(value = "unitId") String unitId,
|
||||||
|
@Param(value = "approval") Boolean approval) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
COALESCE(recipientTotals.recipientCount, 0) AS recipientCount,
|
||||||
|
type.name as typeName,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
ins.businessNo,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.variable instanceVariable,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.id taskId,
|
||||||
|
t.taskName AS taskKey,
|
||||||
|
t.displayName taskName,
|
||||||
|
t.taskType,
|
||||||
|
t.performType taskPerformType,
|
||||||
|
t.taskState,
|
||||||
|
t.finishTime,
|
||||||
|
t.taskParentId,
|
||||||
|
t.variable taskVariable,
|
||||||
|
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||||
|
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
LEFT JOIN special_condolence info ON info.id = ins.businessNo
|
||||||
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT applyId, COUNT(*) AS recipientCount
|
||||||
|
FROM special_condolence_recipient
|
||||||
|
WHERE delFlag = false
|
||||||
|
GROUP BY applyId
|
||||||
|
) recipientTotals ON recipientTotals.applyId = info.id
|
||||||
|
LEFT JOIN special_condolence_type type ON info.type = type.id
|
||||||
|
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||||
|
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("info.id", "is not", null);
|
||||||
|
cnd.and(new Static("""
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_task newer
|
||||||
|
WHERE newer.processInstanceId = t.processInstanceId
|
||||||
|
AND newer.taskName = t.taskName
|
||||||
|
AND newer.id > t.id
|
||||||
|
)
|
||||||
|
"""));
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(SpecialCondolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or(SpecialCondolence::getHelpLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
cnd.andEX("info.type", "=", type);
|
||||||
|
cnd.andEX("YEAR(info.createTime)", "=", year);
|
||||||
|
cnd.andEX("info.applyUnionId", "=", unionId);
|
||||||
|
cnd.andEX("info.applyUnitId", "=", unitId);
|
||||||
|
|
||||||
|
cnd.and("t.taskName", "=", "af363a4e-fc56-42a0-9906-8c7a2814006b");
|
||||||
|
if (!"superadmin".equals(SecurityUtil.getUserLoginname()) && !AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name())) {
|
||||||
|
Sql unitSql = Sqls.queryString("""
|
||||||
|
SELECT DISTINCT ur.unitId
|
||||||
|
FROM sys_user_role ur
|
||||||
|
INNER JOIN sys_role r ON r.id = ur.roleId
|
||||||
|
WHERE ur.userId = @userId
|
||||||
|
AND ur.enable = true
|
||||||
|
AND r.disabled = false
|
||||||
|
AND r.code = @roleCode
|
||||||
|
AND ur.unitId IS NOT NULL
|
||||||
|
AND ur.unitId <> ''
|
||||||
|
""");
|
||||||
|
unitSql.setParam("userId", SecurityUtil.getUserId());
|
||||||
|
unitSql.setParam("roleCode", RoleConstant.UNIT_SCHOOL_LEADER.name());
|
||||||
|
dao.execute(unitSql);
|
||||||
|
List<String> managedUnitIds = unitSql.getList(String.class);
|
||||||
|
if (managedUnitIds.isEmpty()) {
|
||||||
|
cnd.and(new Static("1 = 0"));
|
||||||
|
} else {
|
||||||
|
cnd.and("info.applyUnitId", "in", managedUnitIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (approval) {
|
||||||
|
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||||
|
} else {
|
||||||
|
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||||
|
cnd.desc("info.createTime");
|
||||||
|
} else {
|
||||||
|
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||||
|
}
|
||||||
|
cnd.groupBy("t.id");
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination<NutMap> pageVO = specialcondolenceService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
return Result.success(pageVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
+303
@@ -0,0 +1,303 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.lang.Dict;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.annotation.SLog;
|
||||||
|
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.sms.SmsService;
|
||||||
|
import com.budwk.app.base.utils.PageUtil;
|
||||||
|
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||||
|
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||||
|
import com.budwk.app.flow.engine.FlowEngine;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.flow.vo.ProcessTaskVO;
|
||||||
|
import com.budwk.app.sys.views.View_user;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceType;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
import com.deepoove.poi.data.PictureRenderData;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
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.lang.Lang;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceApplyController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/28 11:06
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/special_condolence/mine")
|
||||||
|
@Api("特殊慰问我的")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class SpecialCondolenceMineController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
@Inject
|
||||||
|
private FlowEngine flowEngine;
|
||||||
|
@Inject
|
||||||
|
private SysOfficeTemplateUtil sysOfficeTemplateUtil;
|
||||||
|
|
||||||
|
@At("/")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/mine/index.html")
|
||||||
|
@SaCheckPermission("special_condolence.mine")
|
||||||
|
public void index() {}
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/staffbenefit/specialcondolence/mine/index.html")
|
||||||
|
@SaCheckPermission("h5.special_condolence.mine")
|
||||||
|
public void h5Index() {}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.mine", "h5.special_condolence.mine"}, mode = SaMode.OR)
|
||||||
|
public Result pageData(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
COALESCE(recipientTotals.recipientCount, 0) AS recipientCount,
|
||||||
|
type.name as typeName,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
ins.businessNo,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.variable instanceVariable,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.id taskId,
|
||||||
|
t.taskName AS taskKey,
|
||||||
|
t.displayName taskName,
|
||||||
|
t.taskType,
|
||||||
|
t.performType taskPerformType,
|
||||||
|
t.taskState,
|
||||||
|
t.finishTime,
|
||||||
|
t.taskParentId,
|
||||||
|
t.variable taskVariable,
|
||||||
|
IF((SELECT taskName FROM wf_process_task tt WHERE tt.id = t.taskParentId) = 'startTask', 1, 0) canRevoke,
|
||||||
|
(select MAX(id) from wf_process_task where processInstanceId = ins.id and taskName = 'startTask') AS startTaskId
|
||||||
|
FROM
|
||||||
|
special_condolence info
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT applyId, COUNT(*) AS recipientCount
|
||||||
|
FROM special_condolence_recipient
|
||||||
|
WHERE delFlag = false
|
||||||
|
GROUP BY applyId
|
||||||
|
) recipientTotals ON recipientTotals.applyId = info.id
|
||||||
|
LEFT JOIN special_condolence_type type ON info.type = type.id
|
||||||
|
LEFT JOIN `wf_process_instance` ins ON ins.businessNo = info.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
processInstanceId,
|
||||||
|
taskName,
|
||||||
|
displayName,
|
||||||
|
taskType,
|
||||||
|
performType,
|
||||||
|
taskState,
|
||||||
|
finishTime,
|
||||||
|
taskParentId,
|
||||||
|
variable,
|
||||||
|
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
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(SpecialCondolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or(SpecialCondolence::getHelpLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
cnd.andEX("year(info.createTime)", "=", year);
|
||||||
|
cnd.andEX("info.type", "=", type);
|
||||||
|
cnd.and("info.createdBy", "=", SecurityUtil.getUserId());
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) {
|
||||||
|
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||||
|
} else {
|
||||||
|
cnd.desc("info.createTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination<NutMap> pagination = specialcondolenceService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
return Result.success(pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@Ok("void")
|
||||||
|
@ApiOperation("导出特殊慰问申请表")
|
||||||
|
@SaCheckPermission("special_condolence.mine")
|
||||||
|
public void doExportApply(String id, HttpServletResponse response, Boolean print) throws Exception {
|
||||||
|
log.info("[特殊慰问导出] 开始,applyId={}, userId={}, format={}", id, SecurityUtil.getUserId(), Boolean.TRUE.equals(print) ? "PDF" : "Word");
|
||||||
|
SpecialCondolence specialcondolence = specialcondolenceService.loadApplication(id);
|
||||||
|
if (specialcondolence == null) throw new BaseException("该条记录不存在");
|
||||||
|
if (!SecurityUtil.getUserId().equals(specialcondolence.getCreatedBy())) {
|
||||||
|
throw new BaseException("只能导出本人提交的申请");
|
||||||
|
}
|
||||||
|
ProcessInstance instance = specialcondolenceService.dao().fetch(ProcessInstance.class,
|
||||||
|
Cnd.where("businessNo", "=", id).desc("id"));
|
||||||
|
if (instance == null || !ProcessInstanceStateEnum.FINISHED.getCode().equals(instance.getState())) {
|
||||||
|
throw new BaseException("只能导出已完成的申请");
|
||||||
|
}
|
||||||
|
log.info("[特殊慰问导出] 流程已完成,applyId={}, instanceId={}, state={}, applicantSignPresent={}", id, instance.getId(), instance.getState(), StrUtil.isNotBlank(specialcondolence.getSignature()));
|
||||||
|
NutMap docData = Lang.obj2nutmap(specialcondolence);
|
||||||
|
docData.put("payUserName", StrUtil.nullToEmpty(specialcondolence.getBankUserName()));
|
||||||
|
SpecialCondolenceType type = specialcondolenceService.dao().fetch(SpecialCondolenceType.class, specialcondolence.getType());
|
||||||
|
docData.put("typeName", type == null ? "" : type.getName());
|
||||||
|
docData.put("signature", null);
|
||||||
|
if (StrUtil.isNotBlank(specialcondolence.getSignature())) {
|
||||||
|
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, specialcondolence.getSignature());
|
||||||
|
if (signature == null) throw new BaseException("申请人签字图片读取失败");
|
||||||
|
docData.put("signature", signature);
|
||||||
|
}
|
||||||
|
fillApplyApprovals(docData, instance);
|
||||||
|
for (String field : List.of("signature", "secondApprovalSign", "thirdApprovalSign", "fourthApprovalSign")) {
|
||||||
|
Object value = docData.get(field);
|
||||||
|
log.info("[特殊慰问导出] 渲染前图片字段,applyId={}, instanceId={}, field={}, valueType={}", id, instance.getId(), field, value == null ? "null" : value.getClass().getName());
|
||||||
|
}
|
||||||
|
String fileName = "重庆工贸职业技术学院特殊慰问申请表_" + StrUtil.nullToEmpty(specialcondolence.getHelpUserName());
|
||||||
|
try (InputStream input = getClass().getResourceAsStream("/templates/condolence/重庆工贸职业技术学院职工慰问申请表.doc")) {
|
||||||
|
if (input == null) throw new BaseException("特殊慰问申请表模板不存在");
|
||||||
|
boolean pdf = Boolean.TRUE.equals(print);
|
||||||
|
com.aspose.words.Document template = new com.aspose.words.Document(input);
|
||||||
|
template.getRange().replace("职工慰问", "特殊慰问", new com.aspose.words.FindReplaceOptions());
|
||||||
|
com.aspose.words.NodeCollection rows = template.getChildNodes(com.aspose.words.NodeType.ROW, true);
|
||||||
|
for (int i = rows.getCount() - 1; i >= 0; i--) {
|
||||||
|
com.aspose.words.Node row = rows.get(i);
|
||||||
|
if (row.getText().contains("firstApproval") || row.getText().contains("分工会主席")) row.remove();
|
||||||
|
}
|
||||||
|
java.io.ByteArrayOutputStream templateOutput = new java.io.ByteArrayOutputStream();
|
||||||
|
template.save(templateOutput, com.aspose.words.SaveFormat.DOCX);
|
||||||
|
byte[] bytes;
|
||||||
|
if (specialcondolence.getRecipients() != null && !specialcondolence.getRecipients().isEmpty()) {
|
||||||
|
com.aspose.words.Document combined = null;
|
||||||
|
for (cn.hutool.json.JSONObject person : specialcondolence.getRecipients()) {
|
||||||
|
NutMap personData = new NutMap();
|
||||||
|
personData.putAll(docData);
|
||||||
|
personData.putAll(person);
|
||||||
|
personData.put("payUserName", person.getStr("bankUserName"));
|
||||||
|
byte[] rendered = sysOfficeTemplateUtil.renderTemplate(new java.io.ByteArrayInputStream(templateOutput.toByteArray()), personData, null, false, "specialcondolence:" + id);
|
||||||
|
com.aspose.words.Document part = new com.aspose.words.Document(new java.io.ByteArrayInputStream(rendered));
|
||||||
|
if (combined == null) combined = part;
|
||||||
|
else combined.appendDocument(part, com.aspose.words.ImportFormatMode.KEEP_SOURCE_FORMATTING);
|
||||||
|
}
|
||||||
|
java.io.ByteArrayOutputStream output = new java.io.ByteArrayOutputStream();
|
||||||
|
combined.save(output, pdf ? com.aspose.words.SaveFormat.PDF : com.aspose.words.SaveFormat.DOCX);
|
||||||
|
bytes = output.toByteArray();
|
||||||
|
} else {
|
||||||
|
bytes = sysOfficeTemplateUtil.renderTemplate(new java.io.ByteArrayInputStream(templateOutput.toByteArray()), docData, null, pdf, "specialcondolence:" + id);
|
||||||
|
}
|
||||||
|
log.info("[特殊慰问导出] 渲染完成,applyId={}, format={}, outputBytes={}", id, pdf ? "PDF" : "Word", bytes.length);
|
||||||
|
CommonDownloadUtil.download(fileName + (pdf ? ".pdf" : ".docx"), bytes, response);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[特殊慰问导出] 模板渲染或文件输出失败,applyId={}, instanceId={}, format={}", id, instance.getId(), Boolean.TRUE.equals(print) ? "PDF" : "Word", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillApplyApprovals(NutMap docData, ProcessInstance instance) {
|
||||||
|
String[] taskKeys = {"c438972e-2f67-4907-b229-cb7aa17da147",
|
||||||
|
"7f560675-aeea-4254-a57e-957d03d6b786", "af363a4e-fc56-42a0-9906-8c7a2814006b"};
|
||||||
|
String[] fields = {"secondApproval", "thirdApproval", "fourthApproval"};
|
||||||
|
List<String> suffixes = List.of("Opinion", "Sign", "Year", "Month", "Day");
|
||||||
|
for (String field : fields) {
|
||||||
|
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
|
}
|
||||||
|
List<ProcessTask> tasks = specialcondolenceService.dao().query(ProcessTask.class,
|
||||||
|
Cnd.where("processInstanceId", "=", instance.getId()).asc("id"));
|
||||||
|
log.info("[特殊慰问导出] 查询审批记录,applyId={}, instanceId={}, taskCount={}, expectedTaskKeys={}", instance.getBusinessNo(), instance.getId(), tasks.size(), List.of(taskKeys));
|
||||||
|
for (ProcessTask task : tasks) {
|
||||||
|
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(task.getId());
|
||||||
|
log.info("[特殊慰问导出] 审批记录,instanceId={}, taskId={}, taskKey={}, displayName={}, state={}, finishTime={}, isFirstTaskNode={}, matchedApproval={}", instance.getId(), task.getId(), task.getTaskName(), task.getDisplayName(), task.getTaskState(), task.getFinishTime(), taskVO.getExt() == null ? null : taskVO.getExt().get("isFirstTaskNode"), List.of(taskKeys).contains(task.getTaskName()));
|
||||||
|
if ("startTask".equals(task.getTaskName()) || (!List.of(taskKeys).contains(task.getTaskName())
|
||||||
|
&& taskVO.getExt() != null && Boolean.TRUE.equals(taskVO.getExt().getBool("isFirstTaskNode")))) {
|
||||||
|
log.info("[特殊慰问导出] 申请节点重置本轮审批字段,instanceId={}, taskId={}, taskKey={}", instance.getId(), task.getId(), task.getTaskName());
|
||||||
|
// 重新申请后,仅导出本轮审批记录。
|
||||||
|
for (String field : fields) {
|
||||||
|
for (String suffix : suffixes) docData.put(field + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < taskKeys.length; i++) {
|
||||||
|
if (!taskKeys[i].equals(task.getTaskName())) continue;
|
||||||
|
for (String suffix : suffixes) docData.put(fields[i] + suffix, "Sign".equals(suffix) ? null : "");
|
||||||
|
if (!ProcessTaskStateEnum.FINISHED.getCode().equals(task.getTaskState())) {
|
||||||
|
log.info("[特殊慰问导出] 跳过未完成审批,instanceId={}, taskId={}, field={}, state={}", instance.getId(), task.getId(), fields[i], task.getTaskState());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Dict data = taskVO.getExt() == null ? Dict.create() : taskVO.getTaskFormData();
|
||||||
|
log.info("[特殊慰问导出] 读取审批表单,instanceId={}, taskId={}, field={}, formKeys={}, signPresent={}, signReferenceLength={}", instance.getId(), task.getId(), fields[i], data.keySet(), StrUtil.isNotBlank(data.getStr("sign")), StrUtil.nullToEmpty(data.getStr("sign")).length());
|
||||||
|
if (StrUtil.isBlank(data.getStr("sign"))) log.warn("[特殊慰问导出] 已完成审批缺少签名字段,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i]);
|
||||||
|
docData.put(fields[i] + "Opinion", StrUtil.nullToEmpty(data.getStr("opinion")));
|
||||||
|
if (StrUtil.isNotBlank(data.getStr("sign"))) {
|
||||||
|
PictureRenderData signature = sysOfficeTemplateUtil.createPictureRenderData(90, 40, data.getStr("sign"));
|
||||||
|
if (signature == null) throw new BaseException("审批签字图片读取失败");
|
||||||
|
docData.put(fields[i] + "Sign", signature);
|
||||||
|
log.info("[特殊慰问导出] 审批签名填充完成,instanceId={}, taskId={}, field={}", instance.getId(), task.getId(), fields[i] + "Sign");
|
||||||
|
}
|
||||||
|
docData.put(fields[i] + "Year", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "yyyy"));
|
||||||
|
docData.put(fields[i] + "Month", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "M"));
|
||||||
|
docData.put(fields[i] + "Day", task.getFinishTime() == null ? "" : DateUtil.format(task.getFinishTime(), "d"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("删除")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
@SaCheckPermission(value = {"special_condolence.mine", "h5.special_condolence.mine"}, mode = SaMode.OR)
|
||||||
|
@SLog(tag = "特殊慰问系统-我的申请", msg = "删除特殊慰问")
|
||||||
|
public Result delete(@Param("id") String id) {
|
||||||
|
specialcondolenceService.deleteApplication(id);
|
||||||
|
flowEngine.processInstanceService().deleteProcessInstanceByBusinessKey(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("查询单个慰问申请信息")
|
||||||
|
@SaCheckPermission(value = {"special_condolence", "h5.special_condolence"}, mode = SaMode.OR)
|
||||||
|
public Result info(String id) {
|
||||||
|
SpecialCondolence specialcondolence = specialcondolenceService.loadApplication(id);
|
||||||
|
SpecialCondolenceType type = specialcondolenceService.dao().fetch(SpecialCondolenceType.class, Cnd.where(SpecialCondolenceType::getId, "=", specialcondolence.getType()));
|
||||||
|
NutMap nutMap = Lang.obj2nutmap(specialcondolence);
|
||||||
|
nutMap.put("typeName", type == null ? "" : type.getName());
|
||||||
|
return Result.success(nutMap);
|
||||||
|
}
|
||||||
|
@Inject
|
||||||
|
private SmsService smsService;
|
||||||
|
}
|
||||||
+180
@@ -0,0 +1,180 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.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.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.ProcessInstanceStateEnum;
|
||||||
|
import com.budwk.app.sys.param.SysMsgSummaryPageForm;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
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;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
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 SpecialCondolenceReadController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 16:25
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@IocBean
|
||||||
|
@Ok("json:full")
|
||||||
|
@Api(tags = "特殊慰问阅览")
|
||||||
|
@At("/platform/special_condolence/read")
|
||||||
|
public class SpecialCondolenceReadController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
|
||||||
|
@At("")
|
||||||
|
@SaCheckPermission("special_condolence.read")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/read/index.html")
|
||||||
|
public void index() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission("special_condolence.read")
|
||||||
|
public Result pageData(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type,
|
||||||
|
@Param(value = "unionId") String unionId,
|
||||||
|
@Param(value = "unitId") String unitId) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
(SELECT COUNT(*) FROM special_condolence_recipient recipient WHERE recipient.applyId = info.id AND recipient.delFlag = false) AS recipientCount,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
type.name as typeName,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.displayName taskName
|
||||||
|
FROM
|
||||||
|
special_condolence info
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
processInstanceId,
|
||||||
|
displayName,
|
||||||
|
createdAt,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY processInstanceId ORDER BY createdAt DESC) AS rn
|
||||||
|
FROM wf_process_task
|
||||||
|
) t ON t.processInstanceId = ins.id AND t.rn = 1
|
||||||
|
LEFT JOIN special_condolence_type type ON info.type = type.id
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||||
|
cnd.andEX("info.type", "=", type);
|
||||||
|
cnd.andEX("YEAR(info.createTime)", "=", year);
|
||||||
|
cnd.andEX("info.applyUnionId", "=", unionId);
|
||||||
|
cnd.andEX("info.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 (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||||
|
cnd.desc("info.createTime");
|
||||||
|
} else {
|
||||||
|
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||||
|
}
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination<NutMap> pageVO = specialcondolenceService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
return Result.success(pageVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@Ok("void")
|
||||||
|
@SaCheckPermission("special_condolence.read")
|
||||||
|
@ApiOperation("导出特殊慰问汇总表")
|
||||||
|
public void onExport(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type,
|
||||||
|
@Param(value = "unionId") String unionId,
|
||||||
|
@Param(value = "unitId") String unitId,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
//查询审核通过的数据
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
select
|
||||||
|
con.subject,
|
||||||
|
case when recipient.id is null then con.helpUserName else recipient.helpUserName end as helpUserName,
|
||||||
|
case when recipient.id is null then con.helpLoginName else recipient.helpLoginName end as helpLoginName,
|
||||||
|
con.applyUserName,
|
||||||
|
con.helpUnionName,
|
||||||
|
con.helpUnitName,
|
||||||
|
case when recipient.id is null then type.name else recipient.typeName end as typeName,
|
||||||
|
case when recipient.id is null then con.money else recipient.money end as money,
|
||||||
|
con.remark
|
||||||
|
from
|
||||||
|
special_condolence con
|
||||||
|
left join special_condolence_recipient recipient on recipient.applyId = con.id and recipient.delFlag = false
|
||||||
|
left join wf_process_instance ins on ins.businessNo = con.id
|
||||||
|
left join special_condolence_type type on type.id = con.type
|
||||||
|
$condition
|
||||||
|
order by con.createTime desc, con.id, recipient.sortNum, recipient.id
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||||
|
cnd.andEX("con.type", "=", type);
|
||||||
|
cnd.andEX("YEAR(con.createTime)", "=", year);
|
||||||
|
cnd.andEX("con.applyUnionId", "=", unionId);
|
||||||
|
cnd.andEX("con.applyUnitId", "=", unitId);
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or("con.helpUserName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or("con.helpLoginName", "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
List<NutMap> list = specialcondolenceService.listMap(sql);
|
||||||
|
|
||||||
|
List<ExcelExportEntity> exportEntities = new ArrayList<>();
|
||||||
|
exportEntities.add(new ExcelExportEntity("事项", "subject", 30));
|
||||||
|
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));
|
||||||
|
|
||||||
|
ExportParams exportParams = new ExportParams();
|
||||||
|
exportParams.setType(ExcelType.XSSF);
|
||||||
|
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list);
|
||||||
|
CommonDownloadUtil.download("申报人汇总.xlsx", workbook, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
+140
@@ -0,0 +1,140 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
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.PageUtil;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Sqls;
|
||||||
|
import org.nutz.dao.sql.Sql;
|
||||||
|
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||||
|
import org.nutz.dao.util.cri.Static;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhf
|
||||||
|
* @date 2025/12/23 14:13
|
||||||
|
* @description 校工会预审
|
||||||
|
*/
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/special_condolence/schoolPrincipalApproval")
|
||||||
|
@Api("特殊慰问二级审核")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class SpecialCondolenceSecondApprovalController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
|
||||||
|
@At("/")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/schoolPrincipalApproval/index.html")
|
||||||
|
@SaCheckPermission("special_condolence.secondApproval")
|
||||||
|
public void index() {}
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/staffbenefit/specialcondolence/schoolPrincipalApproval/index.html")
|
||||||
|
@SaCheckPermission("h5.special_condolence.secondApproval")
|
||||||
|
public void h5Index() {}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.secondApproval", "h5.special_condolence.secondApproval"}, mode = SaMode.OR)
|
||||||
|
public Result pageData(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type,
|
||||||
|
@Param(value = "unionId") String unionId,
|
||||||
|
@Param(value = "unitId") String unitId,
|
||||||
|
@Param(value = "approval") Boolean approval) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
COALESCE(recipientTotals.recipientCount, 0) AS recipientCount,
|
||||||
|
type.name as typeName,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
ins.businessNo,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.variable instanceVariable,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.id taskId,
|
||||||
|
t.taskName AS taskKey,
|
||||||
|
t.displayName taskName,
|
||||||
|
t.taskType,
|
||||||
|
t.performType taskPerformType,
|
||||||
|
t.taskState,
|
||||||
|
t.finishTime,
|
||||||
|
t.taskParentId,
|
||||||
|
t.variable taskVariable,
|
||||||
|
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||||
|
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
LEFT JOIN special_condolence info ON info.id = ins.businessNo
|
||||||
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT applyId, COUNT(*) AS recipientCount
|
||||||
|
FROM special_condolence_recipient
|
||||||
|
WHERE delFlag = false
|
||||||
|
GROUP BY applyId
|
||||||
|
) recipientTotals ON recipientTotals.applyId = info.id
|
||||||
|
LEFT JOIN special_condolence_type type ON info.type = type.id
|
||||||
|
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||||
|
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("info.id", "is not", null);
|
||||||
|
cnd.and(new Static("""
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_task newer
|
||||||
|
WHERE newer.processInstanceId = t.processInstanceId
|
||||||
|
AND newer.taskName = t.taskName
|
||||||
|
AND newer.id > t.id
|
||||||
|
)
|
||||||
|
"""));
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(SpecialCondolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or(SpecialCondolence::getHelpLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
cnd.andEX("info.type", "=", type);
|
||||||
|
cnd.andEX("YEAR(info.createTime)", "=", year);
|
||||||
|
cnd.andEX("info.applyUnionId", "=", unionId);
|
||||||
|
cnd.andEX("info.applyUnitId", "=", unitId);
|
||||||
|
|
||||||
|
cnd.and("t.taskName", "=", "c438972e-2f67-4907-b229-cb7aa17da147");
|
||||||
|
// cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||||
|
|
||||||
|
if (approval) {
|
||||||
|
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||||
|
} else {
|
||||||
|
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||||
|
cnd.desc("info.createTime");
|
||||||
|
} else {
|
||||||
|
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||||
|
}
|
||||||
|
cnd.groupBy("t.id");
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination<NutMap> pageVO = specialcondolenceService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
return Result.success(pageVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
+144
@@ -0,0 +1,144 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaMode;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
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.PageUtil;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Sqls;
|
||||||
|
import org.nutz.dao.sql.Sql;
|
||||||
|
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||||
|
import org.nutz.dao.util.cri.Static;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
import org.nutz.mvc.annotation.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceThirdApprovalController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 16:23
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@IocBean
|
||||||
|
@At("/platform/special_condolence/schoolUnionApproval")
|
||||||
|
@Api("特殊慰问三级审核")
|
||||||
|
@Ok("json:full")
|
||||||
|
public class SpecialCondolenceThirdApprovalController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceService specialcondolenceService;
|
||||||
|
|
||||||
|
@At("/")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/schoolUnionApproval/index.html")
|
||||||
|
@SaCheckPermission("special_condolence.thirdApproval")
|
||||||
|
public void index() {}
|
||||||
|
|
||||||
|
@At("/h5")
|
||||||
|
@Ok("beetl:/platform/zhghh5/staffbenefit/specialcondolence/schoolUnionApproval/index.html")
|
||||||
|
@SaCheckPermission("h5.special_condolence.thirdApproval")
|
||||||
|
public void h5Index() {}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission(value = {"special_condolence.thirdApproval", "h5.special_condolence.thirdApproval"}, mode = SaMode.OR)
|
||||||
|
public Result pageData(PageForm pageForm,
|
||||||
|
@Param(value = "year") Integer year,
|
||||||
|
@Param(value = "type") String type,
|
||||||
|
@Param(value = "unionId") String unionId,
|
||||||
|
@Param(value = "unitId") String unitId,
|
||||||
|
@Param(value = "approval") Boolean approval) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.*,
|
||||||
|
COALESCE(recipientTotals.recipientCount, 0) AS recipientCount,
|
||||||
|
type.name as typeName,
|
||||||
|
ins.id AS instanceId,
|
||||||
|
ins.businessNo,
|
||||||
|
ins.state instanceState,
|
||||||
|
ins.variable instanceVariable,
|
||||||
|
ins.processDefineId instanceProcessDefineId,
|
||||||
|
t.id taskId,
|
||||||
|
t.taskName AS taskKey,
|
||||||
|
t.displayName taskName,
|
||||||
|
t.taskType,
|
||||||
|
t.performType taskPerformType,
|
||||||
|
t.taskState,
|
||||||
|
t.finishTime,
|
||||||
|
t.taskParentId,
|
||||||
|
t.variable taskVariable,
|
||||||
|
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||||
|
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
LEFT JOIN special_condolence info ON info.id = ins.businessNo
|
||||||
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT applyId, COUNT(*) AS recipientCount
|
||||||
|
FROM special_condolence_recipient
|
||||||
|
WHERE delFlag = false
|
||||||
|
GROUP BY applyId
|
||||||
|
) recipientTotals ON recipientTotals.applyId = info.id
|
||||||
|
LEFT JOIN special_condolence_type type ON info.type = type.id
|
||||||
|
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||||
|
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
cnd.and("info.id", "is not", null);
|
||||||
|
cnd.and(new Static("""
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1 FROM wf_process_task newer
|
||||||
|
WHERE newer.processInstanceId = t.processInstanceId
|
||||||
|
AND newer.taskName = t.taskName
|
||||||
|
AND newer.id > t.id
|
||||||
|
)
|
||||||
|
"""));
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(SpecialCondolence::getHelpUserName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or(SpecialCondolence::getHelpLoginName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
cnd.andEX("info.type", "=", type);
|
||||||
|
cnd.andEX("YEAR(info.createTime)", "=", year);
|
||||||
|
cnd.andEX("info.applyUnionId", "=", unionId);
|
||||||
|
cnd.andEX("info.applyUnitId", "=", unitId);
|
||||||
|
|
||||||
|
cnd.and("t.taskName", "=", "7f560675-aeea-4254-a57e-957d03d6b786");
|
||||||
|
if (!"superadmin".equals(SecurityUtil.getUserLoginname())) {
|
||||||
|
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (approval) {
|
||||||
|
cnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.INTERRUPT.getCode()));
|
||||||
|
} else {
|
||||||
|
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||||
|
cnd.desc("info.createTime");
|
||||||
|
} else {
|
||||||
|
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||||
|
}
|
||||||
|
cnd.groupBy("t.id");
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
Pagination<NutMap> pageVO = specialcondolenceService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
return Result.success(pageVO);
|
||||||
|
}
|
||||||
|
}
|
||||||
+91
@@ -0,0 +1,91 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.controller;
|
||||||
|
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||||
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.base.annotation.SLog;
|
||||||
|
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.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceType;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceTypeService;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||||
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
import org.nutz.mvc.annotation.At;
|
||||||
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceTypeController
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 10:00
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@IocBean
|
||||||
|
@Ok("json:full")
|
||||||
|
@Api(tags = "特殊慰问类型")
|
||||||
|
@At("/platform/special_condolence/type")
|
||||||
|
public class SpecialCondolenceTypeController {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Dao dao;
|
||||||
|
@Inject
|
||||||
|
private SpecialCondolenceTypeService typeService;
|
||||||
|
|
||||||
|
@At("")
|
||||||
|
@SaCheckPermission("special_condolence.type")
|
||||||
|
@Ok("beetl:/platform/zhgh/staffbenefit/specialcondolence/type/index.html")
|
||||||
|
public void index() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("分页查询")
|
||||||
|
@SaCheckPermission("special_condolence.type")
|
||||||
|
public Result pageData(PageForm pageForm) {
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||||
|
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||||
|
seg.or(SpecialCondolenceType::getName, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
seg.or(SpecialCondolenceType::getCode, "like", "%" + pageForm.getSearchKeyword() + "%");
|
||||||
|
cnd.and(seg);
|
||||||
|
}
|
||||||
|
cnd.asc("code");
|
||||||
|
Pagination pagination = typeService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), cnd);
|
||||||
|
return Result.success(pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("新增/修改特殊慰问类型")
|
||||||
|
@SaCheckPermission("special_condolence.type")
|
||||||
|
@SLog(tag = "特殊慰问系统-慰问类型", msg = "新增/修改特殊慰问类型")
|
||||||
|
public Object onSubmit(SpecialCondolenceType type) {
|
||||||
|
typeService.insertOrUpdate(type);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("删除特殊慰问类型")
|
||||||
|
@SaCheckPermission("special_condolence.type")
|
||||||
|
@SLog(tag = "特殊慰问系统-慰问类型", msg = "删除特殊慰问类型")
|
||||||
|
public Object onDelete(String id) {
|
||||||
|
typeService.delete(id);
|
||||||
|
return Result.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@ApiOperation("查询特殊慰问类型")
|
||||||
|
@SaCheckLogin
|
||||||
|
public Result querySpecialCondolenceType() {
|
||||||
|
List<SpecialCondolenceType> list = typeService.query(Cnd.where(SpecialCondolenceType::getEnable, "=", true).asc(SpecialCondolenceType::getCode));
|
||||||
|
return Result.success(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.interceptor;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.budwk.app.flow.constant.FlowConst;
|
||||||
|
import com.budwk.app.flow.engine.FlowInterceptor;
|
||||||
|
import com.budwk.app.flow.engine.core.Execution;
|
||||||
|
import com.budwk.app.flow.engine.core.ServiceContext;
|
||||||
|
import com.budwk.app.flow.entity.ProcessInstance;
|
||||||
|
import com.budwk.app.zhgh.dayofficework.article.models.Article;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import org.nutz.dao.Chain;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.json.Json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceSaveInterceptor
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/28 11:01
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
public class SpecialCondolenceSaveInterceptor implements FlowInterceptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void intercept(Execution execution) {
|
||||||
|
if (!com.budwk.app.web.commons.auth.utils.AuthUtil.hasRoleOr("BRANCH_UNION_CHAIRMAN")) {
|
||||||
|
throw new com.budwk.app.base.exception.BaseException("仅分工会主席可发起特殊慰问申请");
|
||||||
|
}
|
||||||
|
String formDataStr = execution.getArgs().getStr(FlowConst.FORM_DATA);
|
||||||
|
SpecialCondolence specialcondolence = Json.fromJson(SpecialCondolence.class, formDataStr);
|
||||||
|
|
||||||
|
if(StrUtil.isBlank(specialcondolence.getId())) specialcondolence.setCreateTime(DateUtil.now());
|
||||||
|
|
||||||
|
Dao dao = ServiceContext.find(Dao.class);
|
||||||
|
ServiceContext.find(com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService.class).saveApplication(specialcondolence);
|
||||||
|
|
||||||
|
// 设置流程变量
|
||||||
|
execution.getArgs().set("origin", specialcondolence.getOrigin());
|
||||||
|
|
||||||
|
int instanceId = execution.getArgs().getInt(FlowConst.PROCESS_INSTANCE_ID_KEY);
|
||||||
|
dao.update(ProcessInstance.class, Chain.make("businessNo", specialcondolence.getId()), Cnd.where(ProcessInstance::getId, "=", instanceId));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+310
@@ -0,0 +1,310 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.model;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.budwk.app.base.model.BaseModel;
|
||||||
|
import com.budwk.app.sys.models.Sys_file;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.nutz.dao.entity.annotation.*;
|
||||||
|
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolence
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/28 11:03
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("special_condolence")
|
||||||
|
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||||
|
@Comment("特殊慰问")
|
||||||
|
public class SpecialCondolence extends BaseModel {
|
||||||
|
|
||||||
|
@Name
|
||||||
|
@Comment("ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
@PrevInsert(uu32 = true)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("事项")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 200)
|
||||||
|
private String subject;
|
||||||
|
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String applyUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String applyUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
|
private String applyLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人分工会ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String applyUnionId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人分工会")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String applyUnionName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人单位ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String applyUnitId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请人单位")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String applyUnitName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String helpUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String helpUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
|
private String helpLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人分工会ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String helpUnionId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人分工会")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String helpUnionName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人单位ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String helpUnitId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补助人单位")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String helpUnitName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("类型")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String origin;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("收款人")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String payUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("收款人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String payUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("收款人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String payLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问类型")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问编码")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String typeCode;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问方式")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String way;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("统一每人慰问金额")
|
||||||
|
@ColDefine(customType = "decimal(10,2)")
|
||||||
|
private java.math.BigDecimal perMoney;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问金额")
|
||||||
|
@ColDefine(type = ColType.FLOAT, width = 10, precision = 2)
|
||||||
|
private Double money;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("发生时间")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String occurTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("生育几孩(孩次)")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 10)
|
||||||
|
private String child;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("所在医院")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String hospital;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("病房床号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String hospitalHouseNum;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("病房床号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String hospitalHouseBedNum;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("住院病由")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String hospitalBy;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("备注")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("附件")
|
||||||
|
@ColDefine(type = ColType.MYSQL_JSON)
|
||||||
|
private List<JSONObject> files;
|
||||||
|
|
||||||
|
@Comment("签字")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||||
|
@Column(hump = true)
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请时间")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String createTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("户名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String bankUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("银行账号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String bankCardNumber;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("开户行")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String bankOfDeposit;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String certifierUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String certifierUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
|
private String certifierLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人分工会ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String certifierUnionId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人分工会")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String certifierUnionName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人单位ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String certifierUnitId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("证明人单位")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String certifierUnitName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String handlerUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String handlerUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
|
private String handlerLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人分工会ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String handlerUnionId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人分工会")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String handlerUnionName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人单位ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String handlerUnitId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("经办人单位")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String handlerUnitName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("入院时间")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String hospitalizationTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("出院时间")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String leaveHospitalTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("当年第几次住院")
|
||||||
|
@ColDefine(type = ColType.INT)
|
||||||
|
private Integer thisYearHospitalizationNum;
|
||||||
|
|
||||||
|
@Comment("慰问对象明细,由明细表加载")
|
||||||
|
private List<JSONObject> recipients;
|
||||||
|
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.model;
|
||||||
|
|
||||||
|
import com.budwk.app.base.model.BaseModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.nutz.dao.entity.annotation.*;
|
||||||
|
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("special_condolence_recipient")
|
||||||
|
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||||
|
@TableIndexes({@Index(name = "idx_special_condolence_recipient_apply", fields = {"applyId"}, unique = false)})
|
||||||
|
@Comment("特殊慰问被申请人明细")
|
||||||
|
public class SpecialCondolenceRecipient extends BaseModel {
|
||||||
|
@Name
|
||||||
|
@PrevInsert(uu32 = true)
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("申请ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String applyId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问对象用户ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String helpUserId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("人员类型")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String personType;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问对象工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 120)
|
||||||
|
private String helpLoginName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问对象")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String helpUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问类型ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问类型名称")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String typeName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问类型编码")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String typeCode;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问方式")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String way;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("身份证号码")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 18)
|
||||||
|
private String idCard;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("开户行")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String bankOfDeposit;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("户名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String bankUserName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("收款账户")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String bankCardNumber;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问金额")
|
||||||
|
@ColDefine(customType = "decimal(10,2)")
|
||||||
|
private java.math.BigDecimal money;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问时间")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String occurTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("行序号")
|
||||||
|
@ColDefine(type = ColType.INT)
|
||||||
|
private Integer sortNum;
|
||||||
|
}
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.model;
|
||||||
|
|
||||||
|
import com.budwk.app.base.model.BaseModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.nutz.dao.DB;
|
||||||
|
import org.nutz.dao.entity.annotation.*;
|
||||||
|
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceType
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 9:59
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("special_condolence_type")
|
||||||
|
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||||
|
@Comment("特殊慰问类型")
|
||||||
|
public class SpecialCondolenceType extends BaseModel {
|
||||||
|
|
||||||
|
@Name
|
||||||
|
@Comment("ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
@PrevInsert(uu32 = true)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("编码")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 30)
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("名称")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("费用")
|
||||||
|
@ColDefine(type = ColType.FLOAT, width = 10, precision = 2)
|
||||||
|
private Double money;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("慰问方式")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String way;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("是否启用")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
@Default("1")
|
||||||
|
private Boolean enable;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("是否上传附件")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
private Boolean isUploadFile;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("上传附件说明")
|
||||||
|
@ColDefine(type = ColType.VARCHAR,width = 50)
|
||||||
|
private String uploadFileDesc;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("排序字段")
|
||||||
|
@Prev({
|
||||||
|
@SQL(db = DB.MYSQL, value = "SELECT IFNULL(MAX(location),0)+1 FROM special_condolence_type"),
|
||||||
|
@SQL(db = DB.ORACLE, value = "SELECT COALESCE(MAX(location),0)+1 FROM special_condolence_type")
|
||||||
|
})
|
||||||
|
private Integer location;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("排序")
|
||||||
|
@ColDefine(type = ColType.INT)
|
||||||
|
private int sortNum;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("上传会议纪要")
|
||||||
|
@Default("0")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
private Boolean uploadMeetingRecord;
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.service;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.budwk.app.base.exception.BaseException;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceType;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class SpecialCondolenceRecipients {
|
||||||
|
private SpecialCondolenceRecipients() {}
|
||||||
|
|
||||||
|
public static void prepare(SpecialCondolence info, Dao dao) {
|
||||||
|
if (info.getSubject() == null || info.getSubject().trim().isEmpty() || info.getSubject().trim().length() > 200) throw new BaseException("请填写200字以内的事项");
|
||||||
|
info.setSubject(info.getSubject().trim());
|
||||||
|
List<JSONObject> rows = info.getRecipients();
|
||||||
|
if (rows == null || rows.isEmpty()) throw new BaseException("请添加慰问对象");
|
||||||
|
if (rows.size() > 1000) throw new BaseException("每次申请最多1000人");
|
||||||
|
if (info.getFiles() != null && info.getFiles().size() > 5) throw new BaseException("最多上传5个附件");
|
||||||
|
if (info.getRemark() != null && info.getRemark().trim().length() > 500) throw new BaseException("申请事由最多500字");
|
||||||
|
if (info.getPerMoney() == null || info.getPerMoney().signum() <= 0 || info.getPerMoney().compareTo(new BigDecimal("10000")) > 0 || info.getPerMoney().scale() > 2) throw new BaseException("每人慰问金额须大于0且不超过10000元,最多两位小数");
|
||||||
|
try { LocalDate.parse(info.getOccurTime()); }
|
||||||
|
catch (Exception e) { throw new BaseException("请选择有效的统一慰问时间"); }
|
||||||
|
BigDecimal total = BigDecimal.ZERO;
|
||||||
|
for (int i = 0; i < rows.size(); i++) {
|
||||||
|
JSONObject row = rows.get(i);
|
||||||
|
String prefix = "第" + (i + 1) + "行:";
|
||||||
|
if (row == null) throw new BaseException(prefix + "明细不能为空");
|
||||||
|
row.set("type", info.getType());
|
||||||
|
row.set("money", info.getPerMoney().toPlainString());
|
||||||
|
row.set("occurTime", info.getOccurTime());
|
||||||
|
if (cn.hutool.core.util.StrUtil.isNotBlank(row.getStr("helpUserId"))) resolveUser(row, dao, prefix);
|
||||||
|
String[] fields = {"helpUserName", "type", "idCard", "bankOfDeposit", "bankUserName", "bankCardNumber", "money", "occurTime"};
|
||||||
|
for (String field : fields) {
|
||||||
|
String value = row.getStr(field);
|
||||||
|
if (value == null || value.trim().isEmpty()) throw new BaseException(prefix + "请填写完整的慰问对象信息");
|
||||||
|
row.set(field, value.trim());
|
||||||
|
}
|
||||||
|
if (!validIdCard(row.getStr("idCard"))) throw new BaseException(prefix + "身份证号码不正确");
|
||||||
|
if (!row.getStr("bankCardNumber").matches("[0-9]{6,30}")) throw new BaseException(prefix + "收款账户须为6至30位数字");
|
||||||
|
if (row.getStr("helpUserName").length() > 100 || row.getStr("bankOfDeposit").length() > 100 || row.getStr("bankUserName").length() > 100) throw new BaseException(prefix + "姓名、开户行、户名不能超过100字");
|
||||||
|
if (!row.getStr("money").matches("[0-9]+(\\.[0-9]{1,2})?")) throw new BaseException(prefix + "金额最多两位小数");
|
||||||
|
BigDecimal money = new BigDecimal(row.getStr("money"));
|
||||||
|
if (money.signum() <= 0 || money.compareTo(new BigDecimal("10000")) > 0) throw new BaseException(prefix + "金额须大于0且不超过10000元");
|
||||||
|
try { LocalDate.parse(row.getStr("occurTime")); }
|
||||||
|
catch (Exception e) { throw new BaseException(prefix + "慰问时间格式须为yyyy-MM-dd"); }
|
||||||
|
SpecialCondolenceType type = dao.fetch(SpecialCondolenceType.class, row.getStr("type"));
|
||||||
|
if (type == null || !Boolean.TRUE.equals(type.getEnable())) throw new BaseException(prefix + "慰问类型不存在或已停用");
|
||||||
|
row.set("typeName", type.getName());
|
||||||
|
row.set("typeCode", type.getCode());
|
||||||
|
row.set("way", type.getWay());
|
||||||
|
if (Boolean.TRUE.equals(type.getIsUploadFile()) && (info.getFiles() == null || info.getFiles().isEmpty())) throw new BaseException(prefix + "该慰问类型需要上传附件");
|
||||||
|
total = total.add(money);
|
||||||
|
}
|
||||||
|
JSONObject first = rows.get(0);
|
||||||
|
String name = first.getStr("helpUserName");
|
||||||
|
info.setHelpUserName((rows.size() > 1 && name.length() > 90 ? name.substring(0, 90) : name) + (rows.size() > 1 ? "等" + rows.size() + "人" : ""));
|
||||||
|
info.setHelpUnitId(info.getApplyUnitId());
|
||||||
|
info.setHelpUnitName(info.getApplyUnitName());
|
||||||
|
info.setHelpUnionId(info.getApplyUnionId());
|
||||||
|
info.setHelpUnionName(info.getApplyUnionName());
|
||||||
|
info.setType(first.getStr("type"));
|
||||||
|
info.setTypeCode(first.getStr("typeCode"));
|
||||||
|
info.setWay(first.getStr("way"));
|
||||||
|
info.setOccurTime(first.getStr("occurTime"));
|
||||||
|
info.setMoney(total.doubleValue());
|
||||||
|
info.setBankOfDeposit(first.getStr("bankOfDeposit"));
|
||||||
|
info.setBankUserName(first.getStr("bankUserName"));
|
||||||
|
info.setBankCardNumber(first.getStr("bankCardNumber"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resolveUser(JSONObject row, Dao dao, String prefix) {
|
||||||
|
String userId = row.getStr("helpUserId");
|
||||||
|
com.budwk.app.sys.views.View_user user;
|
||||||
|
String unionId = com.budwk.app.web.commons.auth.utils.SecurityUtil.getUnionId();
|
||||||
|
if (cn.hutool.core.util.StrUtil.isBlank(unionId)) throw new BaseException(prefix + "申请人未关联分工会");
|
||||||
|
if (cn.hutool.core.util.StrUtil.isNotBlank(userId)) {
|
||||||
|
user = dao.fetch(com.budwk.app.sys.views.View_user.class, org.nutz.dao.Cnd.where("id", "=", userId));
|
||||||
|
} else {
|
||||||
|
java.util.List<com.budwk.app.sys.views.View_user> users = dao.query(com.budwk.app.sys.views.View_user.class,
|
||||||
|
org.nutz.dao.Cnd.where("idCard", "=", row.getStr("idCard"))
|
||||||
|
.and("username", "=", row.getStr("helpUserName")));
|
||||||
|
if (users.isEmpty()) throw new BaseException(prefix + "姓名、身份证与人员档案不匹配");
|
||||||
|
java.util.List<com.budwk.app.sys.views.View_user> members = users.stream()
|
||||||
|
.filter(member -> java.util.Objects.equals(member.getUnionId(), unionId))
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
if (members.isEmpty()) throw new BaseException(prefix + "只能选择申请人本工会人员");
|
||||||
|
String loginName = row.getStr("helpLoginName");
|
||||||
|
if (cn.hutool.core.util.StrUtil.isNotBlank(loginName)) {
|
||||||
|
members = members.stream().filter(member -> "劳务派遣人员".equals(member.getPersonType())
|
||||||
|
|| java.util.Objects.equals(member.getLoginname(), loginName))
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
}
|
||||||
|
if (members.isEmpty()) throw new BaseException(prefix + "工号与慰问对象不一致");
|
||||||
|
if (members.size() > 1) throw new BaseException(prefix + "人员身份重复,请核对档案");
|
||||||
|
user = members.get(0);
|
||||||
|
}
|
||||||
|
if (user == null) throw new BaseException(prefix + "慰问对象不存在");
|
||||||
|
if (!java.util.Objects.equals(user.getUnionId(), unionId)) throw new BaseException(prefix + "只能选择申请人本工会人员");
|
||||||
|
if (!"劳务派遣人员".equals(user.getPersonType()) && cn.hutool.core.util.StrUtil.isBlank(row.getStr("helpLoginName"))) throw new BaseException(prefix + "普通人员必须填写工号");
|
||||||
|
if (!"劳务派遣人员".equals(user.getPersonType()) && (cn.hutool.core.util.StrUtil.isBlank(row.getStr("helpLoginName")) || !java.util.Objects.equals(user.getLoginname(), row.getStr("helpLoginName")))) throw new BaseException(prefix + "工号与慰问对象不一致");
|
||||||
|
if (cn.hutool.core.util.StrUtil.isNotBlank(user.getIdCard()) && !user.getIdCard().equalsIgnoreCase(row.getStr("idCard"))) throw new BaseException(prefix + "身份证号码与所选人员不一致");
|
||||||
|
row.set("helpUserId", user.getId());
|
||||||
|
row.set("helpLoginName", user.getLoginname());
|
||||||
|
row.set("personType", user.getPersonType());
|
||||||
|
row.set("helpUserName", user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validIdCard(String value) {
|
||||||
|
if (value == null || !value.matches("[1-9][0-9]{16}[0-9Xx]")) return false;
|
||||||
|
try { LocalDate.parse(value.substring(6, 14), java.time.format.DateTimeFormatter.BASIC_ISO_DATE); }
|
||||||
|
catch (Exception e) { return false; }
|
||||||
|
int[] weights = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < weights.length; i++) sum += (value.charAt(i) - '0') * weights[i];
|
||||||
|
return "10X98765432".charAt(sum % 11) == Character.toUpperCase(value.charAt(17));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.service;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceService
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 11:21
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
public interface SpecialCondolenceService extends BaseService<SpecialCondolence> {
|
||||||
|
void saveApplication(SpecialCondolence info);
|
||||||
|
void saveDraftApplication(SpecialCondolence info);
|
||||||
|
SpecialCondolence loadApplication(String id);
|
||||||
|
void deleteApplication(String id);
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.service;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceTypeService
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 10:03
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
public interface SpecialCondolenceTypeService extends BaseService<SpecialCondolenceType> {
|
||||||
|
}
|
||||||
+110
@@ -0,0 +1,110 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.service.impl;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceRecipient;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceRecipients;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import org.nutz.ioc.aop.Aop;
|
||||||
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
|
import org.nutz.dao.Cnd;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolence;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceServiceImpl
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 11:22
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@IocBean(args = {"refer:dao"})
|
||||||
|
public class SpecialCondolenceServiceImpl extends BaseServiceImpl<SpecialCondolence> implements SpecialCondolenceService {
|
||||||
|
|
||||||
|
public SpecialCondolenceServiceImpl(Dao dao) {
|
||||||
|
super(dao);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public void saveApplication(SpecialCondolence info) {
|
||||||
|
SpecialCondolenceRecipients.prepare(info, dao());
|
||||||
|
persistApplication(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public void saveDraftApplication(SpecialCondolence info) {
|
||||||
|
if (info.getRecipients() == null) info.setRecipients(new ArrayList<>());
|
||||||
|
info.getRecipients().removeIf(row -> row == null || java.util.stream.Stream.of(
|
||||||
|
"helpUserId", "helpUserName", "helpLoginName", "idCard", "bankOfDeposit", "bankUserName", "bankCardNumber")
|
||||||
|
.allMatch(field -> StrUtil.isBlank(row.getStr(field))));
|
||||||
|
for (JSONObject row : info.getRecipients()) {
|
||||||
|
row.set("type", info.getType());
|
||||||
|
row.set("typeCode", info.getTypeCode());
|
||||||
|
row.set("way", info.getWay());
|
||||||
|
row.set("money", info.getPerMoney());
|
||||||
|
row.set("occurTime", info.getOccurTime());
|
||||||
|
}
|
||||||
|
info.setMoney(info.getPerMoney() == null ? null : info.getPerMoney().multiply(BigDecimal.valueOf(info.getRecipients().size())).doubleValue());
|
||||||
|
persistApplication(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void persistApplication(SpecialCondolence info) {
|
||||||
|
dao().insertOrUpdate(info);
|
||||||
|
dao().clear(SpecialCondolenceRecipient.class,
|
||||||
|
Cnd.where("applyId", "=", info.getId()));
|
||||||
|
int sort = 0;
|
||||||
|
for (JSONObject row : info.getRecipients()) {
|
||||||
|
SpecialCondolenceRecipient person = new SpecialCondolenceRecipient();
|
||||||
|
person.setApplyId(info.getId());
|
||||||
|
person.setHelpUserName(row.getStr("helpUserName", ""));
|
||||||
|
person.setHelpUserId(row.getStr("helpUserId", ""));
|
||||||
|
person.setHelpLoginName(row.getStr("helpLoginName"));
|
||||||
|
person.setPersonType(row.getStr("personType"));
|
||||||
|
person.setType(row.getStr("type", ""));
|
||||||
|
person.setTypeName(row.getStr("typeName"));
|
||||||
|
person.setTypeCode(row.getStr("typeCode"));
|
||||||
|
person.setWay(row.getStr("way"));
|
||||||
|
person.setIdCard(row.getStr("idCard", ""));
|
||||||
|
person.setBankOfDeposit(row.getStr("bankOfDeposit", ""));
|
||||||
|
person.setBankUserName(row.getStr("bankUserName", ""));
|
||||||
|
person.setBankCardNumber(row.getStr("bankCardNumber", ""));
|
||||||
|
person.setMoney(row.getBigDecimal("money", BigDecimal.ZERO));
|
||||||
|
person.setOccurTime(row.getStr("occurTime", ""));
|
||||||
|
person.setSortNum(sort++);
|
||||||
|
dao().insert(person);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpecialCondolence loadApplication(String id) {
|
||||||
|
SpecialCondolence info = fetch(id);
|
||||||
|
if (info != null) {
|
||||||
|
List<JSONObject> rows = new ArrayList<>();
|
||||||
|
for (SpecialCondolenceRecipient person : dao().query(
|
||||||
|
SpecialCondolenceRecipient.class,
|
||||||
|
Cnd.where("applyId", "=", id).asc("sortNum").asc("id"))) {
|
||||||
|
rows.add(JSONUtil.parseObj(person));
|
||||||
|
}
|
||||||
|
info.setRecipients(rows);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public void deleteApplication(String id) {
|
||||||
|
dao().clear(SpecialCondolenceRecipient.class,
|
||||||
|
Cnd.where("applyId", "=", id));
|
||||||
|
delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package com.budwk.app.zhgh.staffbenefit.specialcondolence.service.impl;
|
||||||
|
|
||||||
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.model.SpecialCondolenceType;
|
||||||
|
import com.budwk.app.zhgh.staffbenefit.specialcondolence.service.SpecialCondolenceTypeService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ClassName SpecialCondolenceTypeServiceImpl
|
||||||
|
* @Author JyuHsin
|
||||||
|
* @Date 2025/7/29 10:03
|
||||||
|
* @Version 1.0
|
||||||
|
* @Description TODO
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@IocBean(args = {"refer:dao"})
|
||||||
|
public class SpecialCondolenceTypeServiceImpl extends BaseServiceImpl<SpecialCondolenceType> implements SpecialCondolenceTypeService {
|
||||||
|
|
||||||
|
public SpecialCondolenceTypeServiceImpl(Dao dao) {
|
||||||
|
super(dao);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
-- 全量初始化:完整定义特殊慰问申请主表、被申请人明细表和慰问类型表。
|
||||||
|
-- 表已存在时不执行本文件中的建表语句;本文件不复制数据、不配置角色授权和工作流。
|
||||||
|
CREATE TABLE `special_condolence` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT 'ID',
|
||||||
|
`subject` varchar(255) DEFAULT NULL COMMENT '事项',
|
||||||
|
`applyUserId` varchar(32) DEFAULT NULL COMMENT '申请人ID',
|
||||||
|
`applyUserName` varchar(100) DEFAULT NULL COMMENT '申请人姓名',
|
||||||
|
`applyLoginName` varchar(120) DEFAULT NULL COMMENT '申请人工号',
|
||||||
|
`applyUnionId` varchar(32) DEFAULT NULL COMMENT '申请人分工会ID',
|
||||||
|
`applyUnionName` varchar(100) DEFAULT NULL COMMENT '申请人分工会',
|
||||||
|
`applyUnitId` varchar(32) DEFAULT NULL COMMENT '申请人单位ID',
|
||||||
|
`applyUnitName` varchar(100) DEFAULT NULL COMMENT '申请人单位',
|
||||||
|
`helpUserId` varchar(32) DEFAULT NULL COMMENT '补助人ID',
|
||||||
|
`helpUserName` varchar(100) DEFAULT NULL COMMENT '补助人姓名',
|
||||||
|
`helpLoginName` varchar(120) DEFAULT NULL COMMENT '补助人工号',
|
||||||
|
`helpUnionId` varchar(32) DEFAULT NULL COMMENT '补助人分工会ID',
|
||||||
|
`helpUnionName` varchar(100) DEFAULT NULL COMMENT '补助人分工会',
|
||||||
|
`helpUnitId` varchar(32) DEFAULT NULL COMMENT '补助人单位ID',
|
||||||
|
`helpUnitName` varchar(100) DEFAULT NULL COMMENT '补助人单位',
|
||||||
|
`origin` varchar(20) DEFAULT NULL COMMENT '类型',
|
||||||
|
`payUserId` varchar(32) DEFAULT NULL COMMENT '收款人',
|
||||||
|
`payUserName` varchar(30) DEFAULT NULL COMMENT '收款人姓名',
|
||||||
|
`payLoginName` varchar(20) DEFAULT NULL COMMENT '收款人工号',
|
||||||
|
`type` varchar(32) DEFAULT NULL COMMENT '慰问类型',
|
||||||
|
`typeCode` varchar(32) DEFAULT NULL COMMENT '慰问编码',
|
||||||
|
`way` varchar(20) DEFAULT NULL COMMENT '慰问方式',
|
||||||
|
`perMoney` decimal(10,2) DEFAULT NULL COMMENT '统一每人慰问金额',
|
||||||
|
`money` float(10,2) DEFAULT NULL COMMENT '慰问金额',
|
||||||
|
`occurTime` varchar(30) DEFAULT NULL COMMENT '发生时间',
|
||||||
|
`child` varchar(10) DEFAULT NULL COMMENT '生育几孩(孩次)',
|
||||||
|
`hospital` varchar(50) DEFAULT NULL COMMENT '所在医院',
|
||||||
|
`hospitalHouseNum` varchar(20) DEFAULT NULL COMMENT '病房床号',
|
||||||
|
`hospitalHouseBedNum` varchar(20) DEFAULT NULL COMMENT '病房床号',
|
||||||
|
`hospitalBy` varchar(100) DEFAULT NULL COMMENT '住院病由',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`files` json DEFAULT NULL COMMENT '附件',
|
||||||
|
`signature` varchar(255) DEFAULT NULL COMMENT '签字',
|
||||||
|
`createTime` varchar(30) DEFAULT NULL COMMENT '申请时间',
|
||||||
|
`bankUserName` varchar(100) DEFAULT NULL COMMENT '户名',
|
||||||
|
`bankCardNumber` varchar(100) DEFAULT NULL COMMENT '银行账号',
|
||||||
|
`bankOfDeposit` varchar(100) DEFAULT NULL COMMENT '开户行',
|
||||||
|
`certifierUserId` varchar(32) DEFAULT NULL COMMENT '证明人ID',
|
||||||
|
`certifierUserName` varchar(100) DEFAULT NULL COMMENT '证明人姓名',
|
||||||
|
`certifierLoginName` varchar(120) DEFAULT NULL COMMENT '证明人工号',
|
||||||
|
`certifierUnionId` varchar(32) DEFAULT NULL COMMENT '证明人分工会ID',
|
||||||
|
`certifierUnionName` varchar(100) DEFAULT NULL COMMENT '证明人分工会',
|
||||||
|
`certifierUnitId` varchar(32) DEFAULT NULL COMMENT '证明人单位ID',
|
||||||
|
`certifierUnitName` varchar(100) DEFAULT NULL COMMENT '证明人单位',
|
||||||
|
`handlerUserId` varchar(32) DEFAULT NULL COMMENT '经办人ID',
|
||||||
|
`handlerUserName` varchar(100) DEFAULT NULL COMMENT '经办人姓名',
|
||||||
|
`handlerLoginName` varchar(120) DEFAULT NULL COMMENT '经办人工号',
|
||||||
|
`handlerUnionId` varchar(32) DEFAULT NULL COMMENT '经办人分工会ID',
|
||||||
|
`handlerUnionName` varchar(100) DEFAULT NULL COMMENT '经办人分工会',
|
||||||
|
`handlerUnitId` varchar(32) DEFAULT NULL COMMENT '经办人单位ID',
|
||||||
|
`handlerUnitName` varchar(100) DEFAULT NULL COMMENT '经办人单位',
|
||||||
|
`hospitalizationTime` varchar(30) DEFAULT NULL COMMENT '入院时间',
|
||||||
|
`leaveHospitalTime` varchar(30) DEFAULT NULL COMMENT '出院时间',
|
||||||
|
`thisYearHospitalizationNum` int DEFAULT NULL COMMENT '当年第几次住院',
|
||||||
|
`createdBy` varchar(32) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`createdAt` bigint DEFAULT NULL COMMENT '创建时间(毫秒时间戳)',
|
||||||
|
`updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`updatedAt` bigint DEFAULT NULL COMMENT '修改时间(毫秒时间戳)',
|
||||||
|
`delFlag` tinyint(1) DEFAULT 0 COMMENT '删除标记',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='特殊慰问申请';
|
||||||
|
|
||||||
|
CREATE TABLE `special_condolence_type` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT 'ID',
|
||||||
|
`code` varchar(30) DEFAULT NULL COMMENT '编码',
|
||||||
|
`name` varchar(50) DEFAULT NULL COMMENT '名称',
|
||||||
|
`money` float(10,2) DEFAULT NULL COMMENT '费用',
|
||||||
|
`way` varchar(20) DEFAULT NULL COMMENT '慰问方式',
|
||||||
|
`enable` tinyint(1) DEFAULT 1 COMMENT '是否启用',
|
||||||
|
`isUploadFile` tinyint(1) DEFAULT NULL COMMENT '是否上传附件',
|
||||||
|
`uploadFileDesc` varchar(50) DEFAULT NULL COMMENT '上传附件说明',
|
||||||
|
`location` int DEFAULT NULL COMMENT '排序字段',
|
||||||
|
`sortNum` int NOT NULL DEFAULT 0 COMMENT '排序',
|
||||||
|
`uploadMeetingRecord` tinyint(1) DEFAULT 0 COMMENT '上传会议纪要',
|
||||||
|
`createdBy` varchar(32) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`createdAt` bigint DEFAULT NULL COMMENT '创建时间(毫秒时间戳)',
|
||||||
|
`updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`updatedAt` bigint DEFAULT NULL COMMENT '修改时间(毫秒时间戳)',
|
||||||
|
`delFlag` tinyint(1) DEFAULT 0 COMMENT '删除标记',
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='特殊慰问类型';
|
||||||
|
|
||||||
|
-- 一份申请对应一个流程实例;多名被申请人通过 applyId 关联同一份申请。
|
||||||
|
CREATE TABLE `special_condolence_recipient` (
|
||||||
|
`id` varchar(32) NOT NULL COMMENT '明细ID',
|
||||||
|
`applyId` varchar(32) NOT NULL COMMENT '申请主表ID',
|
||||||
|
`helpUserId` varchar(32) NOT NULL COMMENT '慰问对象用户ID',
|
||||||
|
`helpLoginName` varchar(120) DEFAULT NULL COMMENT '慰问对象工号',
|
||||||
|
`personType` varchar(50) DEFAULT NULL COMMENT '人员类型',
|
||||||
|
`helpUserName` varchar(100) NOT NULL COMMENT '慰问对象',
|
||||||
|
`type` varchar(32) NOT NULL COMMENT '慰问类型ID',
|
||||||
|
`typeName` varchar(50) DEFAULT NULL COMMENT '慰问类型名称',
|
||||||
|
`typeCode` varchar(32) DEFAULT NULL COMMENT '慰问类型编码',
|
||||||
|
`way` varchar(20) DEFAULT NULL COMMENT '慰问方式',
|
||||||
|
`idCard` varchar(18) NOT NULL COMMENT '身份证号码',
|
||||||
|
`bankOfDeposit` varchar(100) NOT NULL COMMENT '开户行',
|
||||||
|
`bankUserName` varchar(100) NOT NULL COMMENT '户名',
|
||||||
|
`bankCardNumber` varchar(30) NOT NULL COMMENT '收款账户',
|
||||||
|
`money` decimal(10,2) NOT NULL COMMENT '慰问金额',
|
||||||
|
`occurTime` varchar(30) NOT NULL COMMENT '慰问时间',
|
||||||
|
`sortNum` int NOT NULL DEFAULT 0 COMMENT '行序号',
|
||||||
|
`createdBy` varchar(32) DEFAULT NULL COMMENT '创建人',
|
||||||
|
`createdAt` bigint DEFAULT NULL COMMENT '创建时间(毫秒时间戳)',
|
||||||
|
`updatedBy` varchar(32) DEFAULT NULL COMMENT '修改人',
|
||||||
|
`updatedAt` bigint DEFAULT NULL COMMENT '修改时间(毫秒时间戳)',
|
||||||
|
`delFlag` tinyint(1) DEFAULT 0 COMMENT '删除标记',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_special_condolence_recipient_apply` (`applyId`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='特殊慰问被申请人明细';
|
||||||
|
|
||||||
|
-- 主表保留原有摘要字段兼容现有列表,money 为整份申请的金额合计。
|
||||||
|
-- 被申请人的完整信息保存在 special_condolence_recipient 中,不在主表使用 JSON 存储。
|
||||||
|
|
||||||
|
-- 新增 PC、H5 菜单,角色授权由管理员另行配置。
|
||||||
|
START TRANSACTION;
|
||||||
|
CREATE TEMPORARY TABLE special_condolence_menu_map AS
|
||||||
|
SELECT id oldId, MD5(CONCAT('special_condolence:', id)) newId
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE id IN ('3b49290f7db44130b9f6394a8212321f', '024811fd168e44948e6ab84911fc26bb')
|
||||||
|
OR (href LIKE '/platform/condolence/%' AND href NOT LIKE '%/branchUnionApproval%');
|
||||||
|
CREATE TEMPORARY TABLE special_condolence_parent_map (
|
||||||
|
oldId varchar(32) NOT NULL COMMENT '原父菜单ID',
|
||||||
|
newId varchar(32) NOT NULL COMMENT '特殊慰问父菜单ID',
|
||||||
|
PRIMARY KEY (oldId)
|
||||||
|
);
|
||||||
|
INSERT INTO special_condolence_parent_map (oldId, newId)
|
||||||
|
SELECT oldId, newId FROM special_condolence_menu_map;
|
||||||
|
|
||||||
|
INSERT INTO sys_menu
|
||||||
|
(id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
|
||||||
|
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt,
|
||||||
|
delFlag, processKey, platform, moduleId, isQuickEntry, picIcon, initialPinyinName,
|
||||||
|
isRecommendApp, isRecommendService)
|
||||||
|
SELECT map.newId, COALESCE(parent.newId, m.parentId),
|
||||||
|
CONCAT('T', SUBSTRING(map.newId, 1, 7)), REPLACE(m.name, '职工慰问', '特殊慰问'),
|
||||||
|
m.aliasName, m.type, REPLACE(m.href, '/condolence/', '/special_condolence/'), m.target,
|
||||||
|
m.icon, m.showit, m.disabled,
|
||||||
|
CASE m.id WHEN '3b49290f7db44130b9f6394a8212321f' THEN 'special_condolence'
|
||||||
|
WHEN '024811fd168e44948e6ab84911fc26bb' THEN 'h5.special_condolence'
|
||||||
|
ELSE REPLACE(m.permission, 'condolence', 'special_condolence') END,
|
||||||
|
REPLACE(m.note, '职工慰问', '特殊慰问'), m.location, m.hasChildren,
|
||||||
|
m.createdBy, UNIX_TIMESTAMP()*1000, m.updatedBy, UNIX_TIMESTAMP()*1000, m.delFlag,
|
||||||
|
REPLACE(m.processKey, 'ZGWW', 'TSWW'), m.platform, m.moduleId, m.isQuickEntry,
|
||||||
|
m.picIcon, IF(m.name = '职工慰问', 't', m.initialPinyinName), m.isRecommendApp, m.isRecommendService
|
||||||
|
FROM sys_menu m JOIN special_condolence_menu_map map ON map.oldId = m.id
|
||||||
|
LEFT JOIN special_condolence_parent_map parent ON parent.oldId = m.parentId
|
||||||
|
WHERE NOT EXISTS (SELECT 1 FROM sys_menu existing WHERE existing.id = map.newId);
|
||||||
|
|
||||||
|
-- 父子菜单路径保持树形前缀关系。
|
||||||
|
UPDATE sys_menu child JOIN sys_menu parent ON parent.id = child.parentId
|
||||||
|
JOIN special_condolence_menu_map map ON map.newId = child.id
|
||||||
|
SET child.path = CONCAT(parent.path, RIGHT(child.id, 4));
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE special_condolence_menu_map;
|
||||||
|
DROP TEMPORARY TABLE special_condolence_parent_map;
|
||||||
|
|
||||||
|
-- 权限部分,不要删除
|
||||||
|
-- SYSADMIN
|
||||||
|
-- 特殊慰问 web
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '4c46696d75ff0eddf5cb57fac3e5d06d');
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '3e97a91e7aa9566cdae94850038a6212'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '6c5be59ffb8d7c524ec72f2a02d6c6d2'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '7f66eb63b6ebd81c5eee9c5c2de2ed98'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '8d5ebaa091eee01abb33e89e3dcc92f8'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '9c37242f50c5fb4a9c1b2b9b9dd0e2fd'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '9f4f850904fe751db1cd13977374f99b'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', 'b24a5bef9ccbf7241c5bb85e80352f8f');
|
||||||
|
|
||||||
|
-- 特殊慰问 h5
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '2145812145ee6548552504b4f5a55ff7');
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES ('7f4a820d5a394bb8a0a92d6699afe7c8', '42b4b5f54593cf023961ad1c9ce36f53'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '4f3212a13a54fbb2a082ee77651c9a73'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', '739f64c71fe776dc3520ebb2977c2d68'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', 'b6c725beaf3bfe9f2b29f46855c45a24'),
|
||||||
|
('7f4a820d5a394bb8a0a92d6699afe7c8', 'eb3d1b27d51b84df1cebf24e1278e26c');
|
||||||
|
|
||||||
|
|
||||||
|
-- 校工会办公室主任
|
||||||
|
-- 特殊慰问 web
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('494ac71eb8b44d0e99e19b7fde6bd469', '4c46696d75ff0eddf5cb57fac3e5d06d'),
|
||||||
|
('494ac71eb8b44d0e99e19b7fde6bd469', '8d5ebaa091eee01abb33e89e3dcc92f8'),
|
||||||
|
('494ac71eb8b44d0e99e19b7fde6bd469', '7f66eb63b6ebd81c5eee9c5c2de2ed98');
|
||||||
|
|
||||||
|
-- 特殊慰问 h5
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('494ac71eb8b44d0e99e19b7fde6bd469', '2145812145ee6548552504b4f5a55ff7'),
|
||||||
|
('494ac71eb8b44d0e99e19b7fde6bd469', '42b4b5f54593cf023961ad1c9ce36f53');
|
||||||
|
|
||||||
|
-- 校工会主席
|
||||||
|
-- 特殊慰问 web
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('6aece46b946e4fb9ac4cb15c0cd8c3e6', '4c46696d75ff0eddf5cb57fac3e5d06d'),
|
||||||
|
('6aece46b946e4fb9ac4cb15c0cd8c3e6', '8d5ebaa091eee01abb33e89e3dcc92f8'),
|
||||||
|
('6aece46b946e4fb9ac4cb15c0cd8c3e6', 'b24a5bef9ccbf7241c5bb85e80352f8f');
|
||||||
|
|
||||||
|
-- 特殊慰问 h5
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('6aece46b946e4fb9ac4cb15c0cd8c3e6', '2145812145ee6548552504b4f5a55ff7'),
|
||||||
|
('6aece46b946e4fb9ac4cb15c0cd8c3e6', 'b6c725beaf3bfe9f2b29f46855c45a24');
|
||||||
|
|
||||||
|
-- 校工会主席
|
||||||
|
-- 特殊慰问 web
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('b3854469e6f44901b22bb791cb538431', '4c46696d75ff0eddf5cb57fac3e5d06d'),
|
||||||
|
('b3854469e6f44901b22bb791cb538431', '8d5ebaa091eee01abb33e89e3dcc92f8'),
|
||||||
|
('b3854469e6f44901b22bb791cb538431', '9c37242f50c5fb4a9c1b2b9b9dd0e2fd');
|
||||||
|
|
||||||
|
-- 特殊慰问 h5
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId)
|
||||||
|
VALUES
|
||||||
|
('b3854469e6f44901b22bb791cb538431', '2145812145ee6548552504b4f5a55ff7'),
|
||||||
|
('b3854469e6f44901b22bb791cb538431', '739f64c71fe776dc3520ebb2977c2d68');
|
||||||
|
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, processKey, platform, moduleId, isQuickEntry, picIcon, initialPinyinName, isRecommendApp, isRecommendService) VALUES ('184d56fd537041caa2bde800d0d32436', '90bf20d9065e4e11864952ea18544c25', '009000040003', '个人范围', null, 'data', null, null, null, false, false, 'self', null, 1027, false, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331288, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331288, false, null, 'PC', null, false, null, null, false, false);
|
||||||
|
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, processKey, platform, moduleId, isQuickEntry, picIcon, initialPinyinName, isRecommendApp, isRecommendService) VALUES ('df87d83ed3184019b3872139c15b53ec', '90bf20d9065e4e11864952ea18544c25', '009000040002', '分工会范围', null, 'data', null, null, null, false, false, 'branch_union', null, 1026, false, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331286, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331286, false, null, 'PC', null, false, null, null, false, false);
|
||||||
|
INSERT INTO sys_menu (id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled, permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt, delFlag, processKey, platform, moduleId, isQuickEntry, picIcon, initialPinyinName, isRecommendApp, isRecommendService) VALUES ('f2a75d2494724978b5325075815808c9', '90bf20d9065e4e11864952ea18544c25', '009000040001', '全校范围', null, 'data', null, null, null, false, false, 'all_school', null, 1025, false, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331280, '17a7f8ad3ee947b4a26175049a9c253d', 1793418331280, false, null, 'PC', null, false, null, null, false, false);
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('fd753e8a8c5a404e8e00ef8e0b0c69da', 'df87d83ed3184019b3872139c15b53ec');
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('494ac71eb8b44d0e99e19b7fde6bd469', 'f2a75d2494724978b5325075815808c9');
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('6aece46b946e4fb9ac4cb15c0cd8c3e6', 'f2a75d2494724978b5325075815808c9');
|
||||||
|
INSERT INTO sys_role_menu (roleId, menuId) VALUES ('b3854469e6f44901b22bb791cb538431', 'f2a75d2494724978b5325075815808c9');
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
/* 首页服务门户布局单独限定作用域,避免影响应用中心和其他业务页。 */
|
|
||||||
#v4-home-app.home-portal {
|
|
||||||
width: 100%;
|
|
||||||
max-width: none;
|
|
||||||
margin: 0;
|
|
||||||
color: #20344d;
|
|
||||||
background: #f2f6fb;
|
|
||||||
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
#v4-home-app.home-portal * { box-sizing: border-box; }
|
|
||||||
#v4-home-app .portal-top { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 18px; max-width: 1720px; margin: auto; padding: 18px 24px 0; }
|
|
||||||
/* 使用完整不透明背景铺满横幅,会员信息独立成卡,不再覆盖校园景观。 */
|
|
||||||
#v4-home-app .portal-hero { position: relative; min-width: 0; min-height: 260px; overflow: hidden; border-radius: 12px; background: #e8f4ff; }
|
|
||||||
#v4-home-app .portal-hero::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(90deg, #e8f4ff 0%, #e8f4ff 28%, rgba(232,244,255,.92) 39%, rgba(232,244,255,.35) 54%, rgba(232,244,255,0) 68%); }
|
|
||||||
#v4-home-app .portal-hero-inner { position: relative; z-index: 1; display: flex; align-items: center; min-height: 260px; height: 100%; padding: 32px 40px; }
|
|
||||||
#v4-home-app .portal-hero-copy { max-width: 80%; }
|
|
||||||
#v4-home-app .portal-hero-eyebrow { margin-bottom: 12px; color: #527ca1; font-size: 14px; line-height: 22px; letter-spacing: 2px; }
|
|
||||||
#v4-home-app .portal-hero-copy h1 { margin: 0 0 10px; font-size: 36px; line-height: 1.3; font-weight: 700; color: #083765; }
|
|
||||||
#v4-home-app .portal-hero-copy p { margin: 0; color: #335675; font-size: 17px; line-height: 1.8; }
|
|
||||||
#v4-home-app .portal-values { display: flex; flex-wrap: wrap; gap: 22px 36px; margin-top: 24px; }
|
|
||||||
#v4-home-app .portal-values span { display: inline-flex; align-items: center; gap: 12px; }
|
|
||||||
#v4-home-app .portal-values i { color: #3599f2; font-size: 23px; }
|
|
||||||
/* 首次渲染时分层淡入文字,只改变透明度和位移,不影响卡片布局。 */
|
|
||||||
@keyframes portal-text-enter {
|
|
||||||
from { opacity: 0; transform: translateY(12px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
#v4-home-app .portal-hero-eyebrow,
|
|
||||||
#v4-home-app .portal-hero-copy h1,
|
|
||||||
#v4-home-app .portal-hero-copy p,
|
|
||||||
#v4-home-app .portal-values > span,
|
|
||||||
#v4-home-app .portal-member-date,
|
|
||||||
#v4-home-app .portal-member-heading,
|
|
||||||
#v4-home-app .portal-member .meta-row { animation: portal-text-enter .6s cubic-bezier(.22, 1, .36, 1) backwards; }
|
|
||||||
#v4-home-app .portal-hero-copy h1 { animation-delay: .08s; }
|
|
||||||
#v4-home-app .portal-hero-copy p { animation-delay: .16s; }
|
|
||||||
#v4-home-app .portal-values > span:nth-child(1) { animation-delay: .24s; }
|
|
||||||
#v4-home-app .portal-values > span:nth-child(2) { animation-delay: .30s; }
|
|
||||||
#v4-home-app .portal-values > span:nth-child(3) { animation-delay: .36s; }
|
|
||||||
#v4-home-app .portal-values > span:nth-child(4) { animation-delay: .42s; }
|
|
||||||
#v4-home-app .portal-member-date { animation-delay: .10s; }
|
|
||||||
#v4-home-app .portal-member-heading { animation-delay: .18s; }
|
|
||||||
#v4-home-app .portal-member .meta-row:nth-child(1) { animation-delay: .26s; }
|
|
||||||
#v4-home-app .portal-member .meta-row:nth-child(2) { animation-delay: .34s; }
|
|
||||||
#v4-home-app .portal-member .meta-row:nth-child(3) { animation-delay: .42s; }
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
|
||||||
#v4-home-app .portal-hero-eyebrow,
|
|
||||||
#v4-home-app .portal-hero-copy h1,
|
|
||||||
#v4-home-app .portal-hero-copy p,
|
|
||||||
#v4-home-app .portal-values > span,
|
|
||||||
#v4-home-app .portal-member-date,
|
|
||||||
#v4-home-app .portal-member-heading,
|
|
||||||
#v4-home-app .portal-member .meta-row { animation: none; }
|
|
||||||
}
|
|
||||||
#v4-home-app .portal-content { max-width: 1720px; margin: auto; padding: 18px 24px 28px; }
|
|
||||||
/* 同行共用网格行高,统一横纵间距;待办使用紧凑两行信息,避免撑出大块留白。 */
|
|
||||||
#v4-home-app .portal-columns { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 18px; margin-top: 18px; align-items: stretch; }
|
|
||||||
#v4-home-app .portal-columns > * { min-width: 0; }
|
|
||||||
#v4-home-app .portal-news-wide { grid-column: 1 / -1; }
|
|
||||||
#v4-home-app .portal-panel,
|
|
||||||
#v4-home-app .entry-wrapper,
|
|
||||||
#v4-home-app .todo-center,
|
|
||||||
#v4-home-app .work-template-wrapper,
|
|
||||||
#v4-home-app .jcdt-container { background: #fff; border: 0; border-radius: 12px; padding: 20px; box-shadow: 0 3px 14px rgba(30, 66, 108, .035); }
|
|
||||||
#v4-home-app .home-section-header,
|
|
||||||
#v4-home-app .portal-todo-heading,
|
|
||||||
#v4-home-app .work-template-header,
|
|
||||||
#v4-home-app .portal-news-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; min-height: 28px; margin: 0 0 16px; }
|
|
||||||
#v4-home-app .home-section-title,
|
|
||||||
#v4-home-app .work-template-title,
|
|
||||||
#v4-home-app .portal-news-title,
|
|
||||||
#v4-home-app .portal-todo-heading h3 { display: inline-flex; align-items: center; gap: 9px; margin: 0; padding: 0; border: 0; font-size: 20px; line-height: 1.4; font-weight: 600; color: #123356; }
|
|
||||||
#v4-home-app .home-section-title i,
|
|
||||||
#v4-home-app .work-template-title i,
|
|
||||||
#v4-home-app .portal-news-title > i:first-child,
|
|
||||||
#v4-home-app .portal-todo-heading i { color: #1687f5; font-size: 19px; }
|
|
||||||
#v4-home-app .portal-more { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; border: 0; padding: 4px 0; background: transparent; color: #1687f5; font: inherit; font-size: 13px; cursor: pointer; text-decoration: none; }
|
|
||||||
#v4-home-app .portal-more:hover { color: #0565c6; }
|
|
||||||
#v4-home-app button:focus-visible,
|
|
||||||
#v4-home-app a:focus-visible,
|
|
||||||
#v4-home-app [tabindex]:focus-visible { outline: 2px solid #1687f5; outline-offset: 3px; }
|
|
||||||
#v4-home-app .entry-card { min-width: 0; }
|
|
||||||
#v4-home-app .entry-wrapper { padding-bottom: 0; }
|
|
||||||
#v4-home-app .portal-entry-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; border-bottom: 1px solid #e9eff6; }
|
|
||||||
#v4-home-app .portal-entry-tabs { display: flex; gap: 34px; }
|
|
||||||
#v4-home-app .portal-entry-tabs button { border: 0; border-bottom: 3px solid transparent; padding: 0 0 13px; background: transparent; font: inherit; font-size: 19px; color: #465d78; font-weight: 600; cursor: pointer; }
|
|
||||||
#v4-home-app .portal-entry-tabs button.active { color: #0784fa; border-bottom-color: #0784fa; }
|
|
||||||
#v4-home-app .entry-section + .entry-section { margin-top: 0; }
|
|
||||||
#v4-home-app .app-grid { display: flex; justify-content: flex-start; align-items: center; gap: 12px; min-height: 0; overflow-x: auto; padding: 20px 0; border: 0; border-radius: 0; box-shadow: none; }
|
|
||||||
#v4-home-app .app-item { flex: 0 0 96px; border: 0; font: inherit; padding: 0 4px; max-width: none; }
|
|
||||||
#v4-home-app .app-item:hover { background: #f4f9ff; box-shadow: none; transform: translateY(-2px); }
|
|
||||||
#v4-home-app .app-icon { background: transparent; }
|
|
||||||
#v4-home-app .app-name { display: block; width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 13px; line-height: 20px; min-height: 0; margin-top: 2px; }
|
|
||||||
#v4-home-app .app-empty { padding: 10px 0; }
|
|
||||||
#v4-home-app .act-card { padding: 0; border: 0; border-radius: 0; box-shadow: none; }
|
|
||||||
#v4-home-app .activity-swiper-container { padding: 0 0 4px; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item { display: flex; flex-direction: column; height: 100%; }
|
|
||||||
/* 加高封面并统一裁剪容器,图片、加载态和占位图都保持相同圆角。 */
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .img-box { flex-shrink: 0; height: auto; aspect-ratio: 1.5; border-radius: 10px; overflow: hidden; clip-path: inset(0 round 10px); background: #1687f5; isolation: isolate; }
|
|
||||||
#v4-home-app .img-box .el-image { display: block; width: 100%; height: 100%; position: absolute; inset: 0; border-radius: inherit; overflow: hidden; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .img-box img { height: 100% !important; max-height: none !important; object-fit: cover !important; border-radius: 10px; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .img-box .status { top: 8px; left: 8px; border-radius: 5px; padding: 4px 7px; background: #ed4859; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .img-box .status-ended { background: #8b97a7; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .img-box .status-upcoming { background: #1687f5; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item h4 { flex: 1; margin: 10px 0 8px; height: auto; min-height: 22px; max-height: 44px; font-size: 15px; color: #20344d; line-height: 22px; }
|
|
||||||
#v4-home-app .activity-swiper .swiper-slide .item .time p { white-space: normal; font-size: 12px; color: #7b899d; line-height: 1.6; }
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-next,
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-prev { width: 44px; height: 44px; margin-top: 0; padding: 0; transform: translateY(-50%); border: 1px solid #dbeaff; background: rgba(255,255,255,.96); color: #1687f5; box-shadow: 0 3px 12px rgba(30, 66, 108, .18); }
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-next { right: 8px; }
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-prev { left: 8px; }
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-next:hover,
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-prev:hover { transform: translateY(-50%) scale(1.05); background: #1687f5; color: #fff; }
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-next::after,
|
|
||||||
#v4-home-app .activity-swiper-container .swiper-button-prev::after { font-size: 18px; font-weight: 600; }
|
|
||||||
#v4-home-app .portal-cover-empty { height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 9px; color: #94a7bd; background: #f0f5fb; }
|
|
||||||
#v4-home-app .portal-cover-empty i { font-size: 28px; }
|
|
||||||
#v4-home-app .user-wrapper { background: transparent; }
|
|
||||||
#v4-home-app .user-container { display: block; width: 100%; height: 100%; margin: 0; }
|
|
||||||
#v4-home-app .todo-center { display: flex; flex-direction: column; min-width: 0; height: 100%; }
|
|
||||||
#v4-home-app .todo-center .header { display: block; margin: 0; }
|
|
||||||
#v4-home-app .todo-center .el-tabs { margin: 0 0 8px; }
|
|
||||||
#v4-home-app .todo-center .el-tabs__header { margin: 0; }
|
|
||||||
#v4-home-app .todo-center .el-tabs__nav { display: flex; width: 100%; border-color: #e9eff6; border-radius: 6px 6px 0 0; }
|
|
||||||
#v4-home-app .todo-center .el-tabs__item { flex: 1; min-width: 0; padding: 0 7px; font-size: 12px; height: 36px; line-height: 36px; text-align: center; }
|
|
||||||
#v4-home-app .todo-center .el-tabs__item.is-active { border-bottom: 2px solid #1687f5; color: #1687f5; }
|
|
||||||
#v4-home-app .portal-task-list { display: flex; flex-direction: column; justify-content: space-evenly; flex: 1; min-height: 180px; }
|
|
||||||
#v4-home-app .portal-task-row { display: flex; gap: 10px; align-items: center; padding: 8px 6px; border-bottom: 1px solid #eef3f8; }
|
|
||||||
#v4-home-app .portal-task-row:last-child { border-bottom: 0; }
|
|
||||||
#v4-home-app .portal-task-row:hover { background: #f7fbff; }
|
|
||||||
#v4-home-app .portal-task-icon { width: 34px; height: 40px; display: flex; flex: 0 0 34px; align-items: center; justify-content: center; border-radius: 8px; background: #eef7ff; color: #1687f5; font-size: 22px; }
|
|
||||||
#v4-home-app .portal-task-content { min-width: 0; flex: 1; }
|
|
||||||
#v4-home-app .portal-task-title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: #263548; font-weight: 600; font-size: 14px; line-height: 22px; }
|
|
||||||
#v4-home-app .portal-task-meta { display: flex; align-items: baseline; gap: 10px; font-size: 12px; color: #8390a2; line-height: 21px; }
|
|
||||||
#v4-home-app .portal-task-meta span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
||||||
#v4-home-app .portal-task-meta > span:first-child { max-width: 45%; flex-shrink: 0; }
|
|
||||||
#v4-home-app .portal-task-date { flex-shrink: 0; font-size: 12px; color: #7b899d; }
|
|
||||||
#v4-home-app .portal-task-node { flex: 1; min-width: 0; color: #8b98a9; font-size: 11px; line-height: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
||||||
#v4-home-app .portal-task-row .el-button { flex-shrink: 0; padding: 8px 14px; }
|
|
||||||
#v4-home-app .portal-task-pagination { text-align: right; margin-top: 8px; }
|
|
||||||
#v4-home-app .portal-empty { min-height: 132px; display: flex; align-items: center; justify-content: center; gap: 10px; color: #8a9aac; }
|
|
||||||
#v4-home-app .portal-empty i { font-size: 26px; color: #83b9ee; }
|
|
||||||
#v4-home-app .work-template-wrapper { width: 100%; margin: 0; }
|
|
||||||
#v4-home-app .work-template-card { min-height: 98px; padding: 0; border: 0; border-radius: 0; box-shadow: none; }
|
|
||||||
#v4-home-app .work-template-grid { display: flex; align-items: flex-start; gap: 14px; overflow-x: auto; padding: 4px 0 10px; scroll-snap-type: x proximity; }
|
|
||||||
#v4-home-app .work-template-item { flex: 0 0 88px; width: 88px; padding: 4px; border: 0; font: inherit; scroll-snap-align: start; }
|
|
||||||
#v4-home-app .work-template-item:hover { background: #f4f9ff; box-shadow: none; }
|
|
||||||
#v4-home-app .work-template-icon,
|
|
||||||
#v4-home-app .work-template-icon .el-image { width: 48px; height: 48px; }
|
|
||||||
#v4-home-app .work-template-icon img { width: 48px !important; height: 48px !important; object-fit: contain; }
|
|
||||||
#v4-home-app .work-template-icon i { font-size: 30px; line-height: 48px; color: #83b9ee; }
|
|
||||||
#v4-home-app .work-template-name { font-size: 13px !important; line-height: 20px; min-height: 40px; max-height: 40px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
|
|
||||||
#v4-home-app .work-template-wrapper .no-activity-placeholder { padding: 12px; }
|
|
||||||
#v4-home-app .jcdt-container { width: 100%; max-width: none; height: 100%; margin: 0; }
|
|
||||||
#v4-home-app .portal-news-title { background: transparent; cursor: pointer; font-family: inherit; }
|
|
||||||
#v4-home-app .portal-news-title > i:last-child:not(:first-child) { color: #8092a6; font-size: 14px; }
|
|
||||||
#v4-home-app .portal-news-row { display: flex; align-items: center; gap: 12px; width: 100%; padding: 9px 0; border: 0; background: transparent; color: #42536a; font: inherit; text-align: left; cursor: pointer; }
|
|
||||||
#v4-home-app .portal-news-row time { flex-shrink: 0; padding: 3px 7px; background: #eff5fc; border-radius: 4px; color: #45698f; font-size: 13px; }
|
|
||||||
#v4-home-app .portal-news-row span { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
||||||
#v4-home-app .portal-news-row:hover span { color: #1687f5; }
|
|
||||||
@media (min-width: 1600px) {
|
|
||||||
#v4-home-app .portal-hero-copy h1 { font-size: 42px; }
|
|
||||||
#v4-home-app .app-item { flex-basis: 104px; }
|
|
||||||
}
|
|
||||||
@media (max-width: 1199px) {
|
|
||||||
#v4-home-app .portal-top { grid-template-columns: minmax(0, 1fr) 300px; padding: 18px 18px 0; }
|
|
||||||
#v4-home-app .portal-hero-inner { padding-left: 32px; }
|
|
||||||
#v4-home-app .portal-content { padding: 18px 18px 24px; }
|
|
||||||
#v4-home-app .portal-columns { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
|
|
||||||
#v4-home-app .portal-values { gap: 16px; }
|
|
||||||
#v4-home-app .portal-panel, #v4-home-app .todo-center { padding: 16px; }
|
|
||||||
#v4-home-app .portal-task-row { gap: 8px; padding: 8px 0; }
|
|
||||||
#v4-home-app .portal-task-icon { display: none; }
|
|
||||||
}
|
|
||||||
@media (max-width: 900px) {
|
|
||||||
#v4-home-app .portal-top { grid-template-columns: minmax(0, 1fr); }
|
|
||||||
#v4-home-app .portal-columns { grid-template-columns: minmax(0, 1fr); }
|
|
||||||
#v4-home-app .portal-activities { order: 1; }
|
|
||||||
#v4-home-app .portal-todo { order: 2; }
|
|
||||||
#v4-home-app .portal-templates { order: 3; }
|
|
||||||
#v4-home-app .portal-news { order: 4; }
|
|
||||||
#v4-home-app .portal-hero-copy { max-width: 68%; }
|
|
||||||
#v4-home-app .portal-hero-copy h1 { font-size: 30px; }
|
|
||||||
#v4-home-app .portal-hero-copy p { font-size: 14px; }
|
|
||||||
#v4-home-app .portal-task-icon { display: flex; }
|
|
||||||
#v4-home-app .portal-task-meta { flex-wrap: nowrap; }
|
|
||||||
}
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
#v4-home-app .portal-top { padding: 10px 10px 8px; }
|
|
||||||
#v4-home-app .portal-hero-inner { padding: 24px 20px; }
|
|
||||||
#v4-home-app .portal-hero-copy { max-width: 100%; }
|
|
||||||
#v4-home-app .portal-hero-copy h1 { font-size: 28px; }
|
|
||||||
#v4-home-app .portal-values { gap: 12px 18px; font-size: 12px; }
|
|
||||||
#v4-home-app .portal-values i { font-size: 17px; }
|
|
||||||
#v4-home-app .portal-content { padding: 10px; }
|
|
||||||
#v4-home-app .entry-wrapper { padding: 16px 12px 0; }
|
|
||||||
#v4-home-app .portal-entry-tabs { gap: 20px; }
|
|
||||||
#v4-home-app .portal-entry-tabs button { font-size: 16px; }
|
|
||||||
#v4-home-app .app-item { flex-basis: 84px; }
|
|
||||||
#v4-home-app .home-section-title, #v4-home-app .portal-todo-heading h3, #v4-home-app .work-template-title, #v4-home-app .portal-news-title { font-size: 18px; }
|
|
||||||
#v4-home-app .portal-task-row .el-button { padding: 8px 10px; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 使用参考项目本地横幅图片,文字遮罩保持首页的可读性。 */
|
|
||||||
#v4-home-app .portal-hero-background { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: right bottom; }
|
|
||||||
/* 已展示全部活动时明确禁用入口,避免出现可点击但没有内容切换的按钮。 */
|
|
||||||
#v4-home-app .portal-more:disabled { color: #8a9aac; cursor: default; }
|
|
||||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 MiB |
@@ -52,8 +52,6 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id
|
this.signatureAddress = origin + "/platform/signature/scanPcCode?id=" + this.id
|
||||||
// 打印当前二维码的签字入口,便于从控制台复制地址进行签字测试。
|
|
||||||
console.info("signatureAddress:", this.signatureAddress)
|
|
||||||
return this.$axios.post("/platform/signature/get")
|
return this.$axios.post("/platform/signature/get")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (this._isBeingDestroyed || this._isDestroyed) {
|
if (this._isBeingDestroyed || this._isDestroyed) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
progress
|
progress
|
||||||
:accept="accept"
|
:accept="accept"
|
||||||
:max-count="upload_number"
|
:max-count="upload_number"
|
||||||
|
:upload-text="upload_text"
|
||||||
title=""
|
title=""
|
||||||
description=""
|
description=""
|
||||||
tip=""
|
tip=""
|
||||||
@@ -50,6 +51,11 @@ module.exports = {
|
|||||||
default: 1,
|
default: 1,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
upload_text: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
required: false
|
||||||
|
},
|
||||||
// 上传返回id或url
|
// 上传返回id或url
|
||||||
upload_result_type: {
|
upload_result_type: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -101,6 +107,7 @@ module.exports = {
|
|||||||
this.fileList = val.map((v) => {
|
this.fileList = val.map((v) => {
|
||||||
return {
|
return {
|
||||||
...v,
|
...v,
|
||||||
|
file: v.file || { name: v.name },
|
||||||
status: null,
|
status: null,
|
||||||
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase())
|
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase())
|
||||||
}
|
}
|
||||||
@@ -118,6 +125,7 @@ module.exports = {
|
|||||||
this.fileList = val.map((v) => {
|
this.fileList = val.map((v) => {
|
||||||
return {
|
return {
|
||||||
...v,
|
...v,
|
||||||
|
file: v.file || { name: v.name },
|
||||||
url: v.url ? v.url : v.response?.data,
|
url: v.url ? v.url : v.response?.data,
|
||||||
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()),
|
isImage: ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(v.name.split(".").pop().toLowerCase()),
|
||||||
status: null
|
status: null
|
||||||
@@ -171,8 +179,8 @@ module.exports = {
|
|||||||
f.url = resp.data
|
f.url = resp.data
|
||||||
f.response = resp
|
f.response = resp
|
||||||
f.percentage = 100
|
f.percentage = 100
|
||||||
f.isImage = true
|
f.isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(f.name.split(".").pop().toLowerCase())
|
||||||
delete f.file
|
f.file = { name: f.name }
|
||||||
delete f.content
|
delete f.content
|
||||||
} else {
|
} else {
|
||||||
f.status = "fail"
|
f.status = "fail"
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h5-user-select">
|
||||||
|
<van-field v-bind="$attrs" :value="displayName" readonly clickable is-link @click="open"></van-field>
|
||||||
|
<van-popup v-model="visible" position="bottom" round get-container="body" class="h5-user-select-popup">
|
||||||
|
<div class="h5-user-select-popup__header">
|
||||||
|
<van-button native-type="button" type="default" size="small" @click="visible = false">取消</van-button>
|
||||||
|
<strong>选择慰问对象</strong>
|
||||||
|
<van-button native-type="button" type="info" size="small" :disabled="!pendingUser" @click="confirm">确认</van-button>
|
||||||
|
</div>
|
||||||
|
<van-search v-model="keyword" placeholder="请输入姓名或工号查询" @input="scheduleSearch" @search="search" @clear="search"></van-search>
|
||||||
|
<div class="h5-user-select-popup__list">
|
||||||
|
<div v-if="loading" class="h5-user-select-popup__status"><van-loading size="24px">加载中</van-loading></div>
|
||||||
|
<div v-else-if="error" class="h5-user-select-popup__status"><span class="h5-user-select-popup__error">{{ error }}</span><van-button native-type="button" size="small" @click="search">重新加载</van-button></div>
|
||||||
|
<van-empty v-else-if="!options.length" description="未找到本工会人员"></van-empty>
|
||||||
|
<template v-else>
|
||||||
|
<van-cell v-for="person in options" :key="person.id" clickable
|
||||||
|
:class="{ 'h5-user-select-popup__selected': pendingUser && pendingUser.id === person.id }"
|
||||||
|
:title="person.userName + (person.loginName ? '(' + person.loginName + ')' : '')"
|
||||||
|
:label="[person.unitName, person.personType].filter(Boolean).join(' · ')"
|
||||||
|
@click="pendingUser = person">
|
||||||
|
<van-icon v-if="pendingUser && pendingUser.id === person.id" name="success" color="#1989fa"></van-icon>
|
||||||
|
</van-cell>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
module.exports = {
|
||||||
|
inheritAttrs: false,
|
||||||
|
model: { prop: 'value', event: 'change' },
|
||||||
|
props: {
|
||||||
|
value: { type: String, default: '' },
|
||||||
|
displayName: { type: String, default: '' },
|
||||||
|
api: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return { visible: false, keyword: '', options: [], pendingUser: null, loading: false, error: '', searchTimer: null, requestId: 0 }
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
clearTimeout(this.searchTimer)
|
||||||
|
this.requestId++
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.keyword = ''
|
||||||
|
this.pendingUser = null
|
||||||
|
this.visible = true
|
||||||
|
this.search()
|
||||||
|
},
|
||||||
|
scheduleSearch() {
|
||||||
|
clearTimeout(this.searchTimer)
|
||||||
|
this.requestId++
|
||||||
|
this.pendingUser = null
|
||||||
|
this.loading = true
|
||||||
|
this.searchTimer = setTimeout(() => this.search(), 250)
|
||||||
|
},
|
||||||
|
async search() {
|
||||||
|
clearTimeout(this.searchTimer)
|
||||||
|
const requestId = ++this.requestId
|
||||||
|
this.loading = true
|
||||||
|
this.error = ''
|
||||||
|
this.pendingUser = null
|
||||||
|
try {
|
||||||
|
const result = await this.$axios.post(this.api, { keyword: this.keyword })
|
||||||
|
if (requestId !== this.requestId) return
|
||||||
|
if (result.code !== 0) throw new Error(result.msg || '人员加载失败')
|
||||||
|
this.options = result.data || []
|
||||||
|
} catch (error) {
|
||||||
|
if (requestId !== this.requestId) return
|
||||||
|
this.options = []
|
||||||
|
this.error = error.message || '人员加载失败'
|
||||||
|
} finally {
|
||||||
|
if (requestId === this.requestId) this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirm() {
|
||||||
|
if (!this.pendingUser) return
|
||||||
|
const person = this.pendingUser
|
||||||
|
this.$emit('change', person.id)
|
||||||
|
this.$emit('selected', person, person.id)
|
||||||
|
this.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.h5-user-select-popup { display: flex; flex-direction: column; height: 72vh; max-height: 640px; padding-bottom: env(safe-area-inset-bottom); box-sizing: border-box; }
|
||||||
|
.h5-user-select-popup__header { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; padding: 14px 16px; border-bottom: 1px solid #ebedf0; }
|
||||||
|
.h5-user-select-popup__header strong { font-size: 16px; color: #323233; }
|
||||||
|
.h5-user-select-popup__header .van-button { min-width: 56px; }
|
||||||
|
.h5-user-select-popup__list { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
|
||||||
|
.h5-user-select-popup__selected { background: #edf6ff; }
|
||||||
|
.h5-user-select-popup__status { display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 12px; padding: 40px 16px; }
|
||||||
|
.h5-user-select-popup__error { color: #ee0a24; }
|
||||||
|
</style>
|
||||||
@@ -106,7 +106,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChange(val) {
|
onChange(val) {
|
||||||
|
const selected = this.options.find(item => String(item[this.option_value]) === String(val)) || null
|
||||||
this.$emit("change", val)
|
this.$emit("change", val)
|
||||||
|
this.$emit("selected", selected, val)
|
||||||
},
|
},
|
||||||
|
|
||||||
clearOptions() {
|
clearOptions() {
|
||||||
@@ -114,7 +116,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.clearOptions()
|
this.options = this.option_list || []
|
||||||
console.log(this.placeholder)
|
console.log(this.placeholder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,23 +10,22 @@ const act = {
|
|||||||
<div ref="activitySwiper" class="swiper activity-swiper">
|
<div ref="activitySwiper" class="swiper activity-swiper">
|
||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
<div class="swiper-slide" v-for="(activity, index) in actList" :key="activity.id">
|
<div class="swiper-slide" v-for="(activity, index) in actList" :key="activity.id">
|
||||||
<div class="item" role="button" tabindex="0" @click="go(activity)" @keydown.enter="go(activity)" @keydown.space.prevent="go(activity)">
|
<div class="item" @click="go(activity)">
|
||||||
<div class="img-box">
|
<div class="img-box">
|
||||||
<el-image :src="activity.cover" fit="cover" :alt="activity.name">
|
<img :src="activity.cover || 'https://www.ncu.edu.cn/__local/8/52/2C/644986B4C9A030F7B65300178A6_8679CB08_18467.jpg'"
|
||||||
<div slot="error" class="portal-cover-empty"><i class="fa fa-picture-o" aria-hidden="true"></i><span>暂无图片</span></div>
|
alt="">
|
||||||
</el-image>
|
<span class="status">
|
||||||
<span class="status" :class="{'status-ended': getStatusText(activity) === '已结束', 'status-upcoming': getStatusText(activity) === '未开始'}">
|
|
||||||
{{getStatusText(activity)}}
|
{{getStatusText(activity)}}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<h4 class="title" :title="activity.name">
|
<h4 class="title">
|
||||||
{{ activity.name}}
|
{{ activity.name}}
|
||||||
</h4>
|
</h4>
|
||||||
<!--报名时间-->
|
<!--报名时间-->
|
||||||
<div class="time">
|
<div class="time">
|
||||||
<p :title="[activity.startDate, activity.endDate].filter(Boolean).join(' 至 ')">
|
<p>
|
||||||
<i class="fa fa-clock-o"></i>
|
<i class="fa fa-clock-o"></i>
|
||||||
{{ formatActivityDate(activity.startDate) }} 至 {{ formatActivityDate(activity.endDate) }}
|
时间:{{ activity.startDate }}至{{ activity.endDate }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,21 +34,20 @@ const act = {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 导航按钮 -->
|
<!-- 导航按钮 -->
|
||||||
<button type="button" ref="nextButton" class="swiper-button-next" aria-label="下一组活动"></button>
|
<div ref="nextButton" class="swiper-button-next"></div>
|
||||||
<button type="button" ref="prevButton" class="swiper-button-prev" aria-label="上一组活动"></button>
|
<div ref="prevButton" class="swiper-button-prev"></div>
|
||||||
|
|
||||||
<!-- 进度条 -->
|
<!-- 进度条 -->
|
||||||
<div ref="pagination" class="swiper-pagination"></div>
|
<div ref="pagination" class="swiper-pagination"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="no-activity-placeholder">
|
<div v-else class="no-activity-placeholder">
|
||||||
<div class="icon"><i class="fa fa-calendar" aria-hidden="true"></i></div>
|
<div class="icon">📅</div>
|
||||||
<p>暂无近期活动</p>
|
<p>暂无近期活动</p>
|
||||||
<p class="subtext">敬请关注后续通知</p>
|
<p class="subtext">敬请关注后续通知</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
@@ -59,57 +57,19 @@ const act = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 轮播初始化或尺寸变化后,将左右箭头对齐当前封面的垂直中心。
|
/*查询活动*/
|
||||||
updateNavigationPosition() {
|
|
||||||
this.syncBrowseState()
|
|
||||||
const swiperElement = this.$refs.activitySwiper
|
|
||||||
const cover = swiperElement && swiperElement.querySelector('.img-box')
|
|
||||||
if (!cover) return
|
|
||||||
// 按实际封面高度定位,避免标题换行或响应式列数变化导致箭头偏移。
|
|
||||||
const container = swiperElement.parentElement
|
|
||||||
const top = cover.getBoundingClientRect().top - container.getBoundingClientRect().top + cover.offsetHeight / 2
|
|
||||||
;[this.$refs.prevButton, this.$refs.nextButton].forEach(button => {
|
|
||||||
if (button) button.style.top = top + 'px'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// value 为接口返回的活动日期;无日期时显示待定,避免展示 Invalid date。
|
|
||||||
formatActivityDate(value) {
|
|
||||||
return value ? this.$moment(value).format('YYYY-MM-DD') : '待定'
|
|
||||||
},
|
|
||||||
// 按轮播实际停靠点判断是否还有内容,尺寸改变后同步首页按钮文案和可用状态。
|
|
||||||
syncBrowseState() {
|
|
||||||
const enabled = !!(this.swiper && !this.swiper.destroyed && !this.swiper.isLocked && this.swiper.snapGrid.length > 1)
|
|
||||||
this.$emit('browse-state', {
|
|
||||||
enabled: enabled,
|
|
||||||
label: enabled ? '浏览更多' : (this.actList.length ? '已展示全部活动' : '暂无活动')
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 点击前刷新尺寸,避免异步布局导致轮播状态过期;到末组后返回首组。
|
|
||||||
browseNext() {
|
|
||||||
if (!this.swiper || this.swiper.destroyed) this.initSwiper()
|
|
||||||
if (!this.swiper) return
|
|
||||||
this.swiper.update()
|
|
||||||
this.syncBrowseState()
|
|
||||||
if (this.swiper.isLocked || this.swiper.snapGrid.length <= 1) return
|
|
||||||
this.swiper.isEnd ? this.swiper.slideTo(0) : this.swiper.slideNext()
|
|
||||||
},
|
|
||||||
// 无请求参数;data 为当前用户可见且尚未结束的活动数组,保留本校筛选规则。
|
|
||||||
listAct() {
|
listAct() {
|
||||||
this.$axios.post("/platform/home/listHomeActivity").then((res) => {
|
this.$axios.post("/platform/home/listHomeActivity").then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// for (let i = 0; i < 10; i++) {
|
// for (let i = 0; i < 10; i++) {
|
||||||
// this.actList = this.actList.concat(res.data)
|
// this.actList = this.actList.concat(res.data)
|
||||||
// }
|
// }
|
||||||
this.actList = res.data || []
|
this.actList = res.data
|
||||||
// 数据加载完成后初始化Swiper
|
// 数据加载完成后初始化Swiper
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.initSwiper()
|
this.initSwiper()
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
this.$emit('browse-state', {enabled: false, label: '活动加载失败'})
|
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
|
||||||
this.$emit('browse-state', {enabled: false, label: '活动加载失败'})
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/*初始化Swiper*/
|
/*初始化Swiper*/
|
||||||
@@ -120,7 +80,6 @@ const act = {
|
|||||||
}
|
}
|
||||||
const swiperElement = this.$refs.activitySwiper
|
const swiperElement = this.$refs.activitySwiper
|
||||||
if (!swiperElement) {
|
if (!swiperElement) {
|
||||||
this.syncBrowseState()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 仅操作当前组件的轮播节点,避免页面其他轮播或尺寸观察器影响卡片宽度。
|
// 仅操作当前组件的轮播节点,避免页面其他轮播或尺寸观察器影响卡片宽度。
|
||||||
@@ -130,22 +89,13 @@ const act = {
|
|||||||
centeredSlides: false,
|
centeredSlides: false,
|
||||||
loop: false,
|
loop: false,
|
||||||
watchOverflow: true,
|
watchOverflow: true,
|
||||||
// 双栏中的活动按容器宽度排布,避免用整个窗口宽度挤出过多卡片。
|
|
||||||
breakpointsBase: 'container',
|
|
||||||
observer: false,
|
observer: false,
|
||||||
observeParents: false,
|
observeParents: false,
|
||||||
// 页面内容加载后可能出现滚动条,需重新计算列宽,避免末张封面及圆角被裁切。
|
resizeObserver: false,
|
||||||
resizeObserver: true,
|
|
||||||
roundLengths: true,
|
|
||||||
on: {
|
|
||||||
init: () => this.$nextTick(() => this.updateNavigationPosition()),
|
|
||||||
resize: () => this.$nextTick(() => this.updateNavigationPosition()),
|
|
||||||
slidesUpdated: () => this.$nextTick(() => this.updateNavigationPosition()),
|
|
||||||
},
|
|
||||||
// 鼠标停留在活动区域时可横向浏览,到首尾后释放页面滚动。
|
// 鼠标停留在活动区域时可横向浏览,到首尾后释放页面滚动。
|
||||||
mousewheel: {
|
mousewheel: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
forceToAxis: true,
|
forceToAxis: false,
|
||||||
releaseOnEdges: true,
|
releaseOnEdges: true,
|
||||||
sensitivity: 0.8,
|
sensitivity: 0.8,
|
||||||
},
|
},
|
||||||
@@ -158,15 +108,17 @@ const act = {
|
|||||||
type: 'progressbar',
|
type: 'progressbar',
|
||||||
},
|
},
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
480: {
|
768: {
|
||||||
slidesPerView: 2,
|
slidesPerView: 2,
|
||||||
},
|
},
|
||||||
740: {
|
1024: {
|
||||||
slidesPerView: 3,
|
slidesPerView: 4,
|
||||||
|
},
|
||||||
|
1200: {
|
||||||
|
slidesPerView: 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.syncBrowseState()
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// 活动状态
|
// 活动状态
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
const entry = {
|
const entry = {
|
||||||
template: /*language=HTML*/ `
|
template: /*language=HTML*/ `
|
||||||
<div class="entry-wrapper">
|
<div class="entry-wrapper">
|
||||||
<div class="portal-entry-header">
|
<div :class="['entry-section', 'entry-section-' + section.key]" v-for="section in entrySections" :key="section.key">
|
||||||
<div class="portal-entry-tabs" role="tablist" aria-label="推荐入口">
|
<div class="entry-section-header">
|
||||||
<button v-for="section in entrySections" :key="section.key"
|
<div class="entry-section-title">
|
||||||
type="button" role="tab" :aria-selected="activeSection === section.key"
|
<i :class="section.icon"></i>
|
||||||
:class="{active: activeSection === section.key}" @click="$set(this, 'activeSection', section.key)">{{ section.title }}</button>
|
<span>{{ section.title }}</span>
|
||||||
|
<em>/Applications</em>
|
||||||
</div>
|
</div>
|
||||||
<a class="portal-more" href="/platform/v4/apps">全部应用 <i class="fa fa-arrow-right" aria-hidden="true"></i></a>
|
|
||||||
</div>
|
</div>
|
||||||
<div :class="['entry-section', 'entry-section-' + section.key]" v-for="section in entrySections" :key="section.key" v-show="activeSection === section.key" role="tabpanel">
|
|
||||||
|
|
||||||
<div class="apps-container">
|
<div class="apps-container">
|
||||||
<div class="app-grid" tabindex="0" :aria-label="section.title + ',可横向滚动浏览'">
|
<div class="app-grid">
|
||||||
<button type="button" class="app-item"
|
<div class="app-item"
|
||||||
v-for="(item, index) in section.list"
|
v-for="(item, index) in section.list"
|
||||||
:key="item.id || index"
|
:key="item.id || index"
|
||||||
@click="openService(item, section.key)">
|
@click="openService(item, section.key)">
|
||||||
@@ -21,8 +20,8 @@ const entry = {
|
|||||||
<img v-if="item.picIcon" class="app-icon-img" :src="item.picIcon" alt="" />
|
<img v-if="item.picIcon" class="app-icon-img" :src="item.picIcon" alt="" />
|
||||||
<i v-else class="fa fa-cube app-icon-fallback"></i>
|
<i v-else class="fa fa-cube app-icon-fallback"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-name" :title="item.name">{{ item.name }}</div>
|
<div class="app-name">{{ item.name }}</div>
|
||||||
</button>
|
</div>
|
||||||
<el-empty class="app-empty"
|
<el-empty class="app-empty"
|
||||||
v-if="!section.list || section.list.length === 0"
|
v-if="!section.list || section.list.length === 0"
|
||||||
description="暂无数据"
|
description="暂无数据"
|
||||||
@@ -31,12 +30,10 @@ const entry = {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeSection: 'serv',
|
|
||||||
hasMore: true,
|
hasMore: true,
|
||||||
entries: {
|
entries: {
|
||||||
serv: [],
|
serv: [],
|
||||||
@@ -60,8 +57,8 @@ const entry = {
|
|||||||
this.getFavorite()
|
this.getFavorite()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// platform 固定传 PC;Result.data 为当前用户有权限的推荐服务数组。
|
// 查询推荐服务
|
||||||
getRecommendService() {
|
async getRecommendService() {
|
||||||
this.$axios.post('/platform/home/listRecommendService', {platform: "PC"}).then(res => {
|
this.$axios.post('/platform/home/listRecommendService', {platform: "PC"}).then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.entries.serv = res.data
|
this.entries.serv = res.data
|
||||||
@@ -69,8 +66,8 @@ const entry = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// platform 固定传 PC;Result.data 为当前用户可进入的推荐应用数组。
|
// 获取推荐应用
|
||||||
getRecommendApp() {
|
async getRecommendApp() {
|
||||||
this.$axios.post('/platform/home/listRecommendApp', {platform: "PC"}).then(res => {
|
this.$axios.post('/platform/home/listRecommendApp', {platform: "PC"}).then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.entries.app = res.data
|
this.entries.app = res.data
|
||||||
@@ -78,8 +75,8 @@ const entry = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
// platform 固定传 PC;Result.data 为当前用户收藏且有权限的菜单数组。
|
// 获取我的收藏
|
||||||
getFavorite() {
|
async getFavorite() {
|
||||||
this.$axios.post('/platform/home/listFavorite', {platform: "PC"}).then(res => {
|
this.$axios.post('/platform/home/listFavorite', {platform: "PC"}).then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.entries.fav = res.data
|
this.entries.fav = res.data
|
||||||
@@ -130,6 +127,11 @@ const entry = {
|
|||||||
margin-top: 22px;
|
margin-top: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 临时屏蔽“我的收藏”分组,保留原节点和数据逻辑便于恢复 */
|
||||||
|
.entry-section-fav {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.entry-section-header {
|
.entry-section-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -118,53 +118,42 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<link rel="stylesheet" href="${base!}/assets/platform/css/home-portal.css?v=20261028-2" />
|
<div class="v4-container" id="v4-home-app">
|
||||||
|
|
||||||
<div class="v4-container home-portal" id="v4-home-app">
|
|
||||||
<!-- 首页banner -->
|
<!-- 首页banner -->
|
||||||
<div class="portal-top">
|
<div class="section-banner">
|
||||||
<div class="portal-hero">
|
<div class="banner-img">
|
||||||
<!-- 使用参考项目的本地背景资源,保留横幅文字及渐变遮罩。 -->
|
<img :src="homeBannerList[0] || ''" alt=""/>
|
||||||
<img class="portal-hero-background" src="${base!}/assets/platform/img/home/service-portal-banner-campus-v4.png" alt="" />
|
<stats></stats>
|
||||||
<div class="portal-hero-inner">
|
|
||||||
<div class="portal-hero-copy">
|
|
||||||
<div class="portal-hero-eyebrow">教职工一站式服务平台</div>
|
|
||||||
<h1>智慧工会系统</h1>
|
|
||||||
<p>情系教职工,服务零距离</p>
|
|
||||||
<div class="portal-values">
|
|
||||||
<span><i class="fa fa-heart" aria-hidden="true"></i>服务职工</span>
|
|
||||||
<span><i class="fa fa-users" aria-hidden="true"></i>凝聚职工</span>
|
|
||||||
<span><i class="fa fa-leaf" aria-hidden="true"></i>关爱职工</span>
|
|
||||||
<span><i class="fa fa-file-text" aria-hidden="true"></i>助力发展</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<user class="portal-member" :profile-only="true"></user>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="portal-content">
|
<div class="" style="padding-bottom: 20px">
|
||||||
|
<user></user>
|
||||||
|
|
||||||
|
<div class="home-grid">
|
||||||
<div class="entry-card">
|
<div class="entry-card">
|
||||||
<entry></entry>
|
<entry></entry>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="portal-columns">
|
<div class="home-grid">
|
||||||
<div class="home-section portal-panel portal-activities">
|
<div class="home-section">
|
||||||
<div class="home-section-header">
|
<div class="home-section-header">
|
||||||
<div class="home-section-title">
|
<div class="home-section-title">
|
||||||
<i class="fa fa-calendar"></i>
|
<i class="fa fa-calendar"></i>
|
||||||
<span>最新活动</span>
|
<span>最新活动</span>
|
||||||
|
<em>/Activities</em>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="portal-more" :disabled="!activityBrowse.enabled" @click="$refs.homeActivities.browseNext()">{{ activityBrowse.label }} <i v-if="activityBrowse.enabled" class="fa fa-arrow-right" aria-hidden="true"></i></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="act-card">
|
<div class="act-card">
|
||||||
<act ref="homeActivities" @browse-state="updateActivityBrowse"></act>
|
<act></act>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<user ref="homeTodo" class="portal-todo"></user>
|
|
||||||
<work-template class="portal-templates" v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
|
||||||
<jcdt class="portal-news" :class="{'portal-news-wide': !$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])}" :list="websiteNews"></jcdt>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<work-template v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN'])"></work-template>
|
||||||
|
|
||||||
|
<jcdt :list="websiteNews"></jcdt>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -183,7 +172,7 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
data(){
|
data(){
|
||||||
return{
|
return{
|
||||||
websiteNews: [],
|
websiteNews: [],
|
||||||
activityBrowse: {enabled: false, label: '活动加载中'}
|
homeBannerList: "${config.AppHomeImg!}".split(",").map(item => item.trim()).filter(item => item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
@@ -198,14 +187,10 @@ layout("/layouts/v4/baseLayout.html"){
|
|||||||
this.getWebSiteNews()
|
this.getWebSiteNews()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// state 由活动组件发布,enabled 表示可以翻页,label 说明加载或全部展示状态。
|
|
||||||
updateActivityBrowse(state) {
|
|
||||||
this.$set(this, 'activityBrowse', state)
|
|
||||||
},
|
|
||||||
getWebSiteNews(){
|
getWebSiteNews(){
|
||||||
this.$axios.post('/platform/home/getNews').then(res => {
|
this.$axios.post('/platform/home/getNews').then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.$set(this, 'websiteNews', res.data || [])
|
this.websiteNews = res.data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,72 +2,44 @@ const jcdt = {
|
|||||||
template: /*language=HTML*/ `
|
template: /*language=HTML*/ `
|
||||||
<div class="jcdt-wrapper">
|
<div class="jcdt-wrapper">
|
||||||
<div class="jcdt-container">
|
<div class="jcdt-container">
|
||||||
<div class="portal-news-header">
|
<el-carousel height="360px" :interval="10000" indicator-position="none">
|
||||||
<el-dropdown @command="selectSection" trigger="click">
|
<el-carousel-item v-for="item,index in list" :key="index">
|
||||||
<button type="button" class="portal-news-title"><i class="fa fa-bullhorn" aria-hidden="true"></i> {{ currentNews.label }} <i v-if="list.length > 1" class="fa fa-angle-down" aria-hidden="true"></i></button>
|
<div class="jcdt-title">
|
||||||
<el-dropdown-menu slot="dropdown">
|
<span>{{ item.label }}</span>
|
||||||
<el-dropdown-item v-for="(section, index) in list" :key="index" :command="index">{{ section.label }}</el-dropdown-item>
|
</div>
|
||||||
</el-dropdown-menu>
|
<div class="jcdt-content">
|
||||||
</el-dropdown>
|
<div class="jcdt-list">
|
||||||
<div v-if="pageCount > 1" class="portal-news-pager" aria-label="动态分页">
|
<div class="jcdt-item" v-for="o,i in item.value" :key="i" @click="onLink(o)">
|
||||||
<span class="portal-news-count">共 {{ currentNews.value.length }} 条</span>
|
<div class="date" v-if="o.time">
|
||||||
<button type="button" :disabled="pageNumber === 1" title="上一页动态" aria-label="上一页动态" @click="changePage(-1)"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
|
<i class="el-icon-alarm-clock"></i>
|
||||||
<span class="portal-news-page" aria-live="polite">{{ pageNumber }} / {{ pageCount }}</span>
|
<span>{{o.time}}</span>
|
||||||
<button type="button" :disabled="pageNumber === pageCount" title="下一页动态" aria-label="下一页动态" @click="changePage(1)"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
|
</div>
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="title">{{o.text}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="portal-news-list">
|
|
||||||
<button type="button" class="portal-news-row" v-for="(item, index) in visibleNews" :key="index" @click="onLink(item)">
|
|
||||||
<time v-if="item.time" :title="item.time">{{ item.time.slice(5) }}</time>
|
|
||||||
<span :title="item.text">{{ item.text }}</span>
|
|
||||||
</button>
|
|
||||||
<div v-if="!currentNews.value.length" class="portal-empty">暂无动态</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
</el-carousel-item>
|
||||||
|
</el-carousel>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
return {activeIndex: 0, pageNumber: 1, pageSize: 3}
|
return {}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
list: {
|
list: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: []
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
currentNews() {
|
|
||||||
// 默认遵循接口栏目顺序,不再按栏目名称优先选择。
|
|
||||||
const section = this.list[this.activeIndex] || this.list[0]
|
|
||||||
return section ? {label: section.label, value: section.value || []} : {label: '最新动态', value: []}
|
|
||||||
},
|
|
||||||
visibleNews() {
|
|
||||||
const start = (this.pageNumber - 1) * this.pageSize
|
|
||||||
return this.currentNews.value.slice(start, start + this.pageSize)
|
|
||||||
},
|
|
||||||
pageCount() {
|
|
||||||
return Math.max(1, Math.ceil(this.currentNews.value.length / this.pageSize))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
list() {
|
|
||||||
this.selectSection(0)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// step 为翻页方向(-1 上一页、1 下一页);在组件方法中更新页码,避免事件中的 this 指向错误。
|
|
||||||
changePage(step) {
|
|
||||||
const page = Math.max(1, Math.min(this.pageCount, this.pageNumber + step))
|
|
||||||
this.$set(this, 'pageNumber', page)
|
|
||||||
},
|
|
||||||
// index 为接口栏目数组下标;切换栏目时回到第一页,避免沿用上一栏的末页。
|
|
||||||
selectSection(index) {
|
|
||||||
this.activeIndex = index
|
|
||||||
this.pageNumber = 1
|
|
||||||
},
|
|
||||||
onLink(item) {
|
onLink(item) {
|
||||||
// 完整新闻地址直接打开,相对地址仍以重庆工贸工会网站为基准。
|
// 接口返回文章完整地址;相对地址按当前学校工会域名解析。
|
||||||
const url = this.isHttpOrHttps(item.href) ? item.href : new URL(item.href, "https://gh.cqgmy.edu.cn/").href
|
const url = this.isHttpOrHttps(item.href) ? item.href : new URL(item.href, "https://gh.cqgmy.edu.cn/").href
|
||||||
window.open(url)
|
window.open(url)
|
||||||
},
|
},
|
||||||
@@ -76,15 +48,6 @@ const jcdt = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
style: /*language=CSS*/ `
|
style: /*language=CSS*/ `
|
||||||
/* 每页固定三行,不因展开或末页条数变化撑高相邻的模板卡片。 */
|
|
||||||
#v4-home-app .portal-news-list { min-height: 132px; }
|
|
||||||
#v4-home-app .portal-news-list .portal-news-row { height: 44px; padding: 9px 0; }
|
|
||||||
#v4-home-app .portal-news-pager { display: flex; flex-shrink: 0; align-items: center; gap: 8px; }
|
|
||||||
#v4-home-app .portal-news-count { margin-right: 4px; color: #8a9aac; font-size: 12px; }
|
|
||||||
#v4-home-app .portal-news-page { min-width: 32px; color: #637b96; text-align: center; font-size: 12px; font-variant-numeric: tabular-nums; }
|
|
||||||
#v4-home-app .portal-news-pager button { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid #e4edf7; border-radius: 6px; background: #fff; color: #1687f5; font-size: 18px; cursor: pointer; }
|
|
||||||
#v4-home-app .portal-news-pager button:hover:not(:disabled) { border-color: #b9d8fb; background: #f0f7ff; }
|
|
||||||
#v4-home-app .portal-news-pager button:disabled { border-color: #eef2f7; background: #f8fafc; color: #c3cedb; cursor: default; }
|
|
||||||
.jcdt-wrapper {
|
.jcdt-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
|||||||
@@ -5,22 +5,21 @@ const workTemplate = {
|
|||||||
<div class="work-template-title">
|
<div class="work-template-title">
|
||||||
<i class="fa fa-clipboard"></i>
|
<i class="fa fa-clipboard"></i>
|
||||||
<span>工作模板</span>
|
<span>工作模板</span>
|
||||||
|
<em>/Templates</em>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="portal-more" @click="browseTemplates">更多模板 <i class="fa fa-arrow-right" aria-hidden="true"></i></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="work-template-card">
|
<div class="work-template-card">
|
||||||
<div ref="templateGrid" v-if="templateList && templateList.length > 0" class="work-template-grid">
|
<div v-if="templateList && templateList.length > 0" class="work-template-grid">
|
||||||
<button type="button" class="work-template-item"
|
<div class="work-template-item"
|
||||||
v-for="template in templateList"
|
v-for="template in templateList"
|
||||||
:key="template.id"
|
:key="template.id"
|
||||||
@click="go(template)">
|
@click="go(template)">
|
||||||
<div class="work-template-icon">
|
<div class="work-template-icon">
|
||||||
<el-image :src="template.templateIcon || template.cover" fit="contain">
|
<img :src="template.templateIcon || template.cover || 'https://www.ncu.edu.cn/__local/8/52/2C/644986B4C9A030F7B65300178A6_8679CB08_18467.jpg'"
|
||||||
<i slot="error" class="fa fa-clipboard" aria-hidden="true"></i>
|
alt="">
|
||||||
</el-image>
|
</div>
|
||||||
|
<div class="work-template-name">{{ template.templateName || template.name }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="work-template-name" :title="template.templateName || template.name">{{ template.templateName || template.name }}</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="no-activity-placeholder">
|
<div v-else class="no-activity-placeholder">
|
||||||
@@ -29,7 +28,6 @@ const workTemplate = {
|
|||||||
<p class="subtext">敬请关注后续更新</p>
|
<p class="subtext">敬请关注后续更新</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
data() {
|
data() {
|
||||||
@@ -38,15 +36,6 @@ const workTemplate = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 每次滚动一屏模板,到末尾后回到开头;无模板时不执行。
|
|
||||||
browseTemplates() {
|
|
||||||
const grid = this.$refs.templateGrid
|
|
||||||
if (!grid) return
|
|
||||||
// 模板仍使用全部真实数据,横向翻页不截断管理员可用的入口。
|
|
||||||
const atEnd = grid.scrollLeft + grid.clientWidth >= grid.scrollWidth - 2
|
|
||||||
grid.scrollTo({left: atEnd ? 0 : grid.scrollLeft + grid.clientWidth, behavior: 'smooth'})
|
|
||||||
},
|
|
||||||
// 无请求参数;Result.data 为当前管理员可用的工作模板数组。
|
|
||||||
listTemplate() {
|
listTemplate() {
|
||||||
this.$axios.post("/platform/home/listHomeTemplate").then((res) => {
|
this.$axios.post("/platform/home/listHomeTemplate").then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
|
|||||||
@@ -4,17 +4,13 @@ const user = {
|
|||||||
<!-- 用户容器:左右布局 -->
|
<!-- 用户容器:左右布局 -->
|
||||||
<div class="user-container">
|
<div class="user-container">
|
||||||
<!-- 左侧:用户信息卡片 -->
|
<!-- 左侧:用户信息卡片 -->
|
||||||
<div v-if="profileOnly" class="user-info-card">
|
<div class="user-info-card">
|
||||||
<div class="portal-member-date"><i class="fa fa-calendar-o" aria-hidden="true"></i>{{ $moment().format('YYYY年MM月DD日') }} {{ ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'][$moment().day()] }}</div>
|
|
||||||
<div class="user-details">
|
<div class="user-details">
|
||||||
<div class="portal-member-heading">
|
<div class="user-name">${@auth.getPrincipalProperty('username')}</div>
|
||||||
<span class="portal-member-avatar"><i class="fa fa-user" aria-hidden="true"></i></span>
|
|
||||||
<div><div class="portal-member-welcome">欢迎回来</div><div class="user-name">${@auth.getPrincipalProperty('username')}</div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="user-meta-grid">
|
<div class="user-meta-grid">
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<span class="meta-icon"><i class="fa fa-id-card-o" aria-hidden="true"></i></span>
|
<span class="meta-icon">🆔</span>
|
||||||
<div>
|
<div>
|
||||||
<span class="meta-label">工号</span>
|
<span class="meta-label">工号</span>
|
||||||
<span class="meta-value">${@auth.getPrincipalProperty('loginname')}</span>
|
<span class="meta-value">${@auth.getPrincipalProperty('loginname')}</span>
|
||||||
@@ -22,7 +18,7 @@ const user = {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="meta-row">
|
<div class="meta-row">
|
||||||
<span class="meta-icon"><i class="fa fa-building-o" aria-hidden="true"></i></span>
|
<span class="meta-icon">🏢</span>
|
||||||
<div>
|
<div>
|
||||||
<span class="meta-label">单位信息</span>
|
<span class="meta-label">单位信息</span>
|
||||||
<span class="meta-value">
|
<span class="meta-value">
|
||||||
@@ -37,11 +33,11 @@ const user = {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta-row meta-row-roles">
|
<div class="meta-row">
|
||||||
<span class="meta-icon"><i class="fa fa-shield" aria-hidden="true"></i></span>
|
<span class="meta-icon">🎭</span>
|
||||||
<div>
|
<div>
|
||||||
<span class="meta-label">角色</span>
|
<span class="meta-label">角色</span>
|
||||||
<div class="portal-member-roles" tabindex="0" role="region" aria-label="角色列表,可滚动查看全部角色"><span v-for="(role, index) in roleTags" :key="index" class="portal-member-role">{{ role }}</span><span v-if="!roleTags.length" class="meta-value">—</span></div>
|
<span class="meta-value">{{ roleNames || '—' }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -67,13 +63,10 @@ const user = {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧:待办中心 -->
|
<!-- 右侧:待办中心 -->
|
||||||
<div v-if="!profileOnly" class="todo-center">
|
<div class="todo-center">
|
||||||
<!-- 标题和标签 -->
|
<!-- 标题和标签 -->
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="portal-todo-heading">
|
<h3>待办中心</h3>
|
||||||
<h3><i class="fa fa-list-ul" aria-hidden="true"></i> 待办中心</h3>
|
|
||||||
<a class="portal-more" :href="'/flow/todoCenter?status=' + activeTab" target="_blank">全部待办 <i class="fa fa-arrow-right" aria-hidden="true"></i></a>
|
|
||||||
</div>
|
|
||||||
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabClick">
|
<el-tabs v-model="activeTab" type="card" @tab-click="handleTabClick">
|
||||||
<el-tab-pane :label="tabLabel('待办事宜', taskStats.todoCount)" name="todo"></el-tab-pane>
|
<el-tab-pane :label="tabLabel('待办事宜', taskStats.todoCount)" name="todo"></el-tab-pane>
|
||||||
<el-tab-pane :label="tabLabel('已办事宜', taskStats.doneCount)" name="done"></el-tab-pane>
|
<el-tab-pane :label="tabLabel('已办事宜', taskStats.doneCount)" name="done"></el-tab-pane>
|
||||||
@@ -82,39 +75,55 @@ const user = {
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="portal-task-list" v-loading="tableLoading">
|
<!-- 表格 -->
|
||||||
<div class="portal-task-row" v-for="(task, index) in tableData" :key="task.taskId || task.instanceId || index">
|
<el-table
|
||||||
<i class="fa fa-file-text-o portal-task-icon" aria-hidden="true"></i>
|
:data="todoList"
|
||||||
<div class="portal-task-content">
|
style="width: 100%"
|
||||||
<div class="portal-task-title" :title="task.instanceName">{{ task.instanceName }}</div>
|
border
|
||||||
<div class="portal-task-meta">
|
stripe
|
||||||
<span :title="task.variable && task.variable.initiatorName">申请人:{{ (task.variable && task.variable.initiatorName) || '—' }}</span>
|
v-loading="loading"
|
||||||
<span class="portal-task-node" :title="[task.categoryName, task.taskName].filter(Boolean).join(' · ')">{{ [task.categoryName, task.taskName].filter(Boolean).join(' · ') }}</span>
|
:cell-style="{ padding: '8px' }"
|
||||||
</div>
|
:header-cell-style="{ background: '#f8f9fa', color: '#444', fontWeight: '500' }"
|
||||||
</div>
|
>
|
||||||
<time class="portal-task-date">{{ task.createdAt ? $moment(task.createdAt).format('YYYY-MM-DD') : '—' }}</time>
|
<el-table-column label="序号" type="index" :index="indexMethod" width="100px"></el-table-column>
|
||||||
<el-button type="primary" size="mini" @click="openView(task)">查看</el-button>
|
<el-table-column prop="categoryName" label="流程分类" width="100"></el-table-column>
|
||||||
</div>
|
<el-table-column prop="title" label="流程名称" min-width="300">
|
||||||
<div v-if="!tableLoading && !tableData.length" class="portal-empty"><i class="fa fa-check-circle-o" aria-hidden="true"></i><span>暂无{{ activeTab === 'todo' ? '待办事项' : '相关记录' }}</span></div>
|
<template slot-scope="scope">
|
||||||
<slot></slot>
|
<el-tooltip effect="dark" :content="scope.row.instanceName" placement="top">
|
||||||
</div>
|
<span class="table-title">{{ scope.row.instanceName }}</span>
|
||||||
<el-pagination v-if="pageForm.totalCount > pageForm.pageSize" class="portal-task-pagination"
|
</el-tooltip>
|
||||||
@current-change="pageNumberChange" :current-page="pageForm.pageNumber" :page-size="pageForm.pageSize"
|
</template>
|
||||||
layout="total, prev, next" :total="pageForm.totalCount"></el-pagination>
|
</el-table-column>
|
||||||
|
<el-table-column prop="sender" label="申请人" width="120">
|
||||||
|
<template slot-scope="{row}">{{row.variable.initiatorName}}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="taskName" label="当前流程节点" width="140" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column prop="date" label="发起日期" width="120">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
{{$moment(row.createdAt).format('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="100px" fixed="right">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button type="primary" size="mini" @click="openView(scope.row)">查看</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
mixins: [initTableMixins],
|
mixins: [initTableMixins],
|
||||||
// 同一组件分别承载会员卡和待办卡,各自只加载需要的数据。
|
|
||||||
props: {
|
|
||||||
profileOnly: { type: Boolean, default: false }
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
activeTab: 'todo',
|
activeTab: 'todo',
|
||||||
|
todoList: [],
|
||||||
|
loading: false,
|
||||||
pageForm: {
|
pageForm: {
|
||||||
pageSize: 3
|
pageNum: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
totalCount: 0
|
||||||
},
|
},
|
||||||
taskStats: {
|
taskStats: {
|
||||||
todoCount: 0,
|
todoCount: 0,
|
||||||
@@ -131,12 +140,6 @@ const user = {
|
|||||||
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
roleTags() {
|
|
||||||
// 兼容角色接口已有的中英文分隔符,仅改变展示,不改变角色权限。
|
|
||||||
return String(this.roleNames || '').split(/[,,、;;]/).map(role => role.trim()).filter(Boolean)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
getWeatherInfo(iconCode, temp) {
|
getWeatherInfo(iconCode, temp) {
|
||||||
const info = {
|
const info = {
|
||||||
@@ -186,60 +189,91 @@ const user = {
|
|||||||
|
|
||||||
return info;
|
return info;
|
||||||
},
|
},
|
||||||
// key 为系统配置名称;返回 Promise,值为 Result.data 中的经度或纬度。
|
async getConfigKey(key) {
|
||||||
getConfigKey(key) {
|
const resp = await this.$axios.post("/open/common/getConfigKey", { key })
|
||||||
return this.$axios.post("/open/common/getConfigKey", {key}).then(res => res.data)
|
return resp.data
|
||||||
},
|
},
|
||||||
// 使用本校配置经纬度查询城市及天气,缺少配置时不请求外部天气接口。
|
// 🔆 获取天气
|
||||||
fetchWeather() {
|
async fetchWeather() {
|
||||||
Promise.all([this.getConfigKey("AppMapCenterPointX"), this.getConfigKey("AppMapCenterPointY")])
|
try {
|
||||||
.then(coordinates => {
|
// 存localStorage 112.13,32.01 广州 113.27,23.14
|
||||||
if (!coordinates[0] || !coordinates[1]) return
|
const AppMapCenterPointX = await this.getConfigKey("AppMapCenterPointX")
|
||||||
return this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/geo/v2/city/lookup?location=" + coordinates.join(",") + "&key=" + this.QWEATHER_KEY)
|
const AppMapCenterPointY = await this.getConfigKey("AppMapCenterPointY")
|
||||||
.then(geoRes => {
|
if (!AppMapCenterPointX || !AppMapCenterPointY){
|
||||||
if (geoRes.code !== '200' || !geoRes.location || !geoRes.location.length) {
|
return
|
||||||
throw new Error('城市未找到')
|
|
||||||
}
|
}
|
||||||
const city = geoRes.location[0]
|
|
||||||
return this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/v7/weather/now?location=" + city.id + "&key=" + this.QWEATHER_KEY)
|
// 1. 先通过城市名获取 locationId
|
||||||
.then(weatherRes => {
|
this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/geo/v2/city/lookup?location=" + AppMapCenterPointX + "," + AppMapCenterPointY + "&key=" + this.QWEATHER_KEY).then((geoRes) => {
|
||||||
if (weatherRes.code !== '200' || !weatherRes.now) throw new Error('天气数据异常')
|
if (geoRes.code !== '200' || !geoRes.location?.[0]) {
|
||||||
this.weatherData = Object.assign({}, this.getWeatherInfo(weatherRes.now.icon, weatherRes.now.temp), {
|
console.log('城市未找到')
|
||||||
temp: weatherRes.now.temp, text: weatherRes.now.text, name: city.name
|
}
|
||||||
|
const locationId = geoRes.location[0].id;
|
||||||
|
|
||||||
|
// 2. 获取当前天气
|
||||||
|
this.$axios.get("https://mx5rk62kvj.re.qweatherapi.com/v7/weather/now?location=" + locationId + "&key=" + this.QWEATHER_KEY).then((weatherRes) => {
|
||||||
|
if (weatherRes.code !== '200') {
|
||||||
|
console.warn('天气数据异常:', weatherRes);
|
||||||
|
}
|
||||||
|
const weatherInfo = this.getWeatherInfo(weatherRes.now.icon, weatherRes.now.temp);
|
||||||
|
this.weatherData = {
|
||||||
|
...weatherInfo,
|
||||||
|
temp: weatherRes.now.temp,
|
||||||
|
text: weatherRes.now.text,
|
||||||
|
name: geoRes.location[0].name
|
||||||
|
};
|
||||||
|
this.weatherError = false;
|
||||||
})
|
})
|
||||||
this.weatherError = false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.weatherError = true
|
|
||||||
this.weatherData = null
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('天气加载失败:', err);
|
||||||
|
this.weatherError = true;
|
||||||
|
this.weatherData = null;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 获取任务列表
|
// 获取任务列表
|
||||||
tabLabel(title, count) {
|
tabLabel(title, count) {
|
||||||
return title + "(" + (count || 0) + ")"
|
return title + "(" + (count || 0) + ")"
|
||||||
},
|
},
|
||||||
// 无请求参数;data 的四个 Count 字段分别为当前用户各状态流程数量。
|
async getStatistics() {
|
||||||
getStatistics() {
|
try {
|
||||||
this.$axios.post("/flow/todoCenter/statistics").then(res => {
|
const res = await $.post("/flow/todoCenter/statistics")
|
||||||
if (res.code === 0) this.taskStats = Object.assign({}, this.taskStats, res.data)
|
if (res.code === 0) {
|
||||||
}).catch(() => {
|
this.taskStats = Object.assign({}, this.taskStats, res.data)
|
||||||
this.$message.error("获取待办统计失败")
|
}
|
||||||
})
|
} catch (error) {
|
||||||
|
console.error("获取待办统计失败:", error)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getTasks() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await $.post("/flow/todoCenter/" + this.activeTab, this.pageForm)
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.todoList = res.data.list
|
||||||
|
this.pageForm.totalCount = res.data.totalCount
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error("获取任务列表失败")
|
||||||
|
console.error("获取任务列表失败:", error)
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// WF 状态由 activeTab 决定;pageForm 传分页参数,data.list/totalCount 为记录及总数。
|
|
||||||
// 列表加载和翻页由 initTableMixins 统一处理,首页只补充状态地址和数量统计。
|
|
||||||
pageData() {
|
pageData() {
|
||||||
this.pageDataUrl = "/flow/todoCenter/" + this.activeTab
|
this.getTasks()
|
||||||
initTableMixins.methods.pageData.call(this)
|
|
||||||
this.getStatistics()
|
this.getStatistics()
|
||||||
},
|
},
|
||||||
handleTabClick() {
|
handleTabClick(tab) {
|
||||||
this.doSearch()
|
this.pageData()
|
||||||
|
console.log('切换到:', tab.name);
|
||||||
},
|
},
|
||||||
// 处理任务
|
// 处理任务
|
||||||
openView(task) {
|
async openView(task) {
|
||||||
|
console.log(task)
|
||||||
const {taskId, taskKey, taskState, instanceId, businessNo, formKey} = task
|
const {taskId, taskKey, taskState, instanceId, businessNo, formKey} = task
|
||||||
if (!formKey) {
|
if (!formKey) {
|
||||||
this.$message.warning("当前流程没有配置地址")
|
this.$message.warning("当前流程没有配置地址")
|
||||||
@@ -247,9 +281,8 @@ const user = {
|
|||||||
}
|
}
|
||||||
window.open(formKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
window.open(formKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
||||||
},
|
},
|
||||||
// 无请求参数;Result.data.roleNames 为当前登录人的角色名称字符串。
|
|
||||||
getRoleNames() {
|
getRoleNames() {
|
||||||
this.$axios.post("/platform/sys/role/getRoleNames").then(res => {
|
$.post("/platform/sys/role/getRoleNames").then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.roleNames = res.data.roleNames
|
this.roleNames = res.data.roleNames
|
||||||
}
|
}
|
||||||
@@ -258,45 +291,13 @@ const user = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.profileOnly) {
|
|
||||||
this.getRoleNames()
|
|
||||||
} else {
|
|
||||||
this.pageData()
|
this.pageData()
|
||||||
}
|
this.getRoleNames()
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.profileOnly) this.fetchWeather()
|
this.fetchWeather()
|
||||||
},
|
},
|
||||||
style: /*language=CSS*/ `
|
style: /*language=CSS*/ `
|
||||||
/* 会员卡样式随组件注入,确保与卡片结构同步加载,避免旧外链样式造成排版缺失。 */
|
|
||||||
#v4-home-app .portal-member { min-width: 0; }
|
|
||||||
#v4-home-app .portal-member .user-info-card { height: 100%; padding: 20px; gap: 14px; border: 1px solid #e3edf8; border-radius: 12px; background: linear-gradient(180deg, #f1f7ff 0, #fff 110px); box-shadow: 0 3px 14px rgba(30,66,108,.035); }
|
|
||||||
#v4-home-app .portal-member-date { display: flex; align-items: center; gap: 8px; color: #71839b; font-size: 12px; line-height: 20px; }
|
|
||||||
#v4-home-app .portal-member-heading { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid #eaf0f7; }
|
|
||||||
#v4-home-app .portal-member-heading > div { min-width: 0; }
|
|
||||||
#v4-home-app .portal-member-avatar { display: flex; align-items: center; justify-content: center; flex: 0 0 46px; height: 46px; border-radius: 50%; background: #e1eeff; color: #1687f5; font-size: 25px; }
|
|
||||||
#v4-home-app .portal-member-welcome { margin-bottom: 3px; color: #8797a9; font-size: 12px; line-height: 18px; }
|
|
||||||
#v4-home-app .portal-member .user-name { margin: 0; color: #163c61; text-align: left; font-size: 18px; line-height: 24px; overflow-wrap: anywhere; }
|
|
||||||
#v4-home-app .portal-member .user-meta-grid { gap: 12px; margin: 0; }
|
|
||||||
#v4-home-app .portal-member .meta-row { gap: 8px; }
|
|
||||||
#v4-home-app .portal-member .meta-icon { min-width: 18px; color: #81a4c9; font-size: 14px; }
|
|
||||||
#v4-home-app .portal-member .meta-row > div { display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 8px; min-width: 0; }
|
|
||||||
#v4-home-app .portal-member .meta-label { margin: 0; color: #8995a5; font-size: 12px; line-height: 20px; }
|
|
||||||
#v4-home-app .portal-member .meta-value { color: #283c54; font-size: 12px; font-weight: 400; line-height: 20px; overflow-wrap: anywhere; }
|
|
||||||
#v4-home-app .portal-member .meta-row-roles > div { display: block; }
|
|
||||||
/* 角色最多占用三行标签的高度,超出时内部滚动,避免撑高首页横幅。 */
|
|
||||||
#v4-home-app .portal-member-roles { display: flex; flex-wrap: wrap; align-content: flex-start; gap: 5px; margin-top: 5px; max-height: 88px; overflow-y: auto; overflow-x: hidden; scrollbar-width: thin; scrollbar-color: #c5d9ee transparent; }
|
|
||||||
#v4-home-app .portal-member-roles::-webkit-scrollbar { width: 4px; }
|
|
||||||
#v4-home-app .portal-member-roles::-webkit-scrollbar-thumb { background: #c5d9ee; border-radius: 4px; }
|
|
||||||
#v4-home-app .portal-member-role { max-width: 100%; display: inline-block; padding: 3px 8px; border: 1px solid #e1ebf7; border-radius: 5px; background: #f3f7fc; color: #46617f; font-size: 12px; line-height: 18px; overflow-wrap: anywhere; }
|
|
||||||
#v4-home-app .portal-member .weather-section { margin-top: auto; padding: 8px 10px; border-radius: 8px; background: #f0f7ff; color: #527494; }
|
|
||||||
#v4-home-app .portal-member .weather-header { gap: 6px; }
|
|
||||||
#v4-home-app .portal-member .weather-location,
|
|
||||||
#v4-home-app .portal-member .weather-text { font-size: 12px; }
|
|
||||||
#v4-home-app .portal-member .weather-emoji { font-size: 20px; }
|
|
||||||
#v4-home-app .portal-member .weather-temp { font-size: 18px; }
|
|
||||||
#v4-home-app .portal-member .weather-tip { margin-top: 4px; font-size: 11px; line-height: 18px; }
|
|
||||||
#v4-home-app .portal-member .weather-error { margin-top: auto; padding: 8px; font-size: 12px; }
|
|
||||||
.user-wrapper {
|
.user-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>-->
|
</el-descriptions-item>-->
|
||||||
<el-descriptions-item label="证明人">
|
<!-- <el-descriptions-item label="证明人">
|
||||||
<el-form-item prop="certifierUserId" label="证明人">
|
<el-form-item prop="certifierUserId" label="证明人">
|
||||||
<el-select
|
<el-select
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@@ -75,7 +75,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item> -->
|
||||||
<el-descriptions-item label="慰问类型">
|
<el-descriptions-item label="慰问类型">
|
||||||
<el-form-item prop="type" label="慰问类型">
|
<el-form-item prop="type" label="慰问类型">
|
||||||
<el-select v-model="formData.type" @change="typeChange" style="width: 100%"
|
<el-select v-model="formData.type" @change="typeChange" style="width: 100%"
|
||||||
@@ -112,14 +112,14 @@ layout("/layouts/platform.html"){
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="收款账户">
|
<el-descriptions-item label="收款账户" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||||
<el-form-item prop="bankCardNumber" label="收款账户">
|
<el-form-item prop="bankCardNumber" label="收款账户">
|
||||||
<el-input maxlength="20" v-model="formData.bankCardNumber" placeholder="请填写收款账户"
|
<el-input maxlength="30" v-model="formData.bankCardNumber" placeholder="请填写银行卡号或对公账户号"
|
||||||
></el-input>
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="户名">
|
<el-descriptions-item label="户名" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||||
<el-form-item prop="bankUserName" label="户名">
|
<el-form-item prop="bankUserName" label="户名">
|
||||||
<el-input maxlength="20" v-model="formData.bankUserName"
|
<el-input maxlength="20" v-model="formData.bankUserName"
|
||||||
placeholder="请填写户名"
|
placeholder="请填写户名"
|
||||||
@@ -127,7 +127,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="开户行" >
|
<el-descriptions-item label="开户行" v-if="!['A', 'D'].includes(formData.typeCode)">
|
||||||
<el-form-item prop="bankOfDeposit" label="开户行">
|
<el-form-item prop="bankOfDeposit" label="开户行">
|
||||||
<el-input maxlength="20" v-model="formData.bankOfDeposit"
|
<el-input maxlength="20" v-model="formData.bankOfDeposit"
|
||||||
placeholder="请填写开户行"
|
placeholder="请填写开户行"
|
||||||
@@ -173,10 +173,12 @@ layout("/layouts/platform.html"){
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
</el-descriptions>
|
||||||
|
<el-descriptions :column="3" border>
|
||||||
<el-descriptions-item label="申请事由" :span="3">
|
<el-descriptions-item label="申请事由" :span="3">
|
||||||
<el-form-item prop="remark" label="申请事由">
|
<el-form-item prop="remark" label="申请事由">
|
||||||
<el-input maxlength="500" v-model="formData.remark" placeholder="请填写申请事由"
|
<el-input maxlength="500" v-model="formData.remark" placeholder="请填写申请事由"
|
||||||
type="textarea" :autosize="{ minRows: 4, maxRows: 8}"></el-input>
|
type="textarea" :rows="3" resize="none"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
@@ -238,7 +240,10 @@ layout("/layouts/platform.html"){
|
|||||||
payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
payUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
type: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
way: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
way: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
money: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
money: [
|
||||||
|
{ required: true, message: "请填写慰问金额", trigger: ["change", "blur"] },
|
||||||
|
{ validator: (rule, value, callback) => callback(this.validateMoney(value) ? undefined : new Error("慰问金额须大于0且不超过10000元,最多两位小数")), trigger: ["change", "blur"] }
|
||||||
|
],
|
||||||
occurTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
occurTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
child: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
child: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
hospital: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
hospital: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
@@ -247,14 +252,20 @@ layout("/layouts/platform.html"){
|
|||||||
hospitalBy: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
hospitalBy: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
deadImmediateFamily: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
deadImmediateFamily: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
remark: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
files: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
files: [{ required: true, type: "array", min: 1, max: 5, message: "请上传1至5个附件", trigger: ["change", "blur"] }],
|
||||||
signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
// certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
bankCardNumber: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
bankCardNumber: [
|
||||||
|
{ required: true, message: "请填写银行卡号或对公账户号", trigger: ["change", "blur"] },
|
||||||
|
{ pattern: /^[0-9]{6,30}$/, message: "收款账户须为6至30位数字(银行卡号或对公账户号)", trigger: ["change", "blur"] }
|
||||||
|
],
|
||||||
bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
thisYearHospitalizationNum: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
thisYearHospitalizationNum: [
|
||||||
|
{ required: true, message: "必填", trigger: ["change", "blur"] },
|
||||||
|
{ type: "integer", min: 0, max: 10000, message: "住院次数须为0至10000的整数", trigger: ["change", "blur"] }
|
||||||
|
],
|
||||||
leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
},
|
},
|
||||||
@@ -268,6 +279,9 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
validateMoney(value) {
|
||||||
|
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||||
|
},
|
||||||
createRemoteMethod(options) {
|
createRemoteMethod(options) {
|
||||||
return (keyword) => {
|
return (keyword) => {
|
||||||
this.selectQueryUser(keyword, options)
|
this.selectQueryUser(keyword, options)
|
||||||
|
|||||||
@@ -62,13 +62,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||||
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
||||||
<el-button v-if="row.canRevoke" size="mini" type="danger" @click="onRevoke(row)">撤回</el-button>
|
<el-button v-if="row.canRevoke" size="mini" type="danger" @click="onRevoke(row)">撤回</el-button>
|
||||||
<el-dropdown v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" trigger="click" @command="format => doExportApply(row, format)">
|
<el-button v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" @click="doExportApply(row)" size="mini" type="primary">导出</el-button>
|
||||||
<el-button size="mini" type="primary">导出</el-button>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item command="pdf">导出 PDF</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="word">导出 Word</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">
|
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -109,8 +103,8 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
doExportApply(row, format) {
|
doExportApply(row) {
|
||||||
this.$downLoad('/platform/condolence/mine/doExportApply?id=' + row.id + '&print=' + (format === 'pdf'))
|
this.$downLoad('/platform/condolence/mine/doExportApply?id=' + row.id + '&print=false')
|
||||||
},
|
},
|
||||||
onAdd() {
|
onAdd() {
|
||||||
commonUtil.pjaxPush('/platform/condolence/apply')
|
commonUtil.pjaxPush('/platform/condolence/apply')
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ const basicForm = {
|
|||||||
<el-radio-button :label="false">不上传</el-radio-button>
|
<el-radio-button :label="false">不上传</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>-->
|
</el-form-item>-->
|
||||||
<!-- <el-form-item label="是否上传附件" prop="isUploadFile">-->
|
<el-form-item label="是否上传附件" prop="isUploadFile">
|
||||||
<!-- <el-radio-group v-model="formData.isUploadFile">-->
|
<el-radio-group v-model="formData.isUploadFile">
|
||||||
<!-- <el-radio-button :label="true">是</el-radio-button>-->
|
<el-radio-button :label="true">是</el-radio-button>
|
||||||
<!-- <el-radio-button :label="false">否</el-radio-button>-->
|
<el-radio-button :label="false">否</el-radio-button>
|
||||||
<!-- </el-radio-group>-->
|
</el-radio-group>
|
||||||
<!-- </el-form-item>-->
|
</el-form-item>
|
||||||
<el-form-item label="上传附件说明" prop="uploadFileDesc" v-if="formData.isUploadFile">
|
<el-form-item label="上传附件说明" prop="uploadFileDesc" v-if="formData.isUploadFile">
|
||||||
<el-input v-model="formData.uploadFileDesc" maxlength="50" clearable placeholder="请填写上传附件说明"></el-input>
|
<el-input v-model="formData.uploadFileDesc" maxlength="50" clearable placeholder="请填写上传附件说明"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
+82
-62
@@ -1,8 +1,9 @@
|
|||||||
<!--#
|
<!--#
|
||||||
layout("/layouts/platform.html"){
|
layout("/layouts/platform.html"){
|
||||||
#-->
|
#-->
|
||||||
<div id="app">
|
<div id="app" v-cloak>
|
||||||
<el-card shadow="never" v-if="isShow">
|
<el-card shadow="never" v-if="pageLoading" v-loading="pageLoading" element-loading-text="正在加载申请信息" style="min-height: 300px"></el-card>
|
||||||
|
<el-card shadow="never" v-else-if="isShow">
|
||||||
<snaker-start slot="header" label="困难帮扶申请" define_key="KNBF"></snaker-start>
|
<snaker-start slot="header" label="困难帮扶申请" define_key="KNBF"></snaker-start>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" class="flow-task-form">
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":" class="flow-task-form">
|
||||||
<el-descriptions :column="3" border>
|
<el-descriptions :column="3" border>
|
||||||
@@ -26,7 +27,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="受补助人">
|
<el-descriptions-item label="受补助人">
|
||||||
<el-form-item prop="userName">
|
<el-form-item prop="userId">
|
||||||
<template v-if="formData.mode == 2">
|
<template v-if="formData.mode == 2">
|
||||||
<el-select :remote-method="queryRecipients"
|
<el-select :remote-method="queryRecipients"
|
||||||
@change="userChange" clearable filterable
|
@change="userChange" clearable filterable
|
||||||
@@ -51,7 +52,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="身份证号" :span="2">
|
<el-descriptions-item label="身份证号" :span="2">
|
||||||
<el-form-item prop="idCard">
|
<el-form-item prop="idCard">
|
||||||
<el-input maxlength="20" clearable placeholder="请填写身份证号"
|
<el-input clearable placeholder="请填写身份证号"
|
||||||
v-model="formData.idCard" maxlength="18"></el-input>
|
v-model="formData.idCard" maxlength="18"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -84,7 +85,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-descriptions-item label="手机号码">
|
<el-descriptions-item label="手机号码">
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input maxlength="11" clearable placeholder="请填写手机号码"
|
<el-input maxlength="11" clearable placeholder="请填写手机号码"
|
||||||
v-model="formData.mobile" maxlength="11"></el-input>
|
v-model="formData.mobile"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="家庭年总收入(万元)">
|
<el-descriptions-item label="家庭年总收入(万元)">
|
||||||
@@ -103,6 +104,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-input-number
|
<el-input-number
|
||||||
v-model="formData.homeNumber"
|
v-model="formData.homeNumber"
|
||||||
:min="1"
|
:min="1"
|
||||||
|
:precision="0"
|
||||||
:step="1"
|
:step="1"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
placeholder="请填写家庭人数">
|
placeholder="请填写家庭人数">
|
||||||
@@ -113,7 +115,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-form-item prop="homeAddress">
|
<el-form-item prop="homeAddress">
|
||||||
<el-input clearable
|
<el-input clearable
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
v-model="formData.homeAddress"
|
v-model="formData.homeAddress" maxlength="200"
|
||||||
placeholder="请填写家庭住址">
|
placeholder="请填写家庭住址">
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -132,7 +134,7 @@ layout("/layouts/platform.html"){
|
|||||||
<!-- </el-descriptions-item>-->
|
<!-- </el-descriptions-item>-->
|
||||||
<el-descriptions-item label="银行卡号" >
|
<el-descriptions-item label="银行卡号" >
|
||||||
<el-form-item prop="bankCardNum">
|
<el-form-item prop="bankCardNum">
|
||||||
<el-input maxlength="20" clearable placeholder="请填写银行卡号"
|
<el-input maxlength="19" clearable placeholder="请填写银行卡号"
|
||||||
v-model="formData.bankCardNum"></el-input>
|
v-model="formData.bankCardNum"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -152,7 +154,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<el-descriptions-item label="申请金额(元)">
|
<el-descriptions-item label="申请金额(元)">
|
||||||
<el-form-item prop="applyMoney" :rules="[{required:true,type:'number',min:0.01,message:'请填写大于零的申请金额',trigger:['change','blur']}]">
|
<el-form-item prop="applyMoney">
|
||||||
<el-input-number v-model="formData.applyMoney" :precision="2" :min="0.01" placeholder="请输入申请金额"></el-input-number>
|
<el-input-number v-model="formData.applyMoney" :precision="2" :min="0.01" placeholder="请输入申请金额"></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
@@ -198,8 +200,8 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.relation'"
|
:prop="'familyList.'+$index+'.relation'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="textRules('与本人关系', 50)">
|
||||||
<el-input v-model="row.relation" placeholder="请填写与本人关系" clearable></el-input>
|
<el-input v-model="row.relation" maxlength="50" placeholder="请填写与本人关系" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -207,8 +209,8 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.name'"
|
:prop="'familyList.'+$index+'.name'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="textRules('姓名', 100)">
|
||||||
<el-input v-model="row.name" placeholder="请填写姓名" clearable></el-input>
|
<el-input v-model="row.name" maxlength="100" placeholder="请填写姓名" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -216,9 +218,9 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.age'"
|
:prop="'familyList.'+$index+'.age'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="[{required:true,type:'integer',min:1,max:100,message:'年龄须为1至100的整数',trigger:['change','blur']}]">
|
||||||
<el-input-number v-model="row.age" placeholder="年龄" :min="1"
|
<el-input-number v-model="row.age" placeholder="年龄" :min="1"
|
||||||
:max="100" :step="1" style="width: 100%" clearable></el-input-number>
|
:max="100" :precision="0" :step="1" style="width: 100%" clearable></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -226,8 +228,8 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.homeUnit'"
|
:prop="'familyList.'+$index+'.homeUnit'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="textRules('工作单位', 200)">
|
||||||
<el-input v-model="row.homeUnit" placeholder="请填写工作单位" clearable></el-input>
|
<el-input v-model="row.homeUnit" maxlength="200" placeholder="请填写工作单位" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -235,9 +237,9 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.yearIncome'"
|
:prop="'familyList.'+$index+'.yearIncome'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="[{validator:validateIncome,required:true,trigger:['change','blur']}]">
|
||||||
<el-input-number v-model="row.yearIncome" placeholder="年收入"
|
<el-input-number v-model="row.yearIncome" placeholder="年收入"
|
||||||
:min="0" :step="1" style="width: 100%" clearable></el-input-number>
|
:min="0" :precision="2" :step="1" style="width: 100%" clearable></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -245,8 +247,8 @@ layout("/layouts/platform.html"){
|
|||||||
<template slot-scope="{row,$index}">
|
<template slot-scope="{row,$index}">
|
||||||
<el-form-item label-width="0"
|
<el-form-item label-width="0"
|
||||||
:prop="'familyList.'+$index+'.remarks'"
|
:prop="'familyList.'+$index+'.remarks'"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="textRules('备注', 500)">
|
||||||
<el-input v-model="row.remarks" placeholder="请填写备注" clearable></el-input>
|
<el-input v-model="row.remarks" maxlength="500" placeholder="请填写备注" clearable></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -317,6 +319,7 @@ layout("/layouts/platform.html"){
|
|||||||
bizId: GetQueryString("bizId"),
|
bizId: GetQueryString("bizId"),
|
||||||
taskId: GetQueryString("taskId"),
|
taskId: GetQueryString("taskId"),
|
||||||
isShow: false,
|
isShow: false,
|
||||||
|
pageLoading: true,
|
||||||
time: '',
|
time: '',
|
||||||
blockMessage: '',
|
blockMessage: '',
|
||||||
formData: {
|
formData: {
|
||||||
@@ -326,22 +329,37 @@ layout("/layouts/platform.html"){
|
|||||||
applyCount: '1',
|
applyCount: '1',
|
||||||
},
|
},
|
||||||
formRules: {
|
formRules: {
|
||||||
proxyUserName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
proxyUserName: this.textRules('填写人姓名', 100),
|
||||||
proxyLoginName: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
proxyLoginName: this.textRules('填写人工号', 100),
|
||||||
sex: [{required: true, message: '请填写性别', trigger: ['blur', 'change']}],
|
mode: [{required: true, type: 'enum', enum: ['1', '2'], message: '请选择申请模式', trigger: ['blur', 'change']}],
|
||||||
userName: [{required: true, message: '请填写受补助人', trigger: ['blur', 'change']}],
|
sex: [{required: true, type: 'enum', enum: ['男', '女'], message: '请选择性别', trigger: ['blur', 'change']}],
|
||||||
unitName: [{required: true, message: '请填写所属单位', trigger: ['blur', 'change']}],
|
userId: [{required: true, message: '请选择受补助人', trigger: ['blur', 'change']}],
|
||||||
|
unitName: this.textRules('所属单位', 500),
|
||||||
unionName: [{required: true, message: '请填写所属工会', trigger: ['blur', 'change']}],
|
unionName: [{required: true, message: '请填写所属工会', trigger: ['blur', 'change']}],
|
||||||
homeAddress: [{required: true, message: '请填写家庭住址', trigger: ['blur', 'change']}],
|
homeAddress: this.textRules('家庭住址', 200),
|
||||||
mobile: [{required: true, message: '请填写手机号码', trigger: ['blur', 'change']}],
|
mobile: [
|
||||||
idCard: [{required: true, message: '请填写身份证号', trigger: ['blur', 'change']}],
|
{required: true, message: '请填写手机号码', trigger: ['blur', 'change']},
|
||||||
bankCardNum: [{required: true, message: '请填写收款账户卡号', trigger: ['blur', 'change']}],
|
{pattern: /^1[3-9]\d{9}$/, message: '请输入正确的11位手机号码', trigger: ['blur', 'change']}
|
||||||
|
],
|
||||||
|
idCard: [{validator: (rule, value, callback) => {
|
||||||
|
const result = this.isValidIdCard(value || '')
|
||||||
|
callback(result.status === 0 ? new Error(result.msg) : undefined)
|
||||||
|
}, required: true, trigger: ['blur', 'change']}],
|
||||||
|
bankCardNum: [{validator: (rule, value, callback) => {
|
||||||
|
const result = this.validateCard(value || '')
|
||||||
|
callback(result.status === 0 ? new Error(result.msg) : undefined)
|
||||||
|
}, required: true, trigger: ['blur', 'change']}],
|
||||||
bankUserName: [{required: true, message: '请填写户名', trigger: ['blur', 'change']}],
|
bankUserName: [{required: true, message: '请填写户名', trigger: ['blur', 'change']}],
|
||||||
bankOfDeposit: [{required: true, message: '请填写开户行', trigger: ['blur', 'change']}],
|
bankOfDeposit: this.textRules('开户行', 30),
|
||||||
position: [{required: true, message: '请填写职务', trigger: ['blur', 'change']}],
|
position: this.textRules('职务', 20),
|
||||||
officialCapacity: [{required: true, message: '请填写职称', trigger: ['blur', 'change']}],
|
officialCapacity: this.textRules('职称', 20),
|
||||||
subsidyStandards: [{required: true, message: '请选择困难类型', trigger: ['blur', 'change']}],
|
homeIncome: [{validator: this.validateIncome, required: true, trigger: ['blur', 'change']}],
|
||||||
reason: [{required: true, message: '请填写申请原因', trigger: ['blur', 'change']}],
|
homeNumber: [{required: true, type: 'integer', min: 1, message: '家庭人数须为大于零的整数', trigger: ['blur', 'change']}],
|
||||||
|
subsidy: this.textRules('补助类型', 500),
|
||||||
|
subsidyStandards: this.textRules('困难类型', 500),
|
||||||
|
applyMoney: [{validator: this.validateMoney, required: true, trigger: ['blur', 'change']}],
|
||||||
|
reason: this.textRules('生活致困原因', 500),
|
||||||
|
sign: [{required: true, whitespace: true, message: '请完成签字', trigger: ['blur', 'change']}],
|
||||||
},
|
},
|
||||||
|
|
||||||
// 替他人申请相关
|
// 替他人申请相关
|
||||||
@@ -349,8 +367,21 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
textRules(label, max) {
|
||||||
|
return [{required: true, whitespace: true, max, message: '请填写' + label + ',且不超过' + max + '个字符', trigger: ['blur', 'change']}]
|
||||||
|
},
|
||||||
|
validateIncome(rule, value, callback) {
|
||||||
|
const valid = typeof value === 'number' && Number.isFinite(value) && value >= 0 && /^\d+(\.\d{1,2})?$/.test(String(value))
|
||||||
|
callback(valid ? undefined : new Error('收入须为不小于零的数字,最多保留两位小数'))
|
||||||
|
},
|
||||||
|
validateMoney(rule, value, callback) {
|
||||||
|
const valid = typeof value === 'number' && Number.isFinite(value) && value > 0 && /^\d+(\.\d{1,2})?$/.test(String(value))
|
||||||
|
callback(valid ? undefined : new Error('申请金额须大于零,最多保留两位小数'))
|
||||||
|
},
|
||||||
// 保存
|
// 保存
|
||||||
onSave() {
|
async onSave() {
|
||||||
|
const valid = await this.$refs.formRef.validate().catch(() => false)
|
||||||
|
if (!valid) return
|
||||||
this.$confirm("您确定保存吗?", "提示", {
|
this.$confirm("您确定保存吗?", "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
@@ -367,24 +398,13 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
async onSubmit() {
|
async onSubmit() {
|
||||||
this.$refs.formRef.validate().then((valid) => {
|
this.$refs.formRef.validate().catch(() => false).then((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$confirm("您确定要提交吗?", "提示", {
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning"
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
const result = this.isValidIdCard(this.formData.idCard)
|
|
||||||
if (result.status === 0) {
|
|
||||||
this.$message.warning(result.msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const bankRes = this.validateCard(this.formData.bankCardNum)
|
|
||||||
if (bankRes.status === 0) {
|
|
||||||
this.$message.warning(bankRes.msg)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$axios.post('/platform/difficultHelp/apply/submit', {
|
this.$axios.post('/platform/difficultHelp/apply/submit', {
|
||||||
data: JSON.stringify(this.formData)
|
data: JSON.stringify(this.formData)
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
@@ -399,7 +419,7 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
|
|
||||||
async onFinishTask() {
|
async onFinishTask() {
|
||||||
this.$refs.formRef.validate().then((valid) => {
|
this.$refs.formRef.validate().catch(() => false).then((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this.$confirm("您确定要提交吗?", "提示", {
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
@@ -407,17 +427,6 @@ layout("/layouts/platform.html"){
|
|||||||
type: "warning"
|
type: "warning"
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
||||||
const result = this.isValidIdCard(this.formData.idCard)
|
|
||||||
if (result.status === 0) {
|
|
||||||
this.$message.warning(result.msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const bankRes = this.validateCard(this.formData.bankCardNum)
|
|
||||||
if (bankRes.status === 0) {
|
|
||||||
this.$message.warning(bankRes.msg)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$axios.post('/platform/difficultHelp/apply/submitAgain', {
|
this.$axios.post('/platform/difficultHelp/apply/submitAgain', {
|
||||||
data: JSON.stringify(this.formData),
|
data: JSON.stringify(this.formData),
|
||||||
taskId: GetQueryString("taskId")
|
taskId: GetQueryString("taskId")
|
||||||
@@ -446,10 +455,12 @@ layout("/layouts/platform.html"){
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
findOne(id) {
|
findOne(id) {
|
||||||
this.$axios.post('/platform/difficultHelp/mine/findOne', { id }).then(res => {
|
return this.$axios.post('/platform/difficultHelp/mine/findOne', { id }).then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.formData = res.data
|
this.formData = res.data
|
||||||
this.queryRecipients(res.data.loginName)
|
this.queryRecipients(res.data.loginName)
|
||||||
|
} else {
|
||||||
|
throw new Error(res.msg || '申请信息加载失败,请刷新页面重试')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -610,7 +621,7 @@ layout("/layouts/platform.html"){
|
|||||||
return { status: 200, msg: "卡号有效。" };
|
return { status: 200, msg: "卡号有效。" };
|
||||||
},
|
},
|
||||||
async getIsCanPlay() {
|
async getIsCanPlay() {
|
||||||
this.$axios.post('/platform/difficultHelp/apply/getIsCanPlay').then(res => {
|
return this.$axios.post('/platform/difficultHelp/apply/getIsCanPlay').then(res => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
// 新增申请进入页面时,优先校验当前登录人本年度是否已经申请过,已申请则直接拦截新增。
|
// 新增申请进入页面时,优先校验当前登录人本年度是否已经申请过,已申请则直接拦截新增。
|
||||||
if (!this.bizId && res.data.hasCurrentYearApply && !this.$auth.hasRoleOr('BRANCH_UNION_CHAIRMAN')) {
|
if (!this.bizId && res.data.hasCurrentYearApply && !this.$auth.hasRoleOr('BRANCH_UNION_CHAIRMAN')) {
|
||||||
@@ -624,17 +635,26 @@ layout("/layouts/platform.html"){
|
|||||||
if (res.data.applyCount !== null && res.data.applyCount !== undefined && res.data.applyCount !== 0) {
|
if (res.data.applyCount !== null && res.data.applyCount !== undefined && res.data.applyCount !== 0) {
|
||||||
this.$set(this.formData, 'applyCount', res.data.applyCount)
|
this.$set(this.formData, 'applyCount', res.data.applyCount)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(res.msg || '申请资格加载失败,请刷新页面重试')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
try {
|
||||||
await this.getIsCanPlay();
|
await this.getIsCanPlay();
|
||||||
if (this.bizId) {
|
if (this.bizId) {
|
||||||
this.findOne(this.bizId)
|
await this.findOne(this.bizId)
|
||||||
} else {
|
} else {
|
||||||
this.modeChange("1")
|
this.modeChange("1")
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.isShow = false
|
||||||
|
this.blockMessage = error.message || '申请信息加载失败,请刷新页面重试'
|
||||||
|
} finally {
|
||||||
|
this.pageLoading = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
-14
@@ -1,17 +1,5 @@
|
|||||||
<div id="difficult_help_branch_union_approval_form">
|
<div id="difficult_help_branch_union_approval_form">
|
||||||
<el-form :model="formData" ref="formRef" label-width="100px" label-suffix=":">
|
<el-form :model="formData" ref="formRef" label-width="100px" label-suffix=":">
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="formData.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
|
||||||
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -29,8 +17,6 @@
|
|||||||
return {
|
return {
|
||||||
businessId: GetQueryString("businessId"),
|
businessId: GetQueryString("businessId"),
|
||||||
formData: {
|
formData: {
|
||||||
level: "",
|
|
||||||
money: undefined,
|
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-28
@@ -84,18 +84,6 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
<el-dialog title="设置帮扶审批信息" :visible.sync="batchVisible" width="760px">
|
<el-dialog title="设置帮扶审批信息" :visible.sync="batchVisible" width="760px">
|
||||||
<el-form :model="batchForm" ref="batchFormRef" label-width="130px">
|
<el-form :model="batchForm" ref="batchFormRef" label-width="130px">
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="batchForm.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="帮扶金额(元)" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
|
||||||
<el-input-number v-model="batchForm.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,whitespace:true,message:'请填写审批意见',trigger:['change','blur']}]">
|
<el-form-item label="审批意见" prop="tf_opinion" :rules="[{required:true,whitespace:true,message:'请填写审批意见',trigger:['change','blur']}]">
|
||||||
<user-opinion-textarea v-model="batchForm.tf_opinion"></user-opinion-textarea>
|
<user-opinion-textarea v-model="batchForm.tf_opinion"></user-opinion-textarea>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -113,18 +101,6 @@ layout("/layouts/platform.html"){
|
|||||||
{{formData.taskName}}
|
{{formData.taskName}}
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="100px" label-suffix=":">
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="100px" label-suffix=":">
|
||||||
<el-row :gutter="20">
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="formData.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
|
||||||
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-form-item label="审批意见" prop="tf_opinion"
|
<el-form-item label="审批意见" prop="tf_opinion"
|
||||||
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||||
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||||
@@ -178,7 +154,7 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
formData: {},
|
formData: {},
|
||||||
batchVisible: false,
|
batchVisible: false,
|
||||||
batchForm: {level: "", money: undefined, tf_sign: "", tf_opinion: ""},
|
batchForm: {tf_sign: "", tf_opinion: ""},
|
||||||
showApprovalForm: false,
|
showApprovalForm: false,
|
||||||
selectData: []
|
selectData: []
|
||||||
}
|
}
|
||||||
@@ -208,7 +184,7 @@ layout("/layouts/platform.html"){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.batchForm = {level: "", money: undefined, tf_sign: "", tf_opinion: ""}
|
this.batchForm = {tf_sign: "", tf_opinion: ""}
|
||||||
this.batchVisible = true
|
this.batchVisible = true
|
||||||
},
|
},
|
||||||
async submitBatch() {
|
async submitBatch() {
|
||||||
@@ -295,8 +271,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.formData = {
|
this.formData = {
|
||||||
processTaskId: row.taskId,
|
processTaskId: row.taskId,
|
||||||
taskName: row.curTaskName,
|
taskName: row.curTaskName,
|
||||||
level: "",
|
|
||||||
money: undefined,
|
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
}
|
}
|
||||||
this.$refs.infoRef.onOpen(row)
|
this.$refs.infoRef.onOpen(row)
|
||||||
|
|||||||
@@ -72,13 +72,7 @@ layout("/layouts/platform.html"){
|
|||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-if="row.createdBy === $store.state.user.id && row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
|
<el-button v-if="row.createdBy === $store.state.user.id && row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-dropdown v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" trigger="click" @command="format => doExportApply(row, format)">
|
<el-button v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" @click="doExportApply(row)" size="mini" type="primary">导出</el-button>
|
||||||
<el-button size="mini" type="primary">导出</el-button>
|
|
||||||
<el-dropdown-menu slot="dropdown">
|
|
||||||
<el-dropdown-item command="pdf">导出 PDF</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="word">导出 Word</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</el-dropdown>
|
|
||||||
<el-button v-if="row.createdBy === $store.state.user.id && (row.taskKey === 'startTask' || !row.instanceId)" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
|
<el-button v-if="row.createdBy === $store.state.user.id && (row.taskKey === 'startTask' || !row.instanceId)" @click="onDelete(row.id)" size="mini" type="danger">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -187,8 +181,8 @@ layout("/layouts/platform.html"){
|
|||||||
this.units = await this.$businessTool.listUnit((this.$store.state.user.union || {}).id || this.pageForm.unionId)
|
this.units = await this.$businessTool.listUnit((this.$store.state.user.union || {}).id || this.pageForm.unionId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
doExportApply(row, format) {
|
doExportApply(row) {
|
||||||
this.$downLoad('/platform/difficultHelp/reading/doExportApply?id=' + row.id + '&print=' + (format === 'pdf'))
|
this.$downLoad('/platform/difficultHelp/reading/doExportApply?id=' + row.id + '&print=false')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
|||||||
@@ -178,11 +178,7 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
async flushUnits(){
|
async flushUnits(){
|
||||||
this.$set(this.pageForm, "unitId", null)
|
this.$set(this.pageForm, "unitId", null)
|
||||||
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
|
|
||||||
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
|
this.units = await this.$businessTool.listUnit(this.pageForm.unionId)
|
||||||
} else {
|
|
||||||
this.units = await this.$businessTool.listUnit((this.$store.state.user.union || {}).id || this.pageForm.unionId)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
exportYearPayRecord(){
|
exportYearPayRecord(){
|
||||||
this.$downLoad('/platform/difficultHelp/reading/exportYearPayRecord', this.pageForm)
|
this.$downLoad('/platform/difficultHelp/reading/exportYearPayRecord', this.pageForm)
|
||||||
@@ -204,11 +200,7 @@ layout("/layouts/platform.html"){
|
|||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
this.pageData()
|
this.pageData()
|
||||||
if (this.$auth.hasRoleOr('SYSADMIN, SCHOOL_UNION_ADMIN')) {
|
|
||||||
this.unions = await this.$businessTool.listUnion()
|
this.unions = await this.$businessTool.listUnion()
|
||||||
} else {
|
|
||||||
this.unions = await this.$businessTool.listUnion((this.$store.state.user.union || {}).id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
-6
@@ -1,11 +1,6 @@
|
|||||||
<div id="difficult_help_branch_union_approval_form">
|
<div id="difficult_help_branch_union_approval_form">
|
||||||
<el-form :model="formData" ref="formRef" label-width="100px" label-suffix=":">
|
<el-form :model="formData" ref="formRef" label-width="100px" label-suffix=":">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="formData.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
||||||
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
||||||
@@ -29,7 +24,6 @@
|
|||||||
return {
|
return {
|
||||||
businessId: GetQueryString("businessId"),
|
businessId: GetQueryString("businessId"),
|
||||||
formData: {
|
formData: {
|
||||||
level: "",
|
|
||||||
money: undefined,
|
money: undefined,
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-13
@@ -84,11 +84,6 @@ layout("/layouts/platform.html"){
|
|||||||
<el-dialog title="设置帮扶审批信息" :visible.sync="batchVisible" width="760px">
|
<el-dialog title="设置帮扶审批信息" :visible.sync="batchVisible" width="760px">
|
||||||
<el-form :model="batchForm" ref="batchFormRef" label-width="130px">
|
<el-form :model="batchForm" ref="batchFormRef" label-width="130px">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="batchForm.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="帮扶金额(元)" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
<el-form-item label="帮扶金额(元)" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
||||||
<el-input-number v-model="batchForm.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
<el-input-number v-model="batchForm.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
||||||
@@ -113,11 +108,6 @@ layout("/layouts/platform.html"){
|
|||||||
</div>
|
</div>
|
||||||
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="100px" label-suffix=":">
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="100px" label-suffix=":">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="级别" prop="level" :rules="[{required:true,message:'请选择级别',trigger:['change','blur']}]">
|
|
||||||
<dict-select v-model="formData.level" code="DIFFICULT_LEVEL" style="width: 100%" placeholder="请选择级别"></dict-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
<el-form-item label="帮扶金额" prop="money" :rules="[{required:true,message:'请填写帮扶金额',trigger:['change','blur']}]">
|
||||||
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
<el-input-number v-model="formData.money" style="width: 100%" :precision="2" :min="0" placeholder="请输入帮扶金额"></el-input-number>
|
||||||
@@ -177,7 +167,7 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
formData: {},
|
formData: {},
|
||||||
batchVisible: false,
|
batchVisible: false,
|
||||||
batchForm: {level: "", money: undefined, tf_sign: "", tf_opinion: ""},
|
batchForm: {money: undefined, tf_sign: "", tf_opinion: ""},
|
||||||
showApprovalForm: false,
|
showApprovalForm: false,
|
||||||
selectData: [],
|
selectData: [],
|
||||||
}
|
}
|
||||||
@@ -201,7 +191,7 @@ layout("/layouts/platform.html"){
|
|||||||
this.$message.warning('请勾选待审核数据!');
|
this.$message.warning('请勾选待审核数据!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.batchForm = {level: "", money: undefined, tf_sign: "", tf_opinion: ""}
|
this.batchForm = {money: undefined, tf_sign: "", tf_opinion: ""}
|
||||||
this.batchVisible = true
|
this.batchVisible = true
|
||||||
},
|
},
|
||||||
async submitBatch() {
|
async submitBatch() {
|
||||||
@@ -288,7 +278,6 @@ layout("/layouts/platform.html"){
|
|||||||
this.formData = {
|
this.formData = {
|
||||||
processTaskId: row.taskId,
|
processTaskId: row.taskId,
|
||||||
taskName: row.curTaskName,
|
taskName: row.curTaskName,
|
||||||
level: "",
|
|
||||||
money: undefined,
|
money: undefined,
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<el-descriptions-item label="慰问类型" :span="2">
|
||||||
|
<el-form-item label="慰问类型" prop="type">
|
||||||
|
<el-select v-model="formData.type" filterable @change="typeChange" style="width:100%" placeholder="请选择慰问类型">
|
||||||
|
<el-option v-for="t in typeOptions" :key="t.id" :value="t.id" :label="t.name"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="慰问金额" :span="2">
|
||||||
|
<el-form-item label="慰问金额" prop="perMoney" :rules="recipientRules.money">
|
||||||
|
<el-input v-model="formData.perMoney" readonly style="width:100%" placeholder="根据慰问类型自动带出"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="慰问时间" :span="2">
|
||||||
|
<el-form-item label="慰问时间" prop="occurTime" :rules="recipientRules.occurTime">
|
||||||
|
<el-date-picker v-model="formData.occurTime" type="date" value-format="yyyy-MM-dd" style="width:100%" placeholder="请选择慰问时间"></el-date-picker>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
+322
@@ -0,0 +1,322 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style nonce="${cspNonce!}">
|
||||||
|
<!--#include('recipients.css'){}#-->
|
||||||
|
</style>
|
||||||
|
<div id="app" class="special-condolence-apply" v-cloak>
|
||||||
|
<el-card shadow="never">
|
||||||
|
<snaker-start slot="header" label="特殊慰问" define_key="TSWW"></snaker-start>
|
||||||
|
<el-form size="small" :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||||
|
class="flow-task-form">
|
||||||
|
<el-tabs v-model="activeApplicationTab">
|
||||||
|
<el-tab-pane label="基础信息" name="form">
|
||||||
|
<el-descriptions :column="6" border size="small">
|
||||||
|
<el-descriptions-item label="事项" :span="2"><el-form-item prop="subject" label="事项"><el-input v-model="formData.subject" maxlength="200" show-word-limit placeholder="请输入特殊慰问事项"></el-input></el-form-item></el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="申请人姓名" :span="2">{{formData.applyUserName}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请人工号" :span="2">{{formData.applyLoginName}}</el-descriptions-item>
|
||||||
|
|
||||||
|
|
||||||
|
<!--#include('config.html'){}#-->
|
||||||
|
<el-descriptions-item label="申请人单位" :span="2">{{formData.applyUnitName}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请人工会" :span="2">{{formData.applyUnionName}}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="" :span="2"><span></span></el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请事由" :span="6">
|
||||||
|
<el-form-item prop="remark" label="申请事由">
|
||||||
|
<el-input maxlength="500" v-model="formData.remark" placeholder="请填写申请事由"
|
||||||
|
type="textarea" :rows="3" resize="none"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item :span="6" 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-form-item prop="files" label="附件">
|
||||||
|
<file-upload
|
||||||
|
:value.sync="formData.files"
|
||||||
|
:upload_number="5"
|
||||||
|
upload_result_category="array"
|
||||||
|
complete_result
|
||||||
|
upload_mode="drag"
|
||||||
|
></file-upload>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
|
||||||
|
<el-descriptions-item label="签字" :span="6">
|
||||||
|
<el-form-item prop="signature" label="签字" class="special-condolence-signature-item">
|
||||||
|
<pc-signature v-model="formData.signature"></pc-signature>
|
||||||
|
</el-form-item>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="慰问对象" name="recipients" :lazy="false">
|
||||||
|
<!--#include('recipients.html'){}#-->
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-form>
|
||||||
|
<el-row type="flex" justify="end" class="special-condolence-actions">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('recipients.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [specialCondolenceRecipients],
|
||||||
|
components: {
|
||||||
|
ElDatePicker: {
|
||||||
|
extends: ELEMENT.DatePicker,
|
||||||
|
mounted() {
|
||||||
|
// 手动输入触发 change 前初始化日期面板,避免 picker 尚未创建。
|
||||||
|
if (!this.picker) this.mountPicker()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bizId: GetQueryString("bizId"),
|
||||||
|
taskId: GetQueryString("taskId"),
|
||||||
|
formData: { recipients: [] },
|
||||||
|
formRules: {
|
||||||
|
subject: [{ required: true, whitespace: true, message: "请填写事项", trigger: ["blur", "change"] }, { max: 200, message: "事项最多200字", trigger: "blur" }],
|
||||||
|
recipients: [{ validator: (rule, value, callback) => callback(Array.isArray(value) && value.length > 0 ? undefined : new Error("请至少添加一位慰问对象")), trigger: "change" }],
|
||||||
|
helpUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
payUserId: [{ 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"] },
|
||||||
|
{ validator: (rule, value, callback) => callback(this.validateMoney(value) ? undefined : new Error("慰问金额须大于0且不超过10000元,最多两位小数")), 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, type: "array", min: 1, max: 5, message: "请上传1至5个附件", trigger: ["change", "blur"] }],
|
||||||
|
signature: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
handlerUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
// certifierUserId: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
bankCardNumber: [
|
||||||
|
{ required: true, message: "请填写银行卡号或对公账户号", trigger: ["change", "blur"] },
|
||||||
|
{ pattern: /^[0-9]{6,30}$/, message: "收款账户须为6至30位数字(银行卡号或对公账户号)", trigger: ["change", "blur"] }
|
||||||
|
],
|
||||||
|
bankUserName: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
bankOfDeposit: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
thisYearHospitalizationNum: [
|
||||||
|
{ required: true, message: "必填", trigger: ["change", "blur"] },
|
||||||
|
{ type: "integer", min: 0, max: 10000, message: "住院次数须为0至10000的整数", trigger: ["change", "blur"] }
|
||||||
|
],
|
||||||
|
leaveHospitalTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
hospitalizationTime: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
|
||||||
|
},
|
||||||
|
chooseType: {},
|
||||||
|
payUserOptions: [],
|
||||||
|
helpUserOptions: [],
|
||||||
|
typeOptions: [],
|
||||||
|
|
||||||
|
handlerUserOptions: [],
|
||||||
|
certifierUserOptions: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
validateMoney(value) {
|
||||||
|
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||||
|
},
|
||||||
|
createRemoteMethod(options) {
|
||||||
|
return (keyword) => {
|
||||||
|
this.selectQueryUser(keyword, options)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectQueryUser(keyword, options) {
|
||||||
|
options.length = 0
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/listUser", { keyword: keyword }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
options.push(...res.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
helpUserChange(val) {
|
||||||
|
const user = this.helpUserOptions.find(o => o.id === val)
|
||||||
|
if (user) {
|
||||||
|
const { userName, loginName, unitId, unitName, unionId, unionName } = 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)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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) {
|
||||||
|
const { userName, loginName } = user
|
||||||
|
this.$set(this.formData, "payUserName", userName)
|
||||||
|
this.$set(this.formData, "payLoginName", loginName)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
typeChange(id) {
|
||||||
|
this.chooseType = this.typeOptions.find(o => o.id === id)
|
||||||
|
if (this.chooseType) {
|
||||||
|
this.$set(this.formData, "perMoney", this.chooseType.money)
|
||||||
|
this.$set(this.formData, "way", this.chooseType.way)
|
||||||
|
this.$set(this.formData, "typeCode", this.chooseType.code)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSave() {
|
||||||
|
this.$confirm("您确定保存吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/save", { data: JSON.stringify(this.formData) }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async validateApplication(callback) {
|
||||||
|
const form = this.$refs.formRef
|
||||||
|
const fields = form.fields.filter(field => field.prop && !field.prop.startsWith('recipients'))
|
||||||
|
const results = await Promise.all(fields.map(field => new Promise(resolve => {
|
||||||
|
field.validate('', message => resolve(!message))
|
||||||
|
})))
|
||||||
|
if (results.some(valid => !valid)) {
|
||||||
|
this.activeApplicationTab = 'form'
|
||||||
|
this.$message.error('请完善基础信息的必填信息')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.ensureApplicationRecipients()) return
|
||||||
|
form.validate(callback)
|
||||||
|
},
|
||||||
|
onSubmit() {
|
||||||
|
this.validateApplication((valid, invalidFields) => {
|
||||||
|
if (!valid) { this.showInvalidApplicationTab(invalidFields); return }
|
||||||
|
if (valid) {
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/submit", {
|
||||||
|
data: JSON.stringify(this.formData)
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onFinishTask() {
|
||||||
|
this.validateApplication((valid, invalidFields) => {
|
||||||
|
if (!valid) { this.showInvalidApplicationTab(invalidFields); return }
|
||||||
|
if (valid) {
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/submitAgain", {
|
||||||
|
data: JSON.stringify(this.formData),
|
||||||
|
taskId: GetQueryString("taskId")
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
if (this.bizId) {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/info", { id: this.bizId }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.formData = res.data
|
||||||
|
this.initRecipients()
|
||||||
|
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) || {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const { username, loginname, id, unit, union, mobile } = this.$store.state.user
|
||||||
|
this.formData = {
|
||||||
|
recipients: [this.newRecipient()],
|
||||||
|
perMoney: undefined,
|
||||||
|
occurTime: this.$moment().format('YYYY-MM-DD'),
|
||||||
|
applyUserName: username,
|
||||||
|
applyLoginName: loginname,
|
||||||
|
applyUserId: id,
|
||||||
|
applyUnitId: unit?.id,
|
||||||
|
applyUnitName: unit?.name,
|
||||||
|
applyUnionId: union?.id,
|
||||||
|
applyUnionName: union?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post("/platform/special_condolence/type/querySpecialCondolenceType")
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
.special-condolence-apply .el-card__body { padding: 24px; }
|
||||||
|
.special-condolence-apply .special-condolence-section-title { display: flex; align-items: center; gap: 10px; margin: 24px 0 14px; color: #303133; font-size: 15px; font-weight: 600; line-height: 24px; }
|
||||||
|
.special-condolence-apply .el-descriptions__table { table-layout: fixed; }
|
||||||
|
.special-condolence-apply .flow-task-form > .special-condolence-section-title:first-child { margin-top: 0; }
|
||||||
|
.special-condolence-apply .el-descriptions { font-size: 14px; }
|
||||||
|
.special-condolence-apply .el-descriptions .el-descriptions-item__cell { height: 50px; padding: 8px 12px; box-sizing: border-box; font-size: 14px; line-height: 32px; vertical-align: middle; }
|
||||||
|
.special-condolence-apply .el-descriptions-item__label.is-bordered-label { width: 130px; min-width: 130px; max-width: 130px; font-weight: 400; }
|
||||||
|
.special-condolence-apply .el-descriptions-item__content { font-weight: 400; }
|
||||||
|
.special-condolence-apply .el-descriptions .el-form-item__content { line-height: 32px; }
|
||||||
|
.special-condolence-apply .el-descriptions .el-input__inner { height: 32px; line-height: 32px; font-size: 14px; }
|
||||||
|
.special-condolence-apply .el-descriptions .el-input__icon { line-height: 32px; }
|
||||||
|
.special-condolence-apply .el-descriptions .el-textarea__inner { font-size: 14px; line-height: 22px; }
|
||||||
|
|
||||||
|
.special-condolence-apply .el-descriptions-item__label { width: 130px; color: #606266; background: #f7f9fc; }
|
||||||
|
.special-condolence-apply .special-condolence-recipients { margin: 0; }
|
||||||
|
.special-condolence-apply .special-condolence-toolbar { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: 14px; padding: 0 0 12px; }
|
||||||
|
.special-condolence-apply .special-condolence-toolbar .special-condolence-section-title { margin: 0 0 4px; }
|
||||||
|
.special-condolence-hint { color: #606266; font-size: 12px; line-height: 20px; }
|
||||||
|
.special-condolence-apply .special-condolence-toolbar-buttons { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||||
|
.special-condolence-apply .special-condolence-toolbar-buttons .el-button { margin: 0; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item { margin: 0; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item > .el-form-item__content { line-height: normal; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-form-item__error { position: static; padding: 8px 20px; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-table th { background: #f5f7fa; color: #606266; font-weight: 600; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-table .cell { padding: 0 8px; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-select,
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-input-number,
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-date-editor { width: 100%; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-input-number .el-input__inner { text-align: right; }
|
||||||
|
.special-condolence-apply .special-condolence-delete { color: #d64040; }
|
||||||
|
.special-condolence-apply .special-condolence-table-footer { display: flex; justify-content: flex-end; align-items: center; flex-wrap: wrap; gap: 10px; padding: 10px 20px; background: #fafbfd; }
|
||||||
|
.special-condolence-apply .special-condolence-total { display: flex; align-items: baseline; gap: 6px; color: #606266; font-size: 13px; font-variant-numeric: tabular-nums; }
|
||||||
|
.special-condolence-apply .special-condolence-total > span { margin-left: 18px; }
|
||||||
|
.special-condolence-apply .special-condolence-total-amount { color: #303133; font-size: 20px; }
|
||||||
|
.special-condolence-apply .special-condolence-actions { gap: 12px; margin-top: 24px; padding-top: 20px; border-top: 1px solid #ebeef5; }
|
||||||
|
.special-condolence-apply .special-condolence-actions .el-button { margin: 0; min-width: 108px; }
|
||||||
|
.special-condolence-dialog { max-width: calc(100vw - 32px); border-radius: 8px; }
|
||||||
|
.special-condolence-dialog .el-dialog__header { padding: 22px 24px 16px; border-bottom: 1px solid #ebeef5; }
|
||||||
|
.special-condolence-dialog .el-dialog__body { padding: 24px; }
|
||||||
|
.special-condolence-dialog .el-dialog__footer { padding: 16px 24px; border-top: 1px solid #ebeef5; }
|
||||||
|
.special-condolence-dialog .special-condolence-template { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 16px; border: 1px solid #dce6f3; border-radius: 6px; background: #f6f9fe; }
|
||||||
|
.special-condolence-dialog .special-condolence-template > i { color: #409eff; font-size: 28px; }
|
||||||
|
.special-condolence-dialog .special-condolence-template > div { flex: 1; min-width: 180px; }
|
||||||
|
.special-condolence-dialog .special-condolence-template p { margin: 5px 0 0; color: #606266; font-size: 12px; line-height: 18px; }
|
||||||
|
.special-condolence-dialog .special-condolence-upload-title { margin: 22px 0 12px; font-weight: 600; }
|
||||||
|
.special-condolence-dialog .special-condolence-upload .el-upload,
|
||||||
|
.special-condolence-dialog .special-condolence-upload .el-upload-dragger { width: 100%; }
|
||||||
|
.special-condolence-dialog .special-condolence-upload .el-upload-dragger { height: auto; min-height: 150px; padding: 22px 12px; }
|
||||||
|
.special-condolence-dialog .special-condolence-upload .el-icon-upload,
|
||||||
|
.special-condolence-dialog .special-condolence-upload .el-icon-loading { display: block; margin: 0 0 16px; color: #909399; font-size: 44px; line-height: 48px; }
|
||||||
|
.special-condolence-dialog .el-upload__tip { margin-bottom: 16px; line-height: 20px; }
|
||||||
|
.special-condolence-dialog .special-condolence-batch-note { margin-bottom: 24px; padding: 12px 16px; background: #f5f7fa; border-radius: 4px; line-height: 22px; }
|
||||||
|
.special-condolence-dialog .special-condolence-batch-form .el-select,
|
||||||
|
.special-condolence-dialog .special-condolence-batch-form .el-input-number,
|
||||||
|
.special-condolence-dialog .special-condolence-batch-form .el-date-editor { width: 100%; }
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.special-condolence-apply .el-card__body { padding: 16px; }
|
||||||
|
.special-condolence-apply .special-condolence-toolbar { padding: 14px; }
|
||||||
|
.special-condolence-apply .special-condolence-total > span { margin-left: 8px; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-table .el-form-item { margin: 8px 0 20px; }
|
||||||
|
.special-condolence-apply .special-condolence-table-item .el-table .el-form-item__error { position: absolute; padding: 4px 0 0; font-size: 11px; line-height: 14px; white-space: normal; }
|
||||||
|
|
||||||
|
.special-condolence-apply .flow-task-form .el-form-item__error { color: #f56c6c !important; }
|
||||||
|
.special-condolence-apply .el-form-item.is-error .el-input__inner,
|
||||||
|
.special-condolence-apply .el-form-item.is-error .el-textarea__inner { border-color: #f56c6c; }
|
||||||
|
|
||||||
|
.special-condolence-apply .flow-task-form .special-condolence-signature-item .el-form-item__error { position: static; padding-top: 6px; line-height: 20px; white-space: normal; }
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
<section class="special-condolence-recipients">
|
||||||
|
<div class="special-condolence-toolbar">
|
||||||
|
<div class="special-condolence-toolbar-buttons">
|
||||||
|
<el-button size="small" icon="el-icon-upload2" @click="importVisible = true">Excel 导入</el-button>
|
||||||
|
<el-button size="small" type="primary" icon="el-icon-plus" @click="formData.recipients.push(newRecipient())">新增慰问对象</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-form-item prop="recipients" label-width="0" class="special-condolence-table-item">
|
||||||
|
<el-table ref="recipientTableRef" :data="formData.recipients" border stripe size="small" max-height="520" empty-text="暂无慰问对象,点击新增或从 Excel 导入">
|
||||||
|
<el-table-column type="index" label="序号" width="55" align="center" fixed="left"></el-table-column>
|
||||||
|
<el-table-column label="慰问对象" width="200" fixed="left"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + (s.row.helpUserId ? '.helpUserId' : '.helpUserName')" :rules="recipientRules.helpUserId"><el-input v-if="!s.row.helpUserId && s.row.helpUserName" size="small" :value="s.row.helpUserName" readonly></el-input><user-select v-else size="small" v-model="s.row.helpUserId" api="/platform/special_condolence/apply/listUser" api_input_key_name="keyword" :option_list="recipientOptions(s.row)" :option_label_func="item => item.userName + '(' + (item.loginName || '') + ')'" @selected="(user, id) => recipientUserChange(s.row, s.$index, id, user)"></user-select></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="工号" min-width="150"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + '.helpLoginName'" :rules="[{ validator: (rule, value, cb) => cb(!s.row.helpUserId || s.row.personType === '劳务派遣人员' || value ? undefined : new Error('普通人员工号不能为空')), trigger: 'change' }]"><el-input size="small" v-model="s.row.helpLoginName" readonly placeholder="选人后带出,劳务派遣可空"></el-input></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="身份证号码" min-width="205"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + '.idCard'" :rules="recipientRules.idCard"><el-input size="small" v-model="s.row.idCard" maxlength="18" placeholder="请输入18位身份证号"></el-input></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="开户行" min-width="190"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + '.bankOfDeposit'" :rules="recipientRules.bankOfDeposit"><el-input size="small" v-model="s.row.bankOfDeposit" maxlength="100" placeholder="请输入开户银行及支行"></el-input></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="户名" min-width="140"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + '.bankUserName'" :rules="recipientRules.bankUserName"><el-input size="small" v-model="s.row.bankUserName" maxlength="100" placeholder="请输入账户户名"></el-input></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="收款账户" min-width="215"><template slot-scope="s"><el-form-item :prop="'recipients.' + s.$index + '.bankCardNumber'" :rules="recipientRules.bankCardNumber"><el-input size="small" v-model="s.row.bankCardNumber" maxlength="30" placeholder="银行卡号或对公账户号"></el-input></el-form-item></template></el-table-column>
|
||||||
|
<el-table-column label="操作" fixed="right" width="75" align="center"><template slot-scope="s"><el-button size="small" type="text" class="special-condolence-delete" @click="formData.recipients.splice(s.$index, 1)">删除</el-button></template></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="special-condolence-table-footer">
|
||||||
|
<div class="special-condolence-total">共 <strong>{{ recipientCount }}</strong> 人<span>慰问金额合计</span><strong class="special-condolence-total-amount">¥ {{ recipientTotal }}</strong></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<el-dialog title="Excel 导入慰问对象" :visible.sync="importVisible" width="560px" custom-class="special-condolence-dialog" :close-on-click-modal="!importLoading" :close-on-press-escape="!importLoading" :show-close="!importLoading" append-to-body>
|
||||||
|
<div class="special-condolence-template">
|
||||||
|
<i class="el-icon-document"></i>
|
||||||
|
<div><strong>第一步:下载并填写模板</strong><p>按模板表头填写,一行对应一位慰问对象。</p></div>
|
||||||
|
<el-button size="small" type="primary" plain icon="el-icon-download" @click="$downLoad('/platform/special_condolence/apply/importTemplate')">下载模板</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="special-condolence-upload-title">第二步:上传填写好的文件</div>
|
||||||
|
<el-upload class="special-condolence-upload" drag action="" accept=".xlsx,.xls" :http-request="importRecipients" :show-file-list="false" :disabled="importLoading">
|
||||||
|
<i :class="importLoading ? 'el-icon-loading' : 'el-icon-upload'"></i>
|
||||||
|
<div class="el-upload__text">{{ importLoading ? '正在导入,请稍候…' : '将 Excel 文件拖到此处,或点击选择文件' }}</div>
|
||||||
|
<div slot="tip" class="el-upload__tip">支持 .xlsx、.xls 格式,单次最多 1000 行。导入的数据将追加到当前表格。</div>
|
||||||
|
</el-upload>
|
||||||
|
<el-alert title="工号、身份证号码和收款账户请保持文本格式。普通人员须填写正确工号;劳务派遣人员免校验工号,均须属于申请人本工会。" type="info" :closable="false" show-icon></el-alert>
|
||||||
|
<span slot="footer"><el-button :disabled="importLoading" @click="importVisible = false">关闭</el-button></span>
|
||||||
|
</el-dialog>
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
const specialCondolenceRecipients = {
|
||||||
|
data() {
|
||||||
|
return { activeApplicationTab: 'form', recipientRules: this.createRecipientRules(), importVisible: false, importLoading: false }
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
recipientCount() {
|
||||||
|
return (this.formData.recipients || []).length
|
||||||
|
},
|
||||||
|
recipientTotal() {
|
||||||
|
const money = Number(this.formData.perMoney)
|
||||||
|
const cents = (Number.isFinite(money) && money > 0 ? Math.round(money * 100) : 0) * this.recipientCount
|
||||||
|
return (cents / 100).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activeApplicationTab() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.recipientTableRef) this.$refs.recipientTableRef.doLayout()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
typeOptions() { this.chooseType = this.typeOptions.find(t => t.id === this.formData.type) || {} },
|
||||||
|
'formData.type'(value) { this.chooseType = this.typeOptions.find(t => t.id === value) || {} }
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showInvalidApplicationTab(errors) {
|
||||||
|
const fields = Array.isArray(errors) ? errors.map(error => error.name || '') : Object.keys(errors || {})
|
||||||
|
if (!fields.length) return
|
||||||
|
this.activeApplicationTab = fields.some(field => !field.startsWith('recipients')) ? 'form' : 'recipients'
|
||||||
|
if (this.activeApplicationTab === 'recipients') this.notifyRecipientError('请完善慰问对象的必填信息')
|
||||||
|
},
|
||||||
|
notifyRecipientError(message) {
|
||||||
|
if (this.$toast && this.$toast.fail) this.$toast.fail(message)
|
||||||
|
else this.$message.error(message)
|
||||||
|
},
|
||||||
|
ensureApplicationRecipients() {
|
||||||
|
const rows = this.formData.recipients
|
||||||
|
if (!Array.isArray(rows) || rows.length === 0 || rows.some(row => !row || !String(row.helpUserId || row.helpUserName || '').trim())) {
|
||||||
|
this.activeApplicationTab = 'recipients'
|
||||||
|
this.notifyRecipientError('请先选择慰问对象,并填写完整信息')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
createRecipientRules() {
|
||||||
|
const required = label => ({ required: true, whitespace: true, message: '请填写' + label, trigger: ['blur', 'change'] })
|
||||||
|
return {
|
||||||
|
helpUserId: [{ required: true, message: '请选择慰问对象', trigger: 'change' }],
|
||||||
|
type: [{ required: true, message: '请选择慰问类型', trigger: 'change' }],
|
||||||
|
idCard: [required('身份证号码'), { validator: (rule, value, cb) => cb(this.validRecipientIdCard(value) ? undefined : new Error('身份证号码不正确')), trigger: ['blur', 'change'] }],
|
||||||
|
bankOfDeposit: [required('开户行'), { max: 100, message: '开户行最多100字', trigger: 'blur' }],
|
||||||
|
bankUserName: [required('户名'), { max: 100, message: '户名最多100字', trigger: 'blur' }],
|
||||||
|
bankCardNumber: [required('收款账户'), { pattern: /^[0-9]{6,30}$/, message: '请输入6至30位数字账户', trigger: ['blur', 'change'] }],
|
||||||
|
money: [{ validator: (rule, value, cb) => cb(/^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000 ? undefined : new Error('金额须大于0且不超过10000元,最多两位小数')), trigger: ['blur', 'change'] }],
|
||||||
|
occurTime: [{ validator: (rule, value, cb) => cb(this.$moment(value, 'YYYY-MM-DD', true).isValid() ? undefined : new Error('请选择有效慰问时间')), trigger: ['blur', 'change'] }]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validRecipientIdCard(value) {
|
||||||
|
const card = String(value || '').toUpperCase()
|
||||||
|
if (!/^[1-9][0-9]{16}[0-9X]$/.test(card) || !this.$moment(card.substring(6, 14), 'YYYYMMDD', true).isValid()) return false
|
||||||
|
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
|
||||||
|
return '10X98765432'[weights.reduce((sum, weight, index) => sum + weight * Number(card[index]), 0) % 11] === card[17]
|
||||||
|
},
|
||||||
|
recipientOptions(row) {
|
||||||
|
return row.helpUserId ? [{ id: row.helpUserId, userName: row.helpUserName, loginName: row.helpLoginName, personType: row.personType, idCard: row.idCard, bankOfDeposit: row.bankOfDeposit, bankUserName: row.bankUserName, bankCardNumber: row.bankCardNumber }] : []
|
||||||
|
},
|
||||||
|
recipientUserChange(row, index, id, user) {
|
||||||
|
this.$set(row, 'helpUserId', user ? user.id : '')
|
||||||
|
this.$set(row, 'helpUserName', user ? user.userName : '')
|
||||||
|
this.$set(row, 'helpLoginName', user ? user.loginName : '')
|
||||||
|
this.$set(row, 'personType', user ? user.personType : '')
|
||||||
|
this.$set(row, 'idCard', user ? user.idCard || '' : '')
|
||||||
|
this.$set(row, 'bankOfDeposit', user ? user.bankOfDeposit || '' : '')
|
||||||
|
this.$set(row, 'bankUserName', user ? user.bankUserName || user.userName : '')
|
||||||
|
this.$set(row, 'bankCardNumber', user ? user.bankCardNumber || '' : '')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const fields = ['helpUserId', 'helpLoginName', 'idCard', 'bankOfDeposit', 'bankUserName', 'bankCardNumber']
|
||||||
|
const names = fields.map(field => 'recipients.' + index + '.' + field)
|
||||||
|
const form = this.$refs.formRef
|
||||||
|
if (typeof form.validateField === 'function') form.validateField(names)
|
||||||
|
else if (typeof form.validate === 'function') form.validate(names).catch(() => {})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
newRecipient() {
|
||||||
|
return { helpUserId: '', helpLoginName: '', personType: '', helpUserName: '', idCard: '', bankOfDeposit: '', bankUserName: '', bankCardNumber: '' }
|
||||||
|
},
|
||||||
|
initRecipients() {
|
||||||
|
if (this.formData.perMoney == null && this.formData.recipients && this.formData.recipients.length) this.$set(this.formData, 'perMoney', Number(this.formData.recipients[0].money))
|
||||||
|
if (!this.formData.recipients || !this.formData.recipients.length) {
|
||||||
|
this.$set(this.formData, 'recipients', this.formData.helpUserName ? [Object.assign(this.newRecipient(), this.formData, { recipients: undefined })] : [this.newRecipient()])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async importRecipients(request) {
|
||||||
|
this.importLoading = true
|
||||||
|
try {
|
||||||
|
const data = new FormData()
|
||||||
|
data.append('file', request.file)
|
||||||
|
const response = await axios.post('/platform/special_condolence/apply/importRecipients', data, {
|
||||||
|
headers: { 'x-requested-with': 'XMLHttpRequest' }
|
||||||
|
})
|
||||||
|
const result = response.data
|
||||||
|
if (result.code === 0) {
|
||||||
|
const rows = this.formData.recipients.filter(r => r.helpUserName || r.type || r.idCard || r.bankCardNumber || r.bankUserName || r.bankOfDeposit || r.money)
|
||||||
|
this.$set(this.formData, 'recipients', rows.concat(result.data))
|
||||||
|
this.importVisible = false
|
||||||
|
this.$message.success('导入成功,共' + result.data.length + '人')
|
||||||
|
} else this.$message.error('导入失败:' + (result.msg || '请检查文件内容后重试'))
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error('导入失败:' + (error.response?.data?.msg || error.msg || '请检查文件内容后重试'))
|
||||||
|
} finally {
|
||||||
|
this.importLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
const specialcondolenceInfo = {
|
||||||
|
template: /*language=HTML*/ `
|
||||||
|
<div>
|
||||||
|
<el-tabs v-model="activeInfoTab">
|
||||||
|
<el-tab-pane label="基础信息" name="form">
|
||||||
|
<div class="process-title">
|
||||||
|
申请信息
|
||||||
|
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
|
||||||
|
</div>
|
||||||
|
<el-descriptions :column="6" border size="small" :label-style="{ width: '130px', minWidth: '130px', maxWidth: '130px', fontSize: '14px', fontWeight: 400, lineHeight: '32px', padding: '8px 12px' }" :content-style="{ fontSize: '14px', fontWeight: 400, lineHeight: '32px', padding: '8px 12px' }">
|
||||||
|
<el-descriptions-item label="事项" :span="2">{{ viewData.subject || '--' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请人姓名" :span="2">{{ viewData.applyUserName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请人工号" :span="2">{{ viewData.applyLoginName }}</el-descriptions-item>
|
||||||
|
<template v-if="viewData.recipients && viewData.recipients.length">
|
||||||
|
<el-descriptions-item label="慰问类型" :span="2">{{ viewData.typeName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="每人慰问金额" :span="2">{{ viewData.perMoney }} 元</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="慰问时间" :span="2">{{ viewData.occurTime }}</el-descriptions-item>
|
||||||
|
</template>
|
||||||
|
<el-descriptions-item label="申请人单位" :span="2">{{ viewData.applyUnitName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请人工会" :span="2">{{ viewData.applyUnionName }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="" :span="2"><span></span></el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请事由" :span="6">
|
||||||
|
<div style="white-space: pre-line">{{ viewData.remark }}</div>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="附件" :span="6">
|
||||||
|
<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="6">
|
||||||
|
<el-image :src="viewData.signature"
|
||||||
|
v-if="viewData.signature"
|
||||||
|
class="signature-image"></el-image>
|
||||||
|
<span v-else>暂无签字</span>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="慰问对象" name="recipients">
|
||||||
|
<el-descriptions v-if="!viewData.recipients || !viewData.recipients.length" :column="3" border>
|
||||||
|
<template v-if="!viewData.recipients || !viewData.recipients.length">
|
||||||
|
<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>
|
||||||
|
</template>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<div v-if="viewData.recipients && viewData.recipients.length" class="process-title" style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-top:20px">
|
||||||
|
<span>慰问对象明细</span>
|
||||||
|
<span style="font-size:14px;font-weight:normal">慰问金额合计:<strong>¥ {{ detailTotal }}</strong></span>
|
||||||
|
</div>
|
||||||
|
<el-table ref="recipientInfoTableRef" v-if="viewData.recipients && viewData.recipients.length" :data="viewData.recipients" border stripe size="small" max-height="480" class="mt10" :header-cell-style="{ background: '#f5f7fa', color: '#606266' }">
|
||||||
|
<el-table-column type="index" label="序号" width="55" align="center" fixed="left"></el-table-column>
|
||||||
|
<el-table-column prop="helpUserName" label="慰问对象" width="130" fixed="left"></el-table-column>
|
||||||
|
<el-table-column prop="helpLoginName" label="工号" min-width="130"></el-table-column>
|
||||||
|
<el-table-column prop="idCard" label="身份证号码" min-width="190"></el-table-column>
|
||||||
|
<el-table-column prop="bankOfDeposit" label="开户行" min-width="180" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column prop="bankUserName" label="户名" min-width="150"></el-table-column>
|
||||||
|
<el-table-column prop="bankCardNumber" label="收款账户" min-width="210"></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="审核记录" name="records">
|
||||||
|
<div v-if="!doneTasks.length" style="padding:32px;text-align:center;color:#909399">暂无审核记录</div>
|
||||||
|
<template v-for="task in doneTasks">
|
||||||
|
<div class="mt10">
|
||||||
|
<div class="process-title">{{ task.displayName }}</div>
|
||||||
|
<el-descriptions border class="flow-task-form" :column="3" :key="task.id"
|
||||||
|
v-if="task.ext.isFirstTaskNode">
|
||||||
|
<el-descriptions-item label="申请用户">{{ task.ext.initiatorName
|
||||||
|
}}({{task.ext.initiatorAccount}})
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="申请时间">{{ task.finishTime }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="办理结果">
|
||||||
|
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
|
||||||
|
:value="task.ext.submitType"></dict-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<el-descriptions border class="flow-task-form" :column="3" :key="task.id" v-else>
|
||||||
|
<el-descriptions-item label="办理用户">{{ task.taskFormData.userName
|
||||||
|
}}({{task.taskFormData.loginName}})
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="办理时间">{{ task.finishTime }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="办理结果">
|
||||||
|
<dict-tag :options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
|
||||||
|
:value="task.ext.submitType"></dict-tag>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="审批签字" :span="3" v-if="task.taskFormData && task.taskFormData.sign">
|
||||||
|
<el-image :src="task.taskFormData.sign" style="height: 80px" fit="contain"></el-image>
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="办理意见" v-if="!task.ext.isFirstTaskNode">{{
|
||||||
|
task.taskFormData.opinion }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
<slot></slot>
|
||||||
|
<snaker-chart ref="snakerChartRef"></snaker-chart>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
store,
|
||||||
|
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeInfoTab: 'form',
|
||||||
|
visible: false,
|
||||||
|
viewData: {},
|
||||||
|
doneTasks: [],
|
||||||
|
row: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activeInfoTab() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.$refs.recipientInfoTableRef) this.$refs.recipientInfoTableRef.doLayout()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
detailTotal() {
|
||||||
|
const cents = (this.viewData.recipients || []).reduce((sum, row) => {
|
||||||
|
const money = Number(row.money)
|
||||||
|
return sum + (Number.isFinite(money) ? Math.round(money * 100) : 0)
|
||||||
|
}, 0)
|
||||||
|
return (cents / 100).toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onOpen(row) {
|
||||||
|
this.activeInfoTab = 'form'
|
||||||
|
this.row = row
|
||||||
|
this.visible = true
|
||||||
|
this.getInfo()
|
||||||
|
this.getDoneTasks()
|
||||||
|
},
|
||||||
|
getInfo() {
|
||||||
|
this.$axios.post('/platform/special_condolence/mine/info', {id: this.row.id}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.viewData = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取已办任务审批记录
|
||||||
|
getDoneTasks() {
|
||||||
|
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.doneTasks = res.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 查看流程图
|
||||||
|
openChart(){
|
||||||
|
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: /*language=CSS*/ `
|
||||||
|
.el-descriptions-item__label {
|
||||||
|
width: 200px;
|
||||||
|
min-width: 200px;
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
.el-tabs__header {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
+229
@@ -0,0 +1,229 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<guava ref="guava">
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="年度">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="pageForm.year"
|
||||||
|
type="year"
|
||||||
|
value-format="yyyy"
|
||||||
|
placeholder="请选择年度"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="doSearch"
|
||||||
|
></el-date-picker>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="姓名/工号">
|
||||||
|
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="慰问类型">
|
||||||
|
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
|
||||||
|
placeholder="请选择慰问类型" filterable clearable>
|
||||||
|
<el-option v-for="item in typeOptions"
|
||||||
|
:value="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属工会">
|
||||||
|
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会" filterable clearable
|
||||||
|
@change="doSearch" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in unionList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属单位">
|
||||||
|
<el-select @change="doSearch"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择单位" style="width: 100%" v-model="pageForm.unitId">
|
||||||
|
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<table-tool label="申请列表">
|
||||||
|
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
|
||||||
|
<el-radio-button :label="true">已审核</el-radio-button>
|
||||||
|
<el-radio-button :label="false">未审核</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</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>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||||
|
<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="300px">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||||
|
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||||
|
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template #edit>
|
||||||
|
<specialcondolence-info ref="specialcondolenceInfoRef">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<div class="process-title">
|
||||||
|
{{formData.taskName}}
|
||||||
|
</div>
|
||||||
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||||
|
class="flow-task-form">
|
||||||
|
<el-form-item label="审批意见" prop="tf_opinion"
|
||||||
|
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||||
|
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="签字" prop="tf_sign" :rules="[{required:true,message:'请完成审批签字',trigger:['change','blur']}]">
|
||||||
|
<pc-signature v-model="formData.tf_sign" :key="formData.processTaskId"></pc-signature>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-row type="flex" justify="end">
|
||||||
|
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
|
||||||
|
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</specialcondolence-info>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</guava>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"specialcondolence-info": specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
approval: false
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'subject', label: '事项'},
|
||||||
|
{prop: 'applyUserName', label: '申请人'},
|
||||||
|
{prop: 'applyUnionName', label: '所属工会'},
|
||||||
|
{prop: 'applyUnitName', label: '所属单位'},
|
||||||
|
{prop: 'typeName', label: '慰问类型'},
|
||||||
|
{prop: 'recipientCount', label: '慰问人数', width: 100},
|
||||||
|
{prop: 'curTaskName', label: '当前节点'},
|
||||||
|
{prop: 'instanceState', label: '流程状态'},
|
||||||
|
],
|
||||||
|
unionList: [],
|
||||||
|
unitList: [],
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = false
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onAudit(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = true
|
||||||
|
this.formData = {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
}
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async handleTaskAction(val) {
|
||||||
|
try {
|
||||||
|
const valid = await this.$refs.formRef.validate()
|
||||||
|
if (!valid) return
|
||||||
|
} catch (error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: val
|
||||||
|
})
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$refs.guava.index()
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRevoke(row) {
|
||||||
|
this.$confirm("您确定要撤回吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "info"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType')
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.unionList = await this.$businessTool.listUnion()
|
||||||
|
this.unitList = await this.$businessTool.listUnit()
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
<div id="app">
|
||||||
|
<guava ref="guava">
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="年度">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="pageForm.year"
|
||||||
|
type="year"
|
||||||
|
value-format="yyyy"
|
||||||
|
placeholder="请选择年度"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="doSearch"
|
||||||
|
></el-date-picker>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="姓名/工号">
|
||||||
|
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="慰问类型">
|
||||||
|
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
|
||||||
|
placeholder="请选择慰问类型" filterable clearable>
|
||||||
|
<el-option v-for="item in typeOptions"
|
||||||
|
:value="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<table-tool label="申请列表">
|
||||||
|
<el-button type="primary" size="small" @click="onAdd">
|
||||||
|
<i class="ti-plus"></i>
|
||||||
|
新增申请
|
||||||
|
</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>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||||
|
<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="300">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||||
|
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
||||||
|
<el-button v-if="row.canRevoke" size="mini" type="danger" @click="onRevoke(row)">撤回</el-button>
|
||||||
|
<el-button v-if="row.createdBy === $store.state.user.id && row.instanceState == 20" @click="doExportApply(row)" size="mini" type="primary">导出</el-button>
|
||||||
|
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)" size="mini" type="danger">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template #view>
|
||||||
|
<specialcondolence-info ref="specialcondolenceInfoRef"></specialcondolence-info>
|
||||||
|
</template>
|
||||||
|
</guava>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"specialcondolence-info": specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
typeOptions: [],
|
||||||
|
pageDataUrl: "/platform/special_condolence/mine/pageData",
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'subject', label: '事项'},
|
||||||
|
{prop: 'applyUserName', label: '申请人'},
|
||||||
|
{prop: 'applyUnionName', label: '所属工会'},
|
||||||
|
{prop: 'applyUnitName', label: '所属单位'},
|
||||||
|
{prop: 'typeName', label: '慰问类型'},
|
||||||
|
{prop: 'recipientCount', label: '慰问人数', width: 100},
|
||||||
|
{prop: 'taskName', label: '当前节点'},
|
||||||
|
{prop: 'instanceState', label: '流程状态'},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
doExportApply(row) {
|
||||||
|
this.$downLoad('/platform/special_condolence/mine/doExportApply?id=' + row.id + '&print=false')
|
||||||
|
},
|
||||||
|
onAdd() {
|
||||||
|
commonUtil.pjaxPush('/platform/special_condolence/apply')
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.guava.view(()=>{
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onEdit(row) {
|
||||||
|
commonUtil.pjaxPush('/platform/special_condolence/apply?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
|
||||||
|
},
|
||||||
|
onRevoke(row) {
|
||||||
|
this.$confirm("您确定要撤回吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onDelete(id) {
|
||||||
|
this.$confirm("您确定要删除吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/delete", { id }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType')
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<guava ref="guava">
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="年度">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="pageForm.year"
|
||||||
|
type="year"
|
||||||
|
value-format="yyyy"
|
||||||
|
placeholder="请选择年度"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="doSearch"
|
||||||
|
></el-date-picker>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="姓名/工号">
|
||||||
|
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="慰问类型">
|
||||||
|
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
|
||||||
|
placeholder="请选择慰问类型" filterable clearable>
|
||||||
|
<el-option v-for="item in typeOptions"
|
||||||
|
:value="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属工会">
|
||||||
|
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会" filterable clearable
|
||||||
|
@change="doSearch" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in unionList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属单位">
|
||||||
|
<el-select @change="doSearch"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择单位" style="width: 100%" v-model="pageForm.unitId">
|
||||||
|
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<table-tool label="申请列表">
|
||||||
|
<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>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||||
|
<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">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="onView(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>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template #edit>
|
||||||
|
<specialcondolence-info ref="specialcondolenceInfoRef"></specialcondolence-info>
|
||||||
|
</template>
|
||||||
|
</guava>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"specialcondolence-info": specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
typeOptions: [],
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'subject', label: '事项'},
|
||||||
|
{prop: 'applyUserName', label: '申请人'},
|
||||||
|
{prop: 'applyUnionName', label: '所属工会'},
|
||||||
|
{prop: 'applyUnitName', label: '所属单位'},
|
||||||
|
{prop: 'typeName', label: '慰问类型'},
|
||||||
|
{prop: 'recipientCount', label: '慰问人数'},
|
||||||
|
{prop: 'instanceState', label: '流程状态'},
|
||||||
|
],
|
||||||
|
unionList: [],
|
||||||
|
unitList: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onDelete(id) {
|
||||||
|
this.$confirm("您确定要删除吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/delete", { id }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onExport() {
|
||||||
|
this.$downLoad(loc() + '/onExport', this.pageForm)
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType')
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.unionList = await this.$businessTool.listUnion()
|
||||||
|
this.unitList = await this.$businessTool.listUnit()
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+229
@@ -0,0 +1,229 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<guava ref="guava">
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="年度">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="pageForm.year"
|
||||||
|
type="year"
|
||||||
|
value-format="yyyy"
|
||||||
|
placeholder="请选择年度"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="doSearch"
|
||||||
|
></el-date-picker>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="姓名/工号">
|
||||||
|
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="慰问类型">
|
||||||
|
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
|
||||||
|
placeholder="请选择慰问类型" filterable clearable>
|
||||||
|
<el-option v-for="item in typeOptions"
|
||||||
|
:value="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属工会">
|
||||||
|
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会" filterable clearable
|
||||||
|
@change="doSearch" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in unionList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属单位">
|
||||||
|
<el-select @change="doSearch"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择单位" style="width: 100%" v-model="pageForm.unitId">
|
||||||
|
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<table-tool label="申请列表">
|
||||||
|
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
|
||||||
|
<el-radio-button :label="true">已审核</el-radio-button>
|
||||||
|
<el-radio-button :label="false">未审核</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</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>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||||
|
<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="300px">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||||
|
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||||
|
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template #edit>
|
||||||
|
<specialcondolence-info ref="specialcondolenceInfoRef">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<div class="process-title">
|
||||||
|
{{formData.taskName}}
|
||||||
|
</div>
|
||||||
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||||
|
class="flow-task-form">
|
||||||
|
<el-form-item label="审批意见" prop="tf_opinion"
|
||||||
|
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||||
|
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="签字" prop="tf_sign" :rules="[{required:true,message:'请完成审批签字',trigger:['change','blur']}]">
|
||||||
|
<pc-signature v-model="formData.tf_sign" :key="formData.processTaskId"></pc-signature>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-row type="flex" justify="end">
|
||||||
|
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
|
||||||
|
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</specialcondolence-info>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</guava>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"specialcondolence-info": specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
approval: false
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'subject', label: '事项'},
|
||||||
|
{prop: 'applyUserName', label: '申请人'},
|
||||||
|
{prop: 'applyUnionName', label: '所属工会'},
|
||||||
|
{prop: 'applyUnitName', label: '所属单位'},
|
||||||
|
{prop: 'typeName', label: '慰问类型'},
|
||||||
|
{prop: 'recipientCount', label: '慰问人数', width: 100},
|
||||||
|
{prop: 'curTaskName', label: '当前节点'},
|
||||||
|
{prop: 'instanceState', label: '流程状态'},
|
||||||
|
],
|
||||||
|
unionList: [],
|
||||||
|
unitList: [],
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = false
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onAudit(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = true
|
||||||
|
this.formData = {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
}
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async handleTaskAction(val) {
|
||||||
|
try {
|
||||||
|
const valid = await this.$refs.formRef.validate()
|
||||||
|
if (!valid) return
|
||||||
|
} catch (error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: val
|
||||||
|
})
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$refs.guava.index()
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRevoke(row) {
|
||||||
|
this.$confirm("您确定要撤回吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "info"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType')
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.unionList = await this.$businessTool.listUnion()
|
||||||
|
this.unitList = await this.$businessTool.listUnit()
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+229
@@ -0,0 +1,229 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<guava ref="guava">
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="年度">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="pageForm.year"
|
||||||
|
type="year"
|
||||||
|
value-format="yyyy"
|
||||||
|
placeholder="请选择年度"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="doSearch"
|
||||||
|
></el-date-picker>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="姓名/工号">
|
||||||
|
<el-input placeholder="请输入姓名或工号" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="慰问类型">
|
||||||
|
<el-select v-model="pageForm.type" @change="doSearch" style="width: 100%"
|
||||||
|
placeholder="请选择慰问类型" filterable clearable>
|
||||||
|
<el-option v-for="item in typeOptions"
|
||||||
|
:value="item.id"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属工会">
|
||||||
|
<el-select v-model="pageForm.unionId" placeholder="请选择所属工会" filterable clearable
|
||||||
|
@change="doSearch" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="item in unionList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
<search-item label="所属单位">
|
||||||
|
<el-select @change="doSearch"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择单位" style="width: 100%" v-model="pageForm.unitId">
|
||||||
|
<el-option :key="item.id" :label="item.name" :value="item.id" v-for="item in unitList"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<table-tool label="申请列表">
|
||||||
|
<el-radio-group v-model="pageForm.approval" size="small" @change="doSearch">
|
||||||
|
<el-radio-button :label="true">已审核</el-radio-button>
|
||||||
|
<el-radio-button :label="false">未审核</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</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>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'instanceState'">
|
||||||
|
<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="300px">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button @click="onView(row)" size="mini" type="primary">查看</el-button>
|
||||||
|
<el-button v-if="row.taskState === 10" @click="onAudit(row)" size="mini" type="primary">审核</el-button>
|
||||||
|
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<template #edit>
|
||||||
|
<specialcondolence-info ref="specialcondolenceInfoRef">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<div class="process-title">
|
||||||
|
{{formData.taskName}}
|
||||||
|
</div>
|
||||||
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="0" label-suffix=":"
|
||||||
|
class="flow-task-form">
|
||||||
|
<el-form-item label="审批意见" prop="tf_opinion"
|
||||||
|
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
|
||||||
|
<user-opinion-textarea v-model="formData.tf_opinion"></user-opinion-textarea>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="签字" prop="tf_sign" :rules="[{required:true,message:'请完成审批签字',trigger:['change','blur']}]">
|
||||||
|
<pc-signature v-model="formData.tf_sign" :key="formData.processTaskId"></pc-signature>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-row type="flex" justify="end">
|
||||||
|
<el-button @click="handleTaskAction(1)" size="small" type="primary">同意申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(2)" size="small" type="danger">拒绝申请</el-button>
|
||||||
|
<el-button @click="handleTaskAction(6)" size="small" type="info">退回到发起人</el-button>
|
||||||
|
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</specialcondolence-info>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</guava>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"specialcondolence-info": specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
approval: false
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'subject', label: '事项'},
|
||||||
|
{prop: 'applyUserName', label: '申请人'},
|
||||||
|
{prop: 'applyUnionName', label: '所属工会'},
|
||||||
|
{prop: 'applyUnitName', label: '所属单位'},
|
||||||
|
{prop: 'typeName', label: '慰问类型'},
|
||||||
|
{prop: 'recipientCount', label: '慰问人数', width: 100},
|
||||||
|
{prop: 'curTaskName', label: '当前节点'},
|
||||||
|
{prop: 'instanceState', label: '流程状态'},
|
||||||
|
],
|
||||||
|
unionList: [],
|
||||||
|
unitList: [],
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = false
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onAudit(row) {
|
||||||
|
this.$refs.guava.edit(()=>{
|
||||||
|
this.showApprovalForm = true
|
||||||
|
this.formData = {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
}
|
||||||
|
this.$refs.specialcondolenceInfoRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async handleTaskAction(val) {
|
||||||
|
try {
|
||||||
|
const valid = await this.$refs.formRef.validate()
|
||||||
|
if (!valid) return
|
||||||
|
} catch (error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: val
|
||||||
|
})
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$refs.guava.index()
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRevoke(row) {
|
||||||
|
this.$confirm("您确定要撤回吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "info"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType')
|
||||||
|
.then((resp) => {
|
||||||
|
this.typeOptions = resp.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.unionList = await this.$businessTool.listUnion()
|
||||||
|
this.unitList = await this.$businessTool.listUnit()
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
const basicForm = {
|
||||||
|
template: /*language=HTML*/ `
|
||||||
|
<div>
|
||||||
|
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="110px" label-position="left">
|
||||||
|
<el-form-item label="类型编码" prop="code">
|
||||||
|
<el-input type="text" v-model="formData.code" maxlength="50"
|
||||||
|
placeholder="请填写类型编码"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="类型名称" prop="name">
|
||||||
|
<el-input type="text" v-model="formData.name" maxlength="50"
|
||||||
|
placeholder="请填写类型名称"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="慰问费用" prop="money">
|
||||||
|
<el-input-number style="width: 100%" v-model="formData.money"
|
||||||
|
placeholder="请填写慰问费用" controls-position="right" :controls="false"
|
||||||
|
precision="2"
|
||||||
|
:min="0"
|
||||||
|
:max="10000"></el-input-number>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="慰问方式" prop="way">
|
||||||
|
<el-radio-group v-model="formData.way">
|
||||||
|
<el-radio-button label="慰问金 (A)" border>慰问金 (A)</el-radio-button>
|
||||||
|
<el-radio-button label="提货券 (B)" border>提货券 (B)</el-radio-button>
|
||||||
|
<el-radio-button label="慰问品 (C)" border>慰问品 (C)</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="是否启用" prop="enable">
|
||||||
|
<el-switch
|
||||||
|
v-model="formData.enable"
|
||||||
|
active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949">
|
||||||
|
</el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<!--<el-form-item label="上传会议纪要" prop="uploadMeetingRecord">
|
||||||
|
<el-radio-group v-model="formData.uploadMeetingRecord">
|
||||||
|
<el-radio-button :label="true">上传</el-radio-button>
|
||||||
|
<el-radio-button :label="false">不上传</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>-->
|
||||||
|
<el-form-item label="是否上传附件" prop="isUploadFile">
|
||||||
|
<el-radio-group v-model="formData.isUploadFile">
|
||||||
|
<el-radio-button :label="true">是</el-radio-button>
|
||||||
|
<el-radio-button :label="false">否</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="上传附件说明" prop="uploadFileDesc" v-if="formData.isUploadFile">
|
||||||
|
<el-input v-model="formData.uploadFileDesc" maxlength="50" clearable placeholder="请填写上传附件说明"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-row class="mt10" justify="end" type="flex">
|
||||||
|
<el-button @click="$emit('refresh')">取消</el-button>
|
||||||
|
<el-button @click="onSubmit" type="primary">提交</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formData: { isUploadFile: false },
|
||||||
|
formRules: {
|
||||||
|
name: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||||
|
money: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||||
|
way: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||||
|
code: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||||
|
isUploadFile: [{required: true, message: '必填', trigger: ['blur', 'change']}],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onOpen(row) {
|
||||||
|
if(row && row.id) {
|
||||||
|
this.formData = clone(row)
|
||||||
|
} else {
|
||||||
|
this.formData = { isUploadFile: false }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSubmit() {
|
||||||
|
this.$refs.formRef.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
this.$confirm("您确定要提交吗?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(async () => {
|
||||||
|
const resp = await this.$axios.post("/platform/special_condolence/type/onSubmit", this.formData)
|
||||||
|
if (resp.code === 0) {
|
||||||
|
this.$message.success(resp.msg)
|
||||||
|
this.$emit('refresh')
|
||||||
|
} else {
|
||||||
|
this.$message.warning(resp.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
style: /*language=CSS*/ `
|
||||||
|
.el-input-number .el-input__inner {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
+148
@@ -0,0 +1,148 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app" v-cloak>
|
||||||
|
<guava ref="guava">
|
||||||
|
<template>
|
||||||
|
<el-card shadow="never">
|
||||||
|
<search @search="doSearch">
|
||||||
|
<search-item label="名称/编码">
|
||||||
|
<el-input placeholder="请输入名称或编码" clearable v-model="pageForm.searchKeyword"
|
||||||
|
@keyup.enter.native="doSearch">
|
||||||
|
</el-input>
|
||||||
|
</search-item>
|
||||||
|
</search>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never" class="mt20">
|
||||||
|
<table-tool label="类型列表">
|
||||||
|
<el-button type="primary" size="small" @click="onAdd">
|
||||||
|
<i class="ti-plus"></i>
|
||||||
|
新增类型
|
||||||
|
</el-button>
|
||||||
|
</table-tool>
|
||||||
|
<el-table :data="tableData" @sort-change="pageOrder" :size="tableSize">
|
||||||
|
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
:label="column.label"
|
||||||
|
:prop="column.prop"
|
||||||
|
:key="column.prop"
|
||||||
|
:width="column.width"
|
||||||
|
:sortable="column.sortable"
|
||||||
|
align="center"
|
||||||
|
header-align="center"
|
||||||
|
show-overflow-tooltip
|
||||||
|
v-for="column in tableColumns"
|
||||||
|
>
|
||||||
|
<template v-slot="{ row }" v-if="column.prop === 'isUploadFile'">
|
||||||
|
<span v-if="row.isUploadFile" class="text-success">是</span>
|
||||||
|
<span v-else class="text-danger">否</span>
|
||||||
|
</template>
|
||||||
|
<template v-slot="{ row }" v-else-if="column.prop === 'enable'">
|
||||||
|
<el-switch
|
||||||
|
@change="switchChange(row)"
|
||||||
|
v-model="row.enable"
|
||||||
|
active-color="#13ce66"
|
||||||
|
inactive-color="#ff4949">
|
||||||
|
</el-switch>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="230">
|
||||||
|
<template v-slot="{ row }">
|
||||||
|
<el-button @click="onEdit(row)" size="mini" type="primary">编辑</el-button>
|
||||||
|
<el-button @click="onDelete(row)" size="mini" type="danger">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!--#include("/layouts/pagination.html"){}#-->
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #edit>
|
||||||
|
<basic-form ref="basicFormRef" @refresh="refresh"></basic-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</guava>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('basicForm.js'){}#-->
|
||||||
|
const vue = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
mixins: [initTableMixins],
|
||||||
|
components: {
|
||||||
|
"basic-form": basicForm,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tableColumns: [
|
||||||
|
{prop: 'code', label: '类型编码'},
|
||||||
|
{prop: 'name', label: '类型名称'},
|
||||||
|
{prop: 'money', label: '金额'},
|
||||||
|
{prop: 'way', label: '慰问方式'},
|
||||||
|
// {prop: 'isUploadFile', label: '是否上传附件'},
|
||||||
|
{prop: 'enable', label: '是否启用'},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refresh() {
|
||||||
|
this.doSearch()
|
||||||
|
this.$refs.guava.index()
|
||||||
|
},
|
||||||
|
onAdd() {
|
||||||
|
this.$refs.guava.edit(() => {
|
||||||
|
this.$refs.basicFormRef.onOpen()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onEdit(row) {
|
||||||
|
this.$refs.guava.edit(() => {
|
||||||
|
this.$refs.basicFormRef.onOpen(row)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onDelete(row) {
|
||||||
|
this.$confirm("您确定要删除吗, 是否继续?", "提示", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/type/onDelete", { id: row.id }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
switchChange(row) {
|
||||||
|
this.$axios.post("/platform/special_condolence/type/onSubmit", row).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
pageData() {
|
||||||
|
this.$axios.post(loc() + "/pageData", this.pageForm).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.tableData = res.data.list
|
||||||
|
this.pageForm.totalCount = res.data.totalCount
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
this.pageData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
@@ -255,7 +255,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<van-empty description="暂无数据" v-else></van-empty>
|
<van-empty description="暂无数据" v-else></van-empty>
|
||||||
</van-action-sheet>-->
|
</van-action-sheet>-->
|
||||||
|
|
||||||
<van-field
|
<!-- <van-field
|
||||||
v-model="formData.certifierUserName"
|
v-model="formData.certifierUserName"
|
||||||
name="certifierUserName"
|
name="certifierUserName"
|
||||||
label="证明人"
|
label="证明人"
|
||||||
@@ -288,7 +288,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<van-empty description="暂无数据" v-else></van-empty>
|
<van-empty description="暂无数据" v-else></van-empty>
|
||||||
</van-action-sheet>
|
</van-action-sheet> -->
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="formData.typeName"
|
v-model="formData.typeName"
|
||||||
@@ -322,7 +322,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
name="money"
|
name="money"
|
||||||
label="慰问金额"
|
label="慰问金额"
|
||||||
required
|
required
|
||||||
:rules="[{ required: true }]"
|
:rules="[{ required: true, message: '请填写慰问金额' }, { validator: validateMoney, message: '慰问金额须大于0且不超过10000元,最多两位小数' }]"
|
||||||
placeholder="选择慰问类型自动匹配金额"
|
placeholder="选择慰问类型自动匹配金额"
|
||||||
clickable
|
clickable
|
||||||
type="number"
|
type="number"
|
||||||
@@ -353,17 +353,19 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</van-popup>
|
</van-popup>
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
|
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||||
v-model="formData.bankCardNumber"
|
v-model="formData.bankCardNumber"
|
||||||
label="收款账户"
|
label="收款账户"
|
||||||
maxlength="20"
|
maxlength="30"
|
||||||
clearable
|
clearable
|
||||||
name="bankCardNumber"
|
name="bankCardNumber"
|
||||||
placeholder="请填写收款账户"
|
placeholder="请填写银行卡号或对公账户号"
|
||||||
:rules="[{ required: true }]"
|
:rules="[{ required: true, message: '请填写银行卡号或对公账户号' }, { pattern: /^[0-9]{6,30}$/, message: '收款账户须为6至30位数字(银行卡号或对公账户号)' }]"
|
||||||
required
|
required
|
||||||
></van-field>
|
></van-field>
|
||||||
|
|
||||||
<van-field
|
<van-field
|
||||||
|
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||||
v-model="formData.bankUserName"
|
v-model="formData.bankUserName"
|
||||||
label="户名"
|
label="户名"
|
||||||
placeholder="请填写户名"
|
placeholder="请填写户名"
|
||||||
@@ -373,9 +375,10 @@ layout("/layouts/platform_h5.html"){
|
|||||||
name="bankUserName"
|
name="bankUserName"
|
||||||
></van-field>
|
></van-field>
|
||||||
<van-field
|
<van-field
|
||||||
|
v-if="!['A', 'D'].includes(formData.typeCode)"
|
||||||
v-model="formData.bankOfDeposit"
|
v-model="formData.bankOfDeposit"
|
||||||
label="开户行"
|
label="开户行"
|
||||||
maxlength="30"
|
maxlength="20"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
rows="4"
|
rows="4"
|
||||||
autosize
|
autosize
|
||||||
@@ -433,8 +436,8 @@ layout("/layouts/platform_h5.html"){
|
|||||||
></van-datetime-picker>
|
></van-datetime-picker>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
|
|
||||||
<van-field type="digit" label="当年第几次住院"
|
<van-field type="digit" label="当年第几次住院" name="thisYearHospitalizationNum"
|
||||||
:rules="[{ required: true }]"
|
:rules="[{ required: true }, { validator: value => /^[0-9]+$/.test(String(value)) && Number(value) <= 10000, message: '住院次数须为0至10000的整数' }]"
|
||||||
required
|
required
|
||||||
placeholder="请输入当年第几次住院"
|
placeholder="请输入当年第几次住院"
|
||||||
v-model="formData.thisYearHospitalizationNum"></van-field>
|
v-model="formData.thisYearHospitalizationNum"></van-field>
|
||||||
@@ -443,6 +446,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<van-field
|
<van-field
|
||||||
v-model="formData.remark"
|
v-model="formData.remark"
|
||||||
name="remark"
|
name="remark"
|
||||||
|
maxlength="500"
|
||||||
label="申请事由"
|
label="申请事由"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
rows="4"
|
rows="4"
|
||||||
@@ -460,15 +464,18 @@ layout("/layouts/platform_h5.html"){
|
|||||||
{{ '附件说明:' + chooseType.uploadFileDesc }}
|
{{ '附件说明:' + chooseType.uploadFileDesc }}
|
||||||
</div>
|
</div>
|
||||||
<van-cell-group :border="false">
|
<van-cell-group :border="false">
|
||||||
<van-field class="direction-column-field" name="avatar" label="">
|
<van-field class="direction-column-field" name="files" label="附件" required
|
||||||
|
:rules="[{ validator: () => Array.isArray(formData.files) && formData.files.length > 0 && formData.files.length <= 5, message: '请上传1至5个附件' }]">
|
||||||
<template #input>
|
<template #input>
|
||||||
<h5-file-upload
|
<h5-file-upload
|
||||||
slot="input"
|
slot="input"
|
||||||
:value.sync="formData.files"
|
:value.sync="formData.files"
|
||||||
:upload_number="5"
|
:upload_number="5"
|
||||||
|
upload_text="上传附件"
|
||||||
upload_result_category="array"
|
upload_result_category="array"
|
||||||
complete_result
|
complete_result
|
||||||
></h5-file-upload>
|
></h5-file-upload>
|
||||||
|
<div class="condolence-card__desc">最多上传 5 个文件</div>
|
||||||
</template>
|
</template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
@@ -477,7 +484,8 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<section class="form-section">
|
<section class="form-section">
|
||||||
<h2 class="condolence-card__title">签字确认</h2>
|
<h2 class="condolence-card__title">签字确认</h2>
|
||||||
<van-cell-group :border="false">
|
<van-cell-group :border="false">
|
||||||
<van-field class="direction-column-field" name="signature" label="">
|
<van-field class="direction-column-field" name="signature" label="" :value="formData.signature"
|
||||||
|
:rules="[{ required: true, message: '请填写签字' }]">
|
||||||
<template #input>
|
<template #input>
|
||||||
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
|
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
|
||||||
</template>
|
</template>
|
||||||
@@ -532,6 +540,9 @@ layout("/layouts/platform_h5.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
validateMoney(value) {
|
||||||
|
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||||
|
},
|
||||||
// 选择出院时间
|
// 选择出院时间
|
||||||
showLeaveHospitalTimePickerClick() {
|
showLeaveHospitalTimePickerClick() {
|
||||||
if (this.formData.leaveHospitalTime) {
|
if (this.formData.leaveHospitalTime) {
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<h2 class="condolence-info-card__title">
|
<h2 class="condolence-info-card__title">
|
||||||
审批签字<span class="condolence-audit-card__required">*</span>
|
审批签字<span class="condolence-audit-card__required">*</span>
|
||||||
</h2>
|
</h2>
|
||||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-form>
|
</van-form>
|
||||||
|
|||||||
@@ -158,19 +158,44 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.condolence-info-long-cell {
|
.condolence-info-long-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condolence-info-card .condolence-attachments .empty-container {
|
||||||
|
height: auto;
|
||||||
|
justify-content: flex-start;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condolence-info-card .condolence-attachments .empty-text {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condolence-info-opinion > :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condolence-info-opinion > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.condolence-signature-image,
|
||||||
|
.condolence-approval-signature-image {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
width: 100%;
|
||||||
|
|
||||||
.condolence-info-long-cell .van-cell__title {
|
|
||||||
width: auto;
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
height: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.condolence-info-long-cell .van-cell__value {
|
.condolence-signature-image .van-image__img,
|
||||||
margin-top: 7px;
|
.condolence-approval-signature-image {
|
||||||
|
object-fit: contain;
|
||||||
|
object-position: left center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.condolence-signature-image {
|
.condolence-info-opinion img {
|
||||||
display: block;
|
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ const condolenceInfo = {
|
|||||||
<van-cell title="申请人单位">{{ viewData.applyUnitName || '--' }}</van-cell>
|
<van-cell title="申请人单位">{{ viewData.applyUnitName || '--' }}</van-cell>
|
||||||
<van-cell title="申请人工会">{{ viewData.applyUnionName || '--' }}</van-cell>
|
<van-cell title="申请人工会">{{ viewData.applyUnionName || '--' }}</van-cell>
|
||||||
<van-cell title="慰问对象">{{ viewData.helpUserName || '--' }}</van-cell>
|
<van-cell title="慰问对象">{{ viewData.helpUserName || '--' }}</van-cell>
|
||||||
<van-cell title="证明人">{{ viewData.certifierUserName || '--' }}</van-cell>
|
<!-- <van-cell title="证明人">{{ viewData.certifierUserName || '--' }}</van-cell> -->
|
||||||
<van-cell title="慰问类型">{{ viewData.typeName || '--' }}</van-cell>
|
<van-cell title="慰问类型">{{ viewData.typeName || '--' }}</van-cell>
|
||||||
<van-cell title="慰问金额">{{ viewData.money || '--' }}</van-cell>
|
<van-cell title="慰问金额">{{ viewData.money || '--' }}</van-cell>
|
||||||
<van-cell title="慰问时间">{{ viewData.occurTime || '--' }}</van-cell>
|
<van-cell title="慰问时间">{{ viewData.occurTime || '--' }}</van-cell>
|
||||||
<van-cell title="收款账户">{{ viewData.bankCardNumber || '--' }}</van-cell>
|
<van-cell title="收款账户">{{ viewData.bankCardNumber || '--' }}</van-cell>
|
||||||
<van-cell title="户名">{{ viewData.bankUserName || '--' }}</van-cell>
|
<van-cell title="户名">{{ viewData.bankUserName || '--' }}</van-cell>
|
||||||
<van-cell class="condolence-info-long-cell" title="开户行">
|
<van-cell title="开户行">
|
||||||
{{ viewData.bankOfDeposit || '暂无' }}
|
{{ viewData.bankOfDeposit || '暂无' }}
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<template v-if="['2'].includes(viewData.typeCode)">
|
<template v-if="['2'].includes(viewData.typeCode)">
|
||||||
@@ -39,17 +39,18 @@ const condolenceInfo = {
|
|||||||
<van-cell title="出院时间">{{ viewData.leaveHospitalTime || '--' }}</van-cell>
|
<van-cell title="出院时间">{{ viewData.leaveHospitalTime || '--' }}</van-cell>
|
||||||
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum || '--' }}</van-cell>
|
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum || '--' }}</van-cell>
|
||||||
</template>
|
</template>
|
||||||
<van-cell class="condolence-info-long-cell" title="申请事由">
|
<van-cell title="申请事由">
|
||||||
{{ viewData.remark || '暂无' }}
|
{{ viewData.remark || '暂无' }}
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-cell class="condolence-info-long-cell" title="附件">
|
<van-cell class="condolence-info-long-cell" title="附件">
|
||||||
<file-preview :files="viewData.files" complete_result></file-preview>
|
<file-preview class="condolence-attachments" :files="viewData.files" complete_result></file-preview>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-cell class="condolence-info-long-cell" title="签字">
|
<van-cell class="condolence-info-long-cell" title="签字">
|
||||||
<van-image
|
<van-image
|
||||||
v-if="viewData.signature"
|
v-if="viewData.signature"
|
||||||
:src="viewData.signature"
|
:src="viewData.signature"
|
||||||
class="condolence-signature-image"
|
class="condolence-signature-image"
|
||||||
|
fit="contain"
|
||||||
></van-image>
|
></van-image>
|
||||||
<span v-else>暂无签字</span>
|
<span v-else>暂无签字</span>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
@@ -86,10 +87,10 @@ const condolenceInfo = {
|
|||||||
></dict-tag>
|
></dict-tag>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-cell v-if="task.taskFormData && task.taskFormData.sign" title="审批签字">
|
<van-cell v-if="task.taskFormData && task.taskFormData.sign" title="审批签字">
|
||||||
<img :src="task.taskFormData.sign" style="max-width: 100%; height: 80px; object-fit: contain">
|
<img :src="task.taskFormData.sign" class="condolence-approval-signature-image">
|
||||||
</van-cell>
|
</van-cell>
|
||||||
<van-cell class="condolence-info-long-cell" title="办理意见">
|
<van-cell title="办理意见">
|
||||||
<div v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div>
|
<div class="condolence-info-opinion" v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
+18
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<h2 class="condolence-info-card__title">
|
<h2 class="condolence-info-card__title">
|
||||||
审批签字<span class="condolence-audit-card__required">*</span>
|
审批签字<span class="condolence-audit-card__required">*</span>
|
||||||
</h2>
|
</h2>
|
||||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-form>
|
</van-form>
|
||||||
@@ -223,6 +223,23 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
onReady() {
|
onReady() {
|
||||||
this.queryCondolenceType()
|
this.queryCondolenceType()
|
||||||
|
this.openTodoTask()
|
||||||
|
},
|
||||||
|
openTodoTask() {
|
||||||
|
const taskId = GetQueryString("taskId")
|
||||||
|
const bizId = GetQueryString("bizId")
|
||||||
|
if (!taskId || !bizId) return
|
||||||
|
this.$axios.post("/flow/common/taskInfo", {taskId}).then((res) => {
|
||||||
|
if (res.code !== 0 || !res.data) return
|
||||||
|
const task = res.data
|
||||||
|
if (task.taskName !== "cbd41337-3c87-4959-9027-809df5c7ef5e") return
|
||||||
|
const row = {id: bizId, taskId: task.id, curTaskName: task.displayName}
|
||||||
|
if (task.taskState === 10 && task.executable && GetQueryString("tab") === "todo") {
|
||||||
|
this.onApproval(row)
|
||||||
|
} else {
|
||||||
|
this.onView(row)
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onView(row) {
|
onView(row) {
|
||||||
this.$set(this, "showApprovalForm", false)
|
this.$set(this, "showApprovalForm", false)
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<h2 class="condolence-info-card__title">
|
<h2 class="condolence-info-card__title">
|
||||||
审批签字<span class="condolence-audit-card__required">*</span>
|
审批签字<span class="condolence-audit-card__required">*</span>
|
||||||
</h2>
|
</h2>
|
||||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-form>
|
</van-form>
|
||||||
|
|||||||
+1
-1
@@ -151,7 +151,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<h2 class="condolence-info-card__title">
|
<h2 class="condolence-info-card__title">
|
||||||
审批签字<span class="condolence-audit-card__required">*</span>
|
审批签字<span class="condolence-audit-card__required">*</span>
|
||||||
</h2>
|
</h2>
|
||||||
<van-field name="tf_sign" :value="formData.tf_sign" required :rules="[{required:true,message:'请完成审批签字'}]">
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
</van-field>
|
</van-field>
|
||||||
</van-form>
|
</van-form>
|
||||||
|
|||||||
+1
-71
@@ -114,33 +114,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
审批意见<span class="difficult-help-audit-card__required">*</span>
|
审批意见<span class="difficult-help-audit-card__required">*</span>
|
||||||
</h2>
|
</h2>
|
||||||
<van-form ref="formRef">
|
<van-form ref="formRef">
|
||||||
<section class="difficult-help-info-card">
|
|
||||||
<h2 class="difficult-help-info-card__title">审核信息</h2>
|
|
||||||
<div class="difficult-help-audit-form">
|
|
||||||
<van-field
|
|
||||||
v-model="formData.level"
|
|
||||||
class="difficult-help-audit-select"
|
|
||||||
name="level"
|
|
||||||
label="级别"
|
|
||||||
placeholder="请选择级别"
|
|
||||||
readonly
|
|
||||||
is-link
|
|
||||||
required
|
|
||||||
@click="openLevelPicker"
|
|
||||||
:rules="[{ required: true, message: '请选择级别' }]"
|
|
||||||
></van-field>
|
|
||||||
<van-field
|
|
||||||
v-model="formData.money"
|
|
||||||
class="difficult-help-audit-money"
|
|
||||||
name="money"
|
|
||||||
label="帮扶金额(元)"
|
|
||||||
placeholder="请输入帮扶金额(元)"
|
|
||||||
type="number"
|
|
||||||
required
|
|
||||||
:rules="[{ required: true, message: '请输入帮扶金额(元)' }]"
|
|
||||||
></van-field>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="formData.tf_opinion"
|
v-model="formData.tf_opinion"
|
||||||
class="difficult-help-audit-textarea"
|
class="difficult-help-audit-textarea"
|
||||||
@@ -167,14 +140,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</info>
|
</info>
|
||||||
<van-popup :value="showLevelPicker" position="bottom" :close-on-click-overlay="false">
|
|
||||||
<van-picker
|
|
||||||
show-toolbar
|
|
||||||
:columns="levelColumns"
|
|
||||||
@confirm="onLevelConfirm"
|
|
||||||
@cancel="closeLevelPicker">
|
|
||||||
</van-picker>
|
|
||||||
</van-popup>
|
|
||||||
<van-dialog
|
<van-dialog
|
||||||
:value="confirmVisible"
|
:value="confirmVisible"
|
||||||
title="提示"
|
title="提示"
|
||||||
@@ -214,8 +179,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
skeletonLoading: true,
|
skeletonLoading: true,
|
||||||
|
|
||||||
formData: {},
|
formData: {},
|
||||||
levelColumns: [],
|
|
||||||
showLevelPicker: false,
|
|
||||||
showApprovalForm: false,
|
showApprovalForm: false,
|
||||||
formLoading: false,
|
formLoading: false,
|
||||||
confirmVisible: false,
|
confirmVisible: false,
|
||||||
@@ -280,42 +243,11 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$set(this, "formData", {
|
this.$set(this, "formData", {
|
||||||
processTaskId: row.taskId,
|
processTaskId: row.taskId,
|
||||||
taskName: row.curTaskName,
|
taskName: row.curTaskName,
|
||||||
level: "",
|
|
||||||
money: undefined,
|
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
})
|
})
|
||||||
this.$refs.infoRef.onOpen(row, row.curTaskName || "帮扶审核")
|
this.$refs.infoRef.onOpen(row, row.curTaskName || "帮扶审核")
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载困难级别字典并转换为 Vant Picker 所需的 text/value 结构。
|
|
||||||
initLevelDict() {
|
|
||||||
return this.$axios.post("/open/common/dictOptions", {code: "DIFFICULT_LEVEL"}, {h5SkeletonLoading: true}).then((res) => {
|
|
||||||
const levelData = res && res.code === 0 ? res.data : []
|
|
||||||
this.$set(this, "levelColumns", (levelData || []).map((item) => ({
|
|
||||||
text: item.name,
|
|
||||||
value: item.code
|
|
||||||
})))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 级别选择器作为详情上层弹框,打开时同步增加浏览器历史。
|
|
||||||
openLevelPicker() {
|
|
||||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("difficult-help-level-picker")) return
|
|
||||||
this.$set(this, "showLevelPicker", true)
|
|
||||||
},
|
|
||||||
|
|
||||||
closeLevelPicker(afterClose = null) {
|
|
||||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("difficult-help-level-picker", afterClose)) return
|
|
||||||
this.$set(this, "showLevelPicker", false)
|
|
||||||
if (typeof afterClose === "function") afterClose()
|
|
||||||
},
|
|
||||||
|
|
||||||
onLevelConfirm(option) {
|
|
||||||
this.closeLevelPicker(() => {
|
|
||||||
this.$set(this.formData, "level", option.value)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// val 为流程提交类型:1 同意、2 拒绝、6 退回;校验通过后打开历史栈确认框。
|
// val 为流程提交类型:1 同意、2 拒绝、6 退回;校验通过后打开历史栈确认框。
|
||||||
handleTaskAction(val) {
|
handleTaskAction(val) {
|
||||||
this.$refs.formRef.validate()
|
this.$refs.formRef.validate()
|
||||||
@@ -427,14 +359,12 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
// 先订阅弹框状态,工会加载异常也不能阻断等级选择器与确认框的打开、返回。
|
// 先订阅弹框状态,工会加载异常也不能阻断确认框的打开、返回。
|
||||||
if (window.h5HistoryLayerManager) {
|
if (window.h5HistoryLayerManager) {
|
||||||
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
this.$set(this, "confirmVisible", stack.includes("difficult-help-action-confirm"))
|
this.$set(this, "confirmVisible", stack.includes("difficult-help-action-confirm"))
|
||||||
this.$set(this, "showLevelPicker", stack.includes("difficult-help-level-picker"))
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
this.initLevelDict()
|
|
||||||
// 缓存已就绪时立即加载,否则等待用户接口回填;只初始化一次,避免重置已选筛选条件。
|
// 缓存已就绪时立即加载,否则等待用户接口回填;只初始化一次,避免重置已选筛选条件。
|
||||||
// $watch 由当前 Vue 实例管理,页面销毁时自动注销。
|
// $watch 由当前 Vue 实例管理,页面销毁时自动注销。
|
||||||
let filtersInitialized = false
|
let filtersInitialized = false
|
||||||
|
|||||||
-54
@@ -113,18 +113,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<section class="difficult-help-info-card">
|
<section class="difficult-help-info-card">
|
||||||
<h2 class="difficult-help-info-card__title">审核信息</h2>
|
<h2 class="difficult-help-info-card__title">审核信息</h2>
|
||||||
<div class="difficult-help-audit-form">
|
<div class="difficult-help-audit-form">
|
||||||
<van-field
|
|
||||||
v-model="formData.level"
|
|
||||||
class="difficult-help-audit-select"
|
|
||||||
name="level"
|
|
||||||
label="级别"
|
|
||||||
placeholder="请选择级别"
|
|
||||||
readonly
|
|
||||||
is-link
|
|
||||||
required
|
|
||||||
@click="openLevelPicker"
|
|
||||||
:rules="[{ required: true, message: '请选择级别' }]"
|
|
||||||
></van-field>
|
|
||||||
<van-field
|
<van-field
|
||||||
v-model="formData.money"
|
v-model="formData.money"
|
||||||
class="difficult-help-audit-money"
|
class="difficult-help-audit-money"
|
||||||
@@ -167,14 +155,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</info>
|
</info>
|
||||||
<van-popup :value="showLevelPicker" position="bottom" :close-on-click-overlay="false">
|
|
||||||
<van-picker
|
|
||||||
show-toolbar
|
|
||||||
:columns="levelColumns"
|
|
||||||
@confirm="onLevelConfirm"
|
|
||||||
@cancel="closeLevelPicker">
|
|
||||||
</van-picker>
|
|
||||||
</van-popup>
|
|
||||||
<van-dialog
|
<van-dialog
|
||||||
:value="confirmVisible"
|
:value="confirmVisible"
|
||||||
title="提示"
|
title="提示"
|
||||||
@@ -216,8 +196,6 @@ layout("/layouts/platform_h5.html"){
|
|||||||
formData: {},
|
formData: {},
|
||||||
showApprovalForm: false,
|
showApprovalForm: false,
|
||||||
formLoading: false,
|
formLoading: false,
|
||||||
showLevelPicker: false,
|
|
||||||
levelColumns: [],
|
|
||||||
confirmVisible: false,
|
confirmVisible: false,
|
||||||
confirmActionType: "task",
|
confirmActionType: "task",
|
||||||
pendingSubmitType: null,
|
pendingSubmitType: null,
|
||||||
@@ -272,42 +250,12 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$set(this, "formData", {
|
this.$set(this, "formData", {
|
||||||
processTaskId: row.taskId,
|
processTaskId: row.taskId,
|
||||||
taskName: row.curTaskName,
|
taskName: row.curTaskName,
|
||||||
level: "",
|
|
||||||
money: undefined,
|
money: undefined,
|
||||||
tf_sign: "", tf_opinion: ""
|
tf_sign: "", tf_opinion: ""
|
||||||
})
|
})
|
||||||
this.$refs.infoRef.onOpen(row, row.curTaskName || "帮扶审核")
|
this.$refs.infoRef.onOpen(row, row.curTaskName || "帮扶审核")
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载困难级别字典并转换为 Vant Picker 所需的 text/value 结构。
|
|
||||||
initLevelDict() {
|
|
||||||
return this.$axios.post("/open/common/dictOptions", {code: "DIFFICULT_LEVEL"}, {h5SkeletonLoading: true}).then((res) => {
|
|
||||||
const levelData = res && res.code === 0 ? res.data : []
|
|
||||||
this.$set(this, "levelColumns", (levelData || []).map((item) => ({
|
|
||||||
text: item.name,
|
|
||||||
value: item.code
|
|
||||||
})))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 级别选择器作为详情上层弹框,打开时同步增加浏览器历史。
|
|
||||||
openLevelPicker() {
|
|
||||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("difficult-help-level-picker")) return
|
|
||||||
this.$set(this, "showLevelPicker", true)
|
|
||||||
},
|
|
||||||
|
|
||||||
closeLevelPicker(afterClose = null) {
|
|
||||||
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("difficult-help-level-picker", afterClose)) return
|
|
||||||
this.$set(this, "showLevelPicker", false)
|
|
||||||
if (typeof afterClose === "function") afterClose()
|
|
||||||
},
|
|
||||||
|
|
||||||
onLevelConfirm(option) {
|
|
||||||
this.closeLevelPicker(() => {
|
|
||||||
this.$set(this.formData, "level", option.value)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// val 为流程提交类型:1 同意、2 拒绝、6 退回;校验通过后打开历史栈确认框。
|
// val 为流程提交类型:1 同意、2 拒绝、6 退回;校验通过后打开历史栈确认框。
|
||||||
handleTaskAction(val) {
|
handleTaskAction(val) {
|
||||||
this.$refs.formRef.validate()
|
this.$refs.formRef.validate()
|
||||||
@@ -420,11 +368,9 @@ layout("/layouts/platform_h5.html"){
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initUnion().then(() => this.flushUnits())
|
this.initUnion().then(() => this.flushUnits())
|
||||||
this.initLevelDict()
|
|
||||||
if (!window.h5HistoryLayerManager) return
|
if (!window.h5HistoryLayerManager) return
|
||||||
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
this.$set(this, "confirmVisible", stack.includes("difficult-help-action-confirm"))
|
this.$set(this, "confirmVisible", stack.includes("difficult-help-action-confirm"))
|
||||||
this.$set(this, "showLevelPicker", stack.includes("difficult-help-level-picker"))
|
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
|||||||
+563
@@ -0,0 +1,563 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#app {
|
||||||
|
--color-primary: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > .van-nav-bar .van-icon,
|
||||||
|
#app > .van-nav-bar .van-nav-bar__text {
|
||||||
|
color: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app > .van-nav-bar .van-nav-bar__title,
|
||||||
|
#app > .van-nav-bar .van-nav-bar__text,
|
||||||
|
#app > .van-nav-bar .van-nav-bar__arrow {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-dialog {
|
||||||
|
height: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 慰问申请页复用提案撰写页的 Card 层级,仅覆盖当前表单分组和底部操作栏。 */
|
||||||
|
.specialcondolence-apply-form.form-container {
|
||||||
|
min-height: 100%;
|
||||||
|
padding: 12px 15px calc(84px + env(safe-area-inset-bottom));
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #f3f7fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form > .van-tabs > .van-tabs__content {
|
||||||
|
padding-top: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section {
|
||||||
|
margin-bottom: 11px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #e9eff7;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 3px 11px rgba(51, 87, 126, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .specialcondolence-card__title {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 14px 8px 21px;
|
||||||
|
color: #354255;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .specialcondolence-card__title::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
bottom: 11px;
|
||||||
|
left: 12px;
|
||||||
|
width: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #1989fa;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-cell-group {
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card__desc {
|
||||||
|
padding: 0 14px 8px 21px;
|
||||||
|
color: orangered;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-cell {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-cell:not(:last-child)::after {
|
||||||
|
right: 14px;
|
||||||
|
left: 14px;
|
||||||
|
border-color: #eef2f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-field__label {
|
||||||
|
width: 84px;
|
||||||
|
color: #596779;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-field__value,
|
||||||
|
.specialcondolence-apply-form .form-section .van-field__control {
|
||||||
|
color: #4f5d70;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-field__control::placeholder {
|
||||||
|
color: #b1bac6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-form .form-section .van-cell--required::before {
|
||||||
|
left: 6px;
|
||||||
|
color: #f06464;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-actions {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 9px;
|
||||||
|
padding: 10px 18px calc(10px + env(safe-area-inset-bottom));
|
||||||
|
border-top: 1px solid #edf1f6;
|
||||||
|
background: rgba(255, 255, 255, 0.98);
|
||||||
|
box-shadow: 0 -4px 14px rgba(50, 78, 112, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-actions .van-button {
|
||||||
|
height: 40px;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 14px !important;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-actions .van-button:first-child {
|
||||||
|
flex: 1;
|
||||||
|
color: #1989fa;
|
||||||
|
border-color: #1989fa;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-apply-actions .van-button:last-child {
|
||||||
|
flex: 1.08;
|
||||||
|
border-color: #1989fa;
|
||||||
|
background: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .van-action-sheet__header,
|
||||||
|
#app .van-picker__title,
|
||||||
|
.van-dialog__header {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .van-action-sheet__name,
|
||||||
|
#app .van-action-sheet__cancel,
|
||||||
|
#app .van-empty__description,
|
||||||
|
#app .van-search__field,
|
||||||
|
#app .van-picker__cancel,
|
||||||
|
#app .van-picker__confirm,
|
||||||
|
.van-dialog__message {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app .van-picker-column__item {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.specialcondolence-apply-form .van-field__error-message,
|
||||||
|
.specialcondolence-apply-form .van-field--error .van-field__control { color: #ee0a24 !important; }
|
||||||
|
.specialcondolence-apply-form .van-field__error-message { font-size: 12px; line-height: 18px; padding-top: 4px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<van-nav-bar title="特殊慰问申请" left-text="返回" left-arrow @click-left="historyBack" fixed
|
||||||
|
placeholder></van-nav-bar>
|
||||||
|
|
||||||
|
<!-- 表单容器 -->
|
||||||
|
<van-form ref="formRef" class="form-container specialcondolence-apply-form" :show-error="true" :show-error-message="true">
|
||||||
|
|
||||||
|
<van-tabs v-model="activeApplicationTab" :lazy-render="false">
|
||||||
|
<van-tab title="基础信息" name="form">
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<section class="form-section">
|
||||||
|
<h2 class="specialcondolence-card__title">基本信息</h2>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<van-field v-model="formData.subject" name="subject" label="事项" maxlength="200" required placeholder="请输入特殊慰问事项" :rules="[{ validator: value => !!String(value || '').trim() && String(value).length <= 200, message: '请填写200字以内的事项' }]"></van-field>
|
||||||
|
<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-field :value="chooseType.name || formData.typeName" name="type" label="慰问类型" readonly clickable is-link required placeholder="请选择慰问类型" :rules="[{ validator: () => !!formData.type, message: '请选择慰问类型' }]" @click="showTypePickerClick"></van-field>
|
||||||
|
<van-popup v-model="showTypePicker" position="bottom" round get-container="body"><van-picker :columns="typeColumns" :default-index="typeDefaultIndex" show-toolbar @confirm="onTypeConfirm" @cancel="showTypePicker = false"></van-picker></van-popup>
|
||||||
|
<van-field v-model="formData.perMoney" name="perMoney" label="慰问金额" type="number" readonly required :rules="[{ validator: validateMoney, message: '金额须大于0且不超过10000元,最多两位小数' }]"></van-field>
|
||||||
|
<van-field v-model="formData.occurTime" name="occurTime" label="慰问时间" readonly clickable is-link placeholder="请选择慰问时间" required :rules="[{ validator: value => $moment(value, 'YYYY-MM-DD', true).isValid(), message: '请选择有效慰问时间' }]" @click="showTimePickerClick"></van-field>
|
||||||
|
<van-popup v-model="showTimePicker" position="bottom" round get-container="body"><van-datetime-picker v-if="showTimePicker" v-model="formData.occurDate" type="date" :min-date="minDate" :max-date="maxDate" title="请选择慰问时间" @confirm="confirmOccurTime" @cancel="showTimePicker = false"></van-datetime-picker></van-popup>
|
||||||
|
<van-field
|
||||||
|
v-model="formData.remark"
|
||||||
|
name="remark"
|
||||||
|
maxlength="500"
|
||||||
|
label="申请事由"
|
||||||
|
type="textarea"
|
||||||
|
rows="4"
|
||||||
|
autosize
|
||||||
|
placeholder="请输入申请事由"
|
||||||
|
:rules="[{ required: true }]"
|
||||||
|
required
|
||||||
|
></van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="form-section" v-if="chooseType.isUploadFile === true">
|
||||||
|
<h2 class="specialcondolence-card__title">附件材料</h2>
|
||||||
|
<div v-if="chooseType.isUploadFile && chooseType.uploadFileDesc" class="specialcondolence-card__desc">
|
||||||
|
{{ '附件说明:' + chooseType.uploadFileDesc }}
|
||||||
|
</div>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<van-field class="direction-column-field" name="files" label="附件" required
|
||||||
|
:rules="[{ validator: () => Array.isArray(formData.files) && formData.files.length > 0 && formData.files.length <= 5, message: '请上传1至5个附件' }]">
|
||||||
|
<template #input>
|
||||||
|
<h5-file-upload
|
||||||
|
slot="input"
|
||||||
|
:value.sync="formData.files"
|
||||||
|
:upload_number="5"
|
||||||
|
upload_text="上传附件"
|
||||||
|
upload_result_category="array"
|
||||||
|
complete_result
|
||||||
|
></h5-file-upload>
|
||||||
|
<div class="specialcondolence-card__desc">最多上传 5 个文件</div>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="form-section">
|
||||||
|
<h2 class="specialcondolence-card__title">签字确认</h2>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<van-field class="direction-column-field" name="signature" label="" :value="formData.signature"
|
||||||
|
:rules="[{ required: true, message: '请填写签字' }]">
|
||||||
|
<template #input>
|
||||||
|
<h5-signature v-model="formData.signature" slot="input"></h5-signature>
|
||||||
|
</template>
|
||||||
|
</van-field>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="慰问对象" name="recipients">
|
||||||
|
<section class="form-section">
|
||||||
|
<h2 class="specialcondolence-card__title">慰问对象</h2>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<div v-for="(person, index) in formData.recipients" :key="index">
|
||||||
|
<van-cell :title="'慰问对象 ' + (index + 1)" :title-style="{ fontWeight: 'bold' }"><van-button native-type="button" size="mini" @click="formData.recipients.splice(index, 1)">删除</van-button></van-cell>
|
||||||
|
<h5-user-select v-model="person.helpUserId" :display-name="person.helpUserName" api="/platform/special_condolence/apply/listUser" label="慰问对象" placeholder="点击选择本工会人员" required :name="'recipients.' + index + '.helpUserId'" :rules="mobileRecipientRules('helpUserId', person)" @selected="(user, id) => recipientUserChange(person, index, id, user)"></h5-user-select>
|
||||||
|
<van-field v-model="person.helpLoginName" label="工号" readonly placeholder="选人后带出,劳务派遣可空" :required="!!person.helpUserId && person.personType !== '劳务派遣人员'" :name="'recipients.' + index + '.helpLoginName'" :rules="mobileRecipientRules('helpLoginName', person)"></van-field>
|
||||||
|
<van-field v-model="person.idCard" label="身份证号码" maxlength="18" required :name="'recipients.' + index + '.idCard'" :rules="mobileRecipientRules('idCard', person)"></van-field>
|
||||||
|
<van-field v-model="person.bankOfDeposit" label="开户行" maxlength="100" required :name="'recipients.' + index + '.bankOfDeposit'" :rules="mobileRecipientRules('bankOfDeposit', person)"></van-field>
|
||||||
|
<van-field v-model="person.bankUserName" label="户名" maxlength="100" required :name="'recipients.' + index + '.bankUserName'" :rules="mobileRecipientRules('bankUserName', person)"></van-field>
|
||||||
|
<van-field v-model="person.bankCardNumber" label="收款账户" maxlength="30" required :name="'recipients.' + index + '.bankCardNumber'" :rules="mobileRecipientRules('bankCardNumber', person)"></van-field>
|
||||||
|
</div>
|
||||||
|
<van-field name="recipients" :value="recipientCount" :rules="[{ validator: value => Number(value) > 0, message: '请至少添加一位慰问对象' }]"><template #input><van-button native-type="button" size="small" type="info" plain @click="formData.recipients.push(newRecipient())">增加一行</van-button></template></van-field>
|
||||||
|
<van-cell title="慰问金额合计" :value="'¥ ' + recipientTotal + '(' + recipientCount + '人)'"></van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<div class="form-actions specialcondolence-apply-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>
|
||||||
|
</van-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include("/platform/zhgh/staffbenefit/specialcondolence/apply/recipients.js"){}#-->
|
||||||
|
const vue = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
mixins: [specialCondolenceRecipients],
|
||||||
|
components: {
|
||||||
|
'h5-user-select': httpVueLoader('/components/plugins/sysUserSelect/h5Index.vue?v=' + h5ComponentVersion)
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bizId: GetQueryString("bizId"),
|
||||||
|
taskId: GetQueryString("taskId"),
|
||||||
|
formData: { recipients: [this.newRecipient()], occurTime: this.$moment().format('YYYY-MM-DD') },
|
||||||
|
|
||||||
|
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),
|
||||||
|
maxDate: new Date(2100, 11, 31),
|
||||||
|
|
||||||
|
typeDefaultIndex: 0
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$store.state.user'(user) {
|
||||||
|
if (user && !this.bizId && !this.formData.applyUserId) this.init()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showInvalidApplicationTab(errors) {
|
||||||
|
if (!Array.isArray(errors) || !errors.length) return
|
||||||
|
const error = errors[0]
|
||||||
|
const name = String(error.name || '')
|
||||||
|
const recipient = name.match(/^recipients\.(\d+)\./)
|
||||||
|
this.activeApplicationTab = name.startsWith('recipients') ? 'recipients' : 'form'
|
||||||
|
const message = error.message || '请完善必填信息'
|
||||||
|
this.$toast.fail(recipient ? '第' + (Number(recipient[1]) + 1) + '位慰问对象:' + message : message)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.formRef.scrollToField(error.name)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
mobileRecipientRules(field, person) {
|
||||||
|
const names = { helpUserId: '慰问对象', helpLoginName: '工号', idCard: '身份证号码', bankOfDeposit: '开户行', bankUserName: '户名', bankCardNumber: '收款账户' }
|
||||||
|
if (field === 'helpLoginName') return [{ validator: value => !person.helpUserId || person.personType === '劳务派遣人员' || !!String(value || '').trim(), message: '请完善慰问对象信息(工号不能为空)' }]
|
||||||
|
if (field === 'helpUserId') return [{ validator: () => !!(person.helpUserId || person.helpUserName), message: '请选择慰问对象' }]
|
||||||
|
const rules = [{ validator: value => !!String(value || '').trim(), message: '请填写' + names[field] }]
|
||||||
|
if (field === 'idCard') rules.push({ validator: value => this.validRecipientIdCard(value), message: '身份证号码不正确' })
|
||||||
|
if (field === 'bankCardNumber') rules.push({ pattern: /^[0-9]{6,30}$/, message: '收款账户须为6至30位数字' })
|
||||||
|
if (field === 'bankOfDeposit' || field === 'bankUserName') rules.push({ validator: value => String(value || '').length <= 100, message: names[field] + '最多100字' })
|
||||||
|
return rules
|
||||||
|
},
|
||||||
|
|
||||||
|
validateMoney(value) {
|
||||||
|
return /^(0|[1-9][0-9]*)(\.[0-9]{1,2})?$/.test(String(value)) && Number(value) > 0 && Number(value) <= 10000
|
||||||
|
},
|
||||||
|
// 选择出院时间
|
||||||
|
showLeaveHospitalTimePickerClick() {
|
||||||
|
if (this.formData.leaveHospitalTime) {
|
||||||
|
this.formData.leaveHospitalDate = new Date(this.formData.leaveHospitalTime)
|
||||||
|
}
|
||||||
|
this.showLeaveHospitalTimePicker = true
|
||||||
|
},
|
||||||
|
// 选择住院时间
|
||||||
|
showHospitalizationTimePickerClick() {
|
||||||
|
if (this.formData.hospitalizationTime) {
|
||||||
|
this.formData.hospitalizationDate = new Date(this.formData.hospitalizationTime)
|
||||||
|
}
|
||||||
|
this.showHospitalizationTimePicker = true
|
||||||
|
},
|
||||||
|
// 选择慰问时间
|
||||||
|
showTimePickerClick() {
|
||||||
|
this.$set(this.formData, 'occurDate', this.formData.occurTime ? this.$moment(this.formData.occurTime, 'YYYY-MM-DD').toDate() : new Date())
|
||||||
|
this.showTimePicker = true
|
||||||
|
},
|
||||||
|
confirmOccurTime(value) {
|
||||||
|
this.$set(this.formData, 'occurTime', this.$moment(value).format('YYYY-MM-DD'))
|
||||||
|
this.showTimePicker = false
|
||||||
|
this.$nextTick(() => this.$refs.formRef.validate('occurTime').catch(() => {}))
|
||||||
|
},
|
||||||
|
// 选择慰问类型
|
||||||
|
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 = []
|
||||||
|
},
|
||||||
|
//证明人
|
||||||
|
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
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async selectQueryUser(keyword) {
|
||||||
|
const res = await this.$axios.post("/platform/special_condolence/apply/listUser", { keyword: keyword })
|
||||||
|
return res.data
|
||||||
|
},
|
||||||
|
helpUserChange(user) {
|
||||||
|
const { id, userName, loginName, unitId, unitName, unionId, unionName } = user
|
||||||
|
this.$set(this.formData, "helpUserId", id)
|
||||||
|
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.helpUserSelectShow = false
|
||||||
|
this.searchKeyword = ""
|
||||||
|
this.userOptions = []
|
||||||
|
},
|
||||||
|
payUserChange(user) {
|
||||||
|
const { id, userName, loginName } = user
|
||||||
|
this.$set(this.formData, "payUserId", id)
|
||||||
|
this.$set(this.formData, "payUserName", userName)
|
||||||
|
this.$set(this.formData, "payLoginName", loginName)
|
||||||
|
this.payUserSelectShow = false
|
||||||
|
this.searchKeyword = ""
|
||||||
|
this.userOptions = []
|
||||||
|
},
|
||||||
|
typeChange(id) {
|
||||||
|
this.chooseType = this.typeOptions.find(o => o.id === id)
|
||||||
|
if (this.chooseType) {
|
||||||
|
this.$set(this.formData, "perMoney", this.chooseType.money)
|
||||||
|
this.$set(this.formData, "way", this.chooseType.way)
|
||||||
|
this.$set(this.formData, "typeCode", this.chooseType.code)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTypeConfirm(o) {
|
||||||
|
this.$set(this.formData, "typeName", o.text)
|
||||||
|
this.$set(this.formData, "type", o.value)
|
||||||
|
this.typeChange(o.value)
|
||||||
|
this.showTypePicker = false
|
||||||
|
},
|
||||||
|
onSave() {
|
||||||
|
this.$dialog.confirm({
|
||||||
|
title: "提示",
|
||||||
|
message: "您确定保存吗?"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/save", { data: JSON.stringify(this.formData) }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine/h5")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async onSubmit() {
|
||||||
|
this.$refs.formRef.validate().then(() => {
|
||||||
|
if (!this.formData.signature){
|
||||||
|
this.$toast.fail("请填写签字")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$dialog.confirm({
|
||||||
|
title: "提示",
|
||||||
|
message: "您确定要提交申请吗?"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/submit", { data: JSON.stringify(this.formData) }).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine/h5")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(errors => this.showInvalidApplicationTab(errors))
|
||||||
|
},
|
||||||
|
async onFinishTask() {
|
||||||
|
this.$refs.formRef.validate().then(() => {
|
||||||
|
if (!this.formData.signature){
|
||||||
|
this.$toast.fail("请填写签字")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$dialog.confirm({
|
||||||
|
title: "提示",
|
||||||
|
message: "您确定要提交申请吗?"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/apply/submitAgain", {
|
||||||
|
data: JSON.stringify(this.formData),
|
||||||
|
taskId: GetQueryString("taskId")
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast(res.msg)
|
||||||
|
window.location.replace("/platform/special_condolence/mine/h5")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(errors => this.showInvalidApplicationTab(errors))
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
if (this.bizId) {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/info", { id: this.bizId }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.formData = res.data
|
||||||
|
this.initRecipients()
|
||||||
|
this.chooseType = this.typeOptions.find(o => o.id === this.formData.type) || {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const user = this.$store.state.user
|
||||||
|
if (!user) return
|
||||||
|
const { username, loginname, id, unit, union, mobile } = user
|
||||||
|
this.formData = Object.assign({}, this.formData, {
|
||||||
|
applyUserName: username,
|
||||||
|
applyLoginName: loginname,
|
||||||
|
applyUserId: id,
|
||||||
|
applyUnitId: unit?.id,
|
||||||
|
applyUnitName: unit?.name,
|
||||||
|
applyUnionId: union?.id,
|
||||||
|
applyUnionName: union?.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post("/platform/special_condolence/type/querySpecialCondolenceType")
|
||||||
|
.then((res) => {
|
||||||
|
this.typeOptions = JSON.parse(JSON.stringify(res.data))
|
||||||
|
res.data.forEach((v) => {
|
||||||
|
this.typeColumns.push({ value: v.id, text: v.name })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+205
@@ -0,0 +1,205 @@
|
|||||||
|
.specialcondolence-full-popup {
|
||||||
|
--color-primary: #1989fa;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f3f7fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-full-popup__page {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 46px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-full-popup__page > .van-nav-bar {
|
||||||
|
z-index: 20;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-full-popup__page > .van-nav-bar .van-icon,
|
||||||
|
.specialcondolence-full-popup__page > .van-nav-bar .van-nav-bar__text {
|
||||||
|
color: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-full-popup__scroll {
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex: 1;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-main {
|
||||||
|
padding: 12px 15px calc(18px + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-main > .van-tabs > .van-tabs__content {
|
||||||
|
padding-top: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card {
|
||||||
|
margin-bottom: 11px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #e9eff7;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 3px 11px rgba(51, 87, 126, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card__title {
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 12px 14px 8px 21px;
|
||||||
|
color: #354255;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card__title::before {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
bottom: 11px;
|
||||||
|
left: 12px;
|
||||||
|
width: 2px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #1989fa;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 审核意见复用详情 Card 标题,并与提案 delegation 审核输入区保持一致。 */
|
||||||
|
.specialcondolence-audit-card__required {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: #ee0a24;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-field.specialcondolence-audit-field {
|
||||||
|
width: calc(100% - 28px);
|
||||||
|
margin: 0 14px 14px;
|
||||||
|
padding: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #c9d5e5;
|
||||||
|
border-radius: 0;
|
||||||
|
background: #f7f9fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-field.specialcondolence-audit-field .van-field__control {
|
||||||
|
min-height: 150px;
|
||||||
|
color: #253247;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-field.specialcondolence-audit-field .van-field__control::placeholder {
|
||||||
|
color: #9aa7b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-field.specialcondolence-audit-field .van-field__word-limit {
|
||||||
|
color: #718096;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-field.specialcondolence-audit-field::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-popup-actions {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 12px calc(12px + env(safe-area-inset-bottom));
|
||||||
|
justify-content: space-between;
|
||||||
|
column-gap: 10px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-popup-actions .van-button {
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-popup-actions .specialcondolence-action-primary {
|
||||||
|
border-color: #1989fa;
|
||||||
|
background: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-popup-actions .specialcondolence-action-danger {
|
||||||
|
border-color: #ff4d4f;
|
||||||
|
background: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-cell-group {
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-cell {
|
||||||
|
min-height: 44px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-cell:not(:last-child)::after {
|
||||||
|
right: 14px;
|
||||||
|
left: 14px;
|
||||||
|
border-color: #eef2f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-cell__title {
|
||||||
|
width: 102px;
|
||||||
|
color: #596779;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
flex: 0 0 102px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .van-cell__value {
|
||||||
|
min-width: 0;
|
||||||
|
color: #4f5d70;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: left;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-long-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .specialcondolence-attachments .empty-container {
|
||||||
|
height: auto;
|
||||||
|
justify-content: flex-start;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-card .specialcondolence-attachments .empty-text {
|
||||||
|
font-size: inherit;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-opinion > :first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-opinion > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-signature-image,
|
||||||
|
.specialcondolence-approval-signature-image {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-signature-image .van-image__img,
|
||||||
|
.specialcondolence-approval-signature-image {
|
||||||
|
object-fit: contain;
|
||||||
|
object-position: left center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-info-opinion img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
+209
@@ -0,0 +1,209 @@
|
|||||||
|
const specialcondolenceInfo = {
|
||||||
|
template: /*language=HTML*/ `
|
||||||
|
<van-popup
|
||||||
|
v-model="visible"
|
||||||
|
position="right"
|
||||||
|
class="specialcondolence-full-popup"
|
||||||
|
:close-on-click-overlay="false"
|
||||||
|
get-container="#app"
|
||||||
|
>
|
||||||
|
<div class="specialcondolence-full-popup__page">
|
||||||
|
<van-nav-bar
|
||||||
|
:title="popupTitle"
|
||||||
|
left-arrow
|
||||||
|
left-text="返回"
|
||||||
|
fixed
|
||||||
|
@click-left="onClose()"
|
||||||
|
></van-nav-bar>
|
||||||
|
<div class="specialcondolence-full-popup__scroll">
|
||||||
|
<main class="specialcondolence-info-main">
|
||||||
|
<van-tabs v-model="activeInfoTab" :lazy-render="false">
|
||||||
|
<van-tab title="基础信息" name="form">
|
||||||
|
<section class="specialcondolence-info-card">
|
||||||
|
<h2 class="specialcondolence-info-card__title">基本信息</h2>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<van-cell title="事项">{{ viewData.subject || '--' }}</van-cell>
|
||||||
|
<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>
|
||||||
|
<template v-if="viewData.recipients && viewData.recipients.length">
|
||||||
|
<van-cell title="慰问类型" :value="viewData.typeName"></van-cell>
|
||||||
|
<van-cell title="每人慰问金额" :value="viewData.perMoney"></van-cell>
|
||||||
|
<van-cell title="慰问时间" :value="viewData.occurTime"></van-cell>
|
||||||
|
</template>
|
||||||
|
<van-cell title="申请事由">{{ viewData.remark || '暂无' }}</van-cell>
|
||||||
|
<van-cell class="specialcondolence-info-long-cell" title="附件">
|
||||||
|
<file-preview class="specialcondolence-attachments" :files="viewData.files" complete_result></file-preview>
|
||||||
|
</van-cell>
|
||||||
|
<van-cell class="specialcondolence-info-long-cell" title="签字">
|
||||||
|
<van-image
|
||||||
|
v-if="viewData.signature"
|
||||||
|
:src="viewData.signature"
|
||||||
|
class="specialcondolence-signature-image"
|
||||||
|
fit="contain"
|
||||||
|
></van-image>
|
||||||
|
<span v-else>暂无签字</span>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="慰问对象" name="recipients">
|
||||||
|
<section class="specialcondolence-info-card">
|
||||||
|
<h2 class="specialcondolence-info-card__title">慰问对象</h2>
|
||||||
|
<van-cell-group :border="false">
|
||||||
|
<template v-for="(person, index) in viewData.recipients">
|
||||||
|
<van-cell :title="'慰问对象 ' + (index + 1)" :title-style="{ fontWeight: 'bold' }" :value="person.helpUserName"></van-cell>
|
||||||
|
<van-cell title="工号" :value="person.helpLoginName || '--'"></van-cell>
|
||||||
|
<van-cell title="身份证号码" :value="person.idCard"></van-cell>
|
||||||
|
<van-cell title="开户行" :value="person.bankOfDeposit"></van-cell>
|
||||||
|
<van-cell title="户名" :value="person.bankUserName"></van-cell>
|
||||||
|
<van-cell title="收款账户" :value="person.bankCardNumber"></van-cell>
|
||||||
|
</template>
|
||||||
|
<template v-if="!viewData.recipients || !viewData.recipients.length">
|
||||||
|
<van-cell title="慰问对象">{{ viewData.helpUserName || '--' }}</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 title="开户行">
|
||||||
|
{{ viewData.bankOfDeposit || '暂无' }}
|
||||||
|
</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>
|
||||||
|
</template>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
</van-tab>
|
||||||
|
<van-tab title="审核记录" name="records">
|
||||||
|
<van-empty v-if="!doneTasks.length" description="暂无审核记录"></van-empty>
|
||||||
|
<section
|
||||||
|
v-for="(task, index) in doneTasks"
|
||||||
|
:key="task.id || index"
|
||||||
|
class="specialcondolence-info-card"
|
||||||
|
>
|
||||||
|
<h2 class="specialcondolence-info-card__title">{{ task.displayName || '办理记录' }}</h2>
|
||||||
|
<van-cell-group :border="false" v-if="task.ext && task.ext.isFirstTaskNode">
|
||||||
|
<van-cell title="申请用户">
|
||||||
|
{{ task.ext.initiatorName || '--' }}({{ task.ext.initiatorAccount || '--' }})
|
||||||
|
</van-cell>
|
||||||
|
<van-cell title="申请时间">{{ task.finishTime || '--' }}</van-cell>
|
||||||
|
<van-cell title="办理结果">
|
||||||
|
<dict-tag
|
||||||
|
:options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
|
||||||
|
:value="task.ext.submitType"
|
||||||
|
></dict-tag>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
<van-cell-group :border="false" v-else>
|
||||||
|
<van-cell title="办理用户">
|
||||||
|
{{ task.taskFormData && task.taskFormData.userName || '--' }}({{ task.taskFormData && task.taskFormData.loginName || '--' }})
|
||||||
|
</van-cell>
|
||||||
|
<van-cell title="办理时间">{{ task.finishTime || '--' }}</van-cell>
|
||||||
|
<van-cell title="办理结果">
|
||||||
|
<dict-tag
|
||||||
|
:options="dict.type.PROCESS_TASK_SUBMIT_TYPE"
|
||||||
|
:value="task.ext && task.ext.submitType"
|
||||||
|
></dict-tag>
|
||||||
|
</van-cell>
|
||||||
|
<van-cell v-if="task.taskFormData && task.taskFormData.sign" title="审批签字">
|
||||||
|
<img :src="task.taskFormData.sign" class="specialcondolence-approval-signature-image">
|
||||||
|
</van-cell>
|
||||||
|
<van-cell title="办理意见">
|
||||||
|
<div class="specialcondolence-info-opinion" v-html="task.taskFormData && task.taskFormData.tf_opinion || '暂无'"></div>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell-group>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</van-tab>
|
||||||
|
</van-tabs>
|
||||||
|
<slot></slot>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
|
`,
|
||||||
|
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
|
||||||
|
props: {
|
||||||
|
pageKey: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeInfoTab: 'form',
|
||||||
|
visible: false,
|
||||||
|
popupTitle: "慰问详情",
|
||||||
|
viewData: {},
|
||||||
|
doneTasks: [],
|
||||||
|
row: null,
|
||||||
|
historyLayerUnsubscribe: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 浏览器历史变化时,只同步当前慰问详情弹框的显示状态。
|
||||||
|
syncHistoryLayerStack(stack) {
|
||||||
|
this.$set(this, "visible", stack.includes("specialcondolence-detail"))
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开慰问详情或审核弹框。
|
||||||
|
* row 传列表当前行,title 传顶部导航标题;无返回值。
|
||||||
|
*/
|
||||||
|
onOpen(row, title = "慰问详情") {
|
||||||
|
this.activeInfoTab = 'form'
|
||||||
|
this.$set(this, "row", row)
|
||||||
|
this.$set(this, "popupTitle", title)
|
||||||
|
this.$set(this, "viewData", {})
|
||||||
|
this.$set(this, "doneTasks", [])
|
||||||
|
this.getInfo()
|
||||||
|
this.getDoneTasks()
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-detail")) return
|
||||||
|
this.$set(this, "visible", true)
|
||||||
|
},
|
||||||
|
|
||||||
|
// 顶部返回按钮与业务主动关闭统一回退弹框对应的浏览器历史。
|
||||||
|
onClose(afterClose = null) {
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("specialcondolence-detail", afterClose)) return
|
||||||
|
this.$set(this, "visible", false)
|
||||||
|
if (typeof afterClose === "function") afterClose()
|
||||||
|
},
|
||||||
|
|
||||||
|
getInfo() {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/info", {id: this.row.id}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$set(this, "viewData", res.data || {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getDoneTasks() {
|
||||||
|
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$set(this, "doneTasks", res.data || [])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!window.h5HistoryLayerManager) return
|
||||||
|
window.h5HistoryLayerManager.ensureRegistered(this.pageKey)
|
||||||
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
|
this.syncHistoryLayerStack(stack)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (typeof this.historyLayerUnsubscribe === "function") this.historyLayerUnsubscribe()
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.pageKey === this.pageKey) {
|
||||||
|
window.h5HistoryLayerManager.unregister(this.pageKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+371
@@ -0,0 +1,371 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app { --color-primary: #1989fa; }
|
||||||
|
.specialcondolence-list-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar, .specialcondolence-list-page .van-sticky--fixed { background: #fff; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar .van-icon, .specialcondolence-list-page .van-nav-bar__text { color: #1989fa; }
|
||||||
|
.specialcondolence-list-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||||
|
.specialcondolence-list-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||||
|
.specialcondolence-list-search .van-field__control { color: #263548; font-size: 14px; }
|
||||||
|
.specialcondolence-list-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||||
|
.specialcondolence-list-filter { margin-bottom: 8px; overflow: hidden; border-radius: 10px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__bar { height: 44px; box-shadow: none; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item, .specialcondolence-list-filter .van-dropdown-menu__title { height: 44px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item { align-items: center; justify-content: center; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title { display: inline-flex; align-items: center; line-height: 20px; color: #66758a; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title--active, .specialcondolence-list-filter .van-dropdown-item__option--active, .specialcondolence-list-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__content { width: calc(100% - 24px); margin: 0 12px; overflow: hidden; box-sizing: border-box; border-radius: 0 0 12px 12px; box-shadow: 0 10px 24px rgba(31, 65, 108, .14); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option { display: flex; min-height: 48px; padding: 0 16px; align-items: center; color: #46566c; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option .van-cell__title { display: flex; min-height: 20px; align-items: center; line-height: 20px; }
|
||||||
|
.specialcondolence-list-content { padding: 0 12px; }
|
||||||
|
.specialcondolence-list-skeleton { padding-top: 2px; }
|
||||||
|
.specialcondolence-list-skeleton__card { margin-bottom: 12px; padding: 18px 14px 14px; border: 1px solid #e9eff7; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton { padding: 0; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__title { width: 42%; height: 18px; margin-bottom: 18px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row { height: 14px; margin-top: 12px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:nth-child(2n) { width: 72% !important; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:last-child { width: 34% !important; margin-top: 18px; margin-left: auto; }
|
||||||
|
.specialcondolence-list-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||||
|
.specialcondolence-card-heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||||
|
.specialcondolence-card-title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.specialcondolence-card-code { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-card-status { display: inline-flex; flex: none; }
|
||||||
|
.specialcondolence-card-status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn i { margin-right: 5px; font-size: 13px; }
|
||||||
|
.specialcondolence-list-page .empty-state { padding: 0; }
|
||||||
|
.specialcondolence-list-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||||
|
.specialcondolence-list-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||||
|
.specialcondolence-list-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||||
|
.specialcondolence-list-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style id="style-specialcondolence-info-h5">
|
||||||
|
<!--#include("../common/info.css"){}#-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<div class="specialcondolence-list-page">
|
||||||
|
<van-nav-bar title="分管校领导审批" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||||
|
|
||||||
|
<van-sticky offset-top="46px">
|
||||||
|
<div class="specialcondolence-list-sticky">
|
||||||
|
<van-search
|
||||||
|
v-model="pageForm.searchKeyword"
|
||||||
|
class="specialcondolence-list-search"
|
||||||
|
placeholder="请输入姓名或者工号搜索"
|
||||||
|
shape="round"
|
||||||
|
clearable
|
||||||
|
@search="doSearch"
|
||||||
|
@clear="doSearch"
|
||||||
|
></van-search>
|
||||||
|
<van-dropdown-menu class="specialcondolence-list-filter" :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||||
|
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false"
|
||||||
|
@change="doSearch"></van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.approvalText" :options="approvalOptions" :multiple="false"
|
||||||
|
@change="onApprovalFilterChange"></van-dropdown-item>
|
||||||
|
</van-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</van-sticky>
|
||||||
|
|
||||||
|
<main class="specialcondolence-list-content">
|
||||||
|
<div class="specialcondolence-list-skeleton" v-if="skeletonLoading">
|
||||||
|
<div class="specialcondolence-list-skeleton__card" v-for="index in 3" :key="'fourth-approval-skeleton-' + index">
|
||||||
|
<van-skeleton title :row="5" animated></van-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table-list api="/platform/special_condolence/fourthApproval/pageData" :page_form.sync="pageForm" ref="tableListRef"
|
||||||
|
v-show="!skeletonLoading" :show_loading_overlay="false" @ready="onReady"
|
||||||
|
@loading-change="handleListLoadingChange">
|
||||||
|
<template #header="{index,row}">
|
||||||
|
<div class="specialcondolence-card-header">
|
||||||
|
<div class="specialcondolence-card-heading">
|
||||||
|
<div class="specialcondolence-card-title">{{row.subject || '--'}}</div>
|
||||||
|
</div>
|
||||||
|
<enum-tag class="specialcondolence-card-status" v-if="row.instanceState" :value="row.instanceState"
|
||||||
|
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot="{index,row}">
|
||||||
|
<table-column label="申请人">{{row.applyUserName}}</table-column>
|
||||||
|
<table-column label="所属工会">{{row.applyUnionName}}</table-column>
|
||||||
|
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||||
|
<table-column label="慰问类型">{{row.typeName}}</table-column>
|
||||||
|
<table-column label="慰问人数">{{row.recipientCount}} 人</table-column>
|
||||||
|
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||||
|
</template>
|
||||||
|
<template #actions="{index,row}">
|
||||||
|
<div class="action-btn" @click="onView(row)">
|
||||||
|
<van-icon name="eye-o"></van-icon>
|
||||||
|
<span>查看</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||||
|
<van-icon name="edit"></van-icon>
|
||||||
|
<span>审核</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||||
|
<van-icon name="revoke"></van-icon>
|
||||||
|
<span>撤回</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="specialcondolence-list-empty">
|
||||||
|
<img src="/assets/mobile/img/condolence/condolence-empty.png" alt="暂无慰问审核记录插画">
|
||||||
|
<div class="specialcondolence-list-empty__title">暂无慰问审核记录</div>
|
||||||
|
<div class="specialcondolence-list-empty__hint">当前筛选条件下暂时没有慰问申请</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</table-list>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<info ref="infoRef" page-key="specialcondolence-fourth-detail">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<section class="specialcondolence-info-card">
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批意见<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-form ref="formRef" :show-error="true" :show-error-message="true">
|
||||||
|
<van-field
|
||||||
|
v-model="formData.tf_opinion"
|
||||||
|
class="specialcondolence-audit-field"
|
||||||
|
name="tf_opinion"
|
||||||
|
type="textarea"
|
||||||
|
rows="6"
|
||||||
|
placeholder="请输入审批意见"
|
||||||
|
:rules="[{ validator: value => !!String(value || '').trim(), message: '请填写审批意见' }]"
|
||||||
|
maxlength="100"
|
||||||
|
show-word-limit
|
||||||
|
></van-field>
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批签字<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
|
</van-field>
|
||||||
|
</van-form>
|
||||||
|
</section>
|
||||||
|
<div class="specialcondolence-popup-actions">
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||||
|
<van-button class="specialcondolence-action-primary" type="primary" block :loading="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</info>
|
||||||
|
<van-dialog
|
||||||
|
:value="confirmVisible"
|
||||||
|
title="提示"
|
||||||
|
:message="confirmActionType === 'revoke' ? '您确定要撤回吗?' : '您确定要提交吗?'"
|
||||||
|
show-cancel-button
|
||||||
|
confirm-button-color="#1989fa"
|
||||||
|
@confirm="confirmPendingAction"
|
||||||
|
@cancel="closeActionConfirm"
|
||||||
|
></van-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
components: {
|
||||||
|
info: specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
searchKeyword: '',
|
||||||
|
approvalText: "0",
|
||||||
|
approval: false,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
type: null,
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
approvalOptions: [
|
||||||
|
{text: "未审核", value: "0"},
|
||||||
|
{text: "已审核", value: "1"}
|
||||||
|
],
|
||||||
|
skeletonLoading: true,
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false,
|
||||||
|
formLoading: false,
|
||||||
|
confirmVisible: false,
|
||||||
|
confirmActionType: "task",
|
||||||
|
pendingSubmitType: null,
|
||||||
|
pendingRevokeRow: null,
|
||||||
|
historyLayerUnsubscribe: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// state.initial 表示当前查询前列表为空,仅此阶段使用整组卡片骨架屏。
|
||||||
|
handleListLoadingChange(state) {
|
||||||
|
if (state.initial) this.$set(this, "skeletonLoading", state.loading)
|
||||||
|
},
|
||||||
|
// 审核状态下拉值为字符串,接口参数 approval 继续使用布尔值。
|
||||||
|
onApprovalFilterChange(val) {
|
||||||
|
this.$set(this.pageForm, "approval", val === "1")
|
||||||
|
this.doSearch()
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
this.openTodoTask()
|
||||||
|
},
|
||||||
|
openTodoTask() {
|
||||||
|
const taskId = GetQueryString("taskId")
|
||||||
|
const bizId = GetQueryString("bizId")
|
||||||
|
if (!taskId || !bizId) return
|
||||||
|
this.$axios.post("/flow/common/taskInfo", {taskId}).then((res) => {
|
||||||
|
if (res.code !== 0 || !res.data) return
|
||||||
|
const task = res.data
|
||||||
|
if (task.taskName !== "af363a4e-fc56-42a0-9906-8c7a2814006b") return
|
||||||
|
const row = {id: bizId, taskId: task.id, curTaskName: task.displayName}
|
||||||
|
if (task.taskState === 10 && task.executable && GetQueryString("tab") === "todo") {
|
||||||
|
this.onApproval(row)
|
||||||
|
} else {
|
||||||
|
this.onView(row)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$set(this, "showApprovalForm", false)
|
||||||
|
this.$refs.infoRef.onOpen(row, "慰问详情")
|
||||||
|
},
|
||||||
|
onApproval(row) {
|
||||||
|
this.$set(this, "showApprovalForm", true)
|
||||||
|
this.$set(this, "formData", {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
})
|
||||||
|
this.$refs.infoRef.onOpen(row, row.curTaskName || "慰问审核")
|
||||||
|
},
|
||||||
|
// val 为流程提交类型:1 同意、20 不同意、6 退回;校验通过后打开历史栈确认框。
|
||||||
|
handleTaskAction(val) {
|
||||||
|
this.$refs.formRef.validate()
|
||||||
|
.then(() => {
|
||||||
|
this.$set(this, "confirmActionType", "task")
|
||||||
|
this.$set(this, "pendingSubmitType", val)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
})
|
||||||
|
.catch(errors => {
|
||||||
|
if (!Array.isArray(errors) || !errors.length) return
|
||||||
|
this.$toast(errors[0].message || '请完善审批信息')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.formRef.scrollToField(errors[0].name)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 确认操作时先回退确认框历史,再根据操作类型调用办理或撤回接口。
|
||||||
|
confirmPendingAction() {
|
||||||
|
this.closeActionConfirm(() => {
|
||||||
|
if (this.confirmActionType === "revoke") {
|
||||||
|
this.revokeTask()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.submitTaskAction()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 提交 processTaskId、taskName、tf_opinion、tf_sign 和 submitType,接口返回统一响应对象。
|
||||||
|
submitTaskAction() {
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: this.pendingSubmitType
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
const afterClose = () => {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.closeAll(afterClose)) return
|
||||||
|
this.$refs.infoRef.onClose(afterClose)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
closeActionConfirm(afterClose = null) {
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("specialcondolence-action-confirm", afterClose)) return
|
||||||
|
this.$set(this, "confirmVisible", false)
|
||||||
|
if (typeof afterClose === "function") afterClose()
|
||||||
|
},
|
||||||
|
// row 提供待撤回任务 taskId,确认后保存当前行并由统一确认框执行撤回。
|
||||||
|
onRevoke(row){
|
||||||
|
this.$set(this, "confirmActionType", "revoke")
|
||||||
|
this.$set(this, "pendingRevokeRow", row)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
},
|
||||||
|
// 使用 pendingRevokeRow.taskId 撤回任务,接口返回统一响应对象。
|
||||||
|
revokeTask() {
|
||||||
|
if (!this.pendingRevokeRow) return
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: this.pendingRevokeRow.taskId})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType', {}, {h5SkeletonLoading: true})
|
||||||
|
.then((res) => {
|
||||||
|
const typeList = res.data || []
|
||||||
|
this.$set(this, "typeOptions", [
|
||||||
|
{
|
||||||
|
text: "全部慰问类型",
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
].concat(typeList.map((v) => ({ text: v.name, value: v.id }))))
|
||||||
|
if (this.typeOptions.length > 0) {
|
||||||
|
this.$set(this.pageForm, "type", this.typeOptions[0].value)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doSearch() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.pageForm.pageNumber = 1
|
||||||
|
this.pageForm.totalCount = 0
|
||||||
|
this.$refs.tableListRef.doSearch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!window.h5HistoryLayerManager) return
|
||||||
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
|
this.$set(this, "confirmVisible", stack.includes("specialcondolence-action-confirm"))
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (typeof this.historyLayerUnsubscribe === "function") this.historyLayerUnsubscribe()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+473
@@ -0,0 +1,473 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app {
|
||||||
|
--color-primary: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #f3f7fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .van-nav-bar,
|
||||||
|
.specialcondolence-list-page .van-sticky--fixed {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .van-nav-bar__title {
|
||||||
|
color: #172033;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .van-nav-bar .van-icon,
|
||||||
|
.specialcondolence-list-page .van-nav-bar__text {
|
||||||
|
color: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-sticky {
|
||||||
|
padding: 22px 12px 1px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #f3f7fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-search {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-search .van-search__content {
|
||||||
|
height: 42px;
|
||||||
|
padding-left: 12px;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-search .van-field__control {
|
||||||
|
color: #263548;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-search .van-field__control::placeholder {
|
||||||
|
color: #a7b0bf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__bar {
|
||||||
|
height: 44px;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item,
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title {
|
||||||
|
height: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item {
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 20px;
|
||||||
|
color: #66758a;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title--active,
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option--active,
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||||
|
color: #1989fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__content {
|
||||||
|
width: calc(100% - 24px);
|
||||||
|
margin: 0 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 0 0 12px 12px;
|
||||||
|
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option {
|
||||||
|
display: flex;
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 0 16px;
|
||||||
|
align-items: center;
|
||||||
|
color: #46566c;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option .van-cell__title {
|
||||||
|
display: flex;
|
||||||
|
min-height: 20px;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-content {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton {
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 18px 14px 14px;
|
||||||
|
border: 1px solid #e9eff7;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__title {
|
||||||
|
width: 42%;
|
||||||
|
height: 18px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row {
|
||||||
|
height: 14px;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:nth-child(2n) {
|
||||||
|
width: 72% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:last-child {
|
||||||
|
width: 34% !important;
|
||||||
|
margin-top: 18px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid #e9eff7;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-header {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-heading {
|
||||||
|
min-width: 0;
|
||||||
|
padding-right: 10px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-title {
|
||||||
|
overflow: hidden;
|
||||||
|
color: #253247;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 22px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-code {
|
||||||
|
margin-top: 1px;
|
||||||
|
color: #9ba6b6;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-status {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-card-status .van-tag {
|
||||||
|
min-height: 24px;
|
||||||
|
padding: 3px 9px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .item-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top-color: #edf1f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn {
|
||||||
|
min-height: 28px;
|
||||||
|
padding: 4px 11px;
|
||||||
|
border-radius: 14px;
|
||||||
|
color: #1989fa;
|
||||||
|
background: #eaf4ff;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn.delete {
|
||||||
|
color: #f04444;
|
||||||
|
background: #fff0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn i {
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-page .empty-state {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-empty {
|
||||||
|
display: flex;
|
||||||
|
min-height: 280px;
|
||||||
|
padding: 46px 18px 36px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-empty img {
|
||||||
|
display: block;
|
||||||
|
width: 86%;
|
||||||
|
max-width: 290px;
|
||||||
|
height: auto;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-empty__title {
|
||||||
|
margin-top: 14px;
|
||||||
|
color: #50627a;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.specialcondolence-list-empty__hint {
|
||||||
|
margin-top: 5px;
|
||||||
|
color: #9aa7b8;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style id="style-specialcondolence-info-h5">
|
||||||
|
<!--#include("../common/info.css"){}#-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<div class="specialcondolence-list-page">
|
||||||
|
<van-nav-bar title="我的申请" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||||
|
|
||||||
|
<van-sticky offset-top="46px">
|
||||||
|
<div class="specialcondolence-list-sticky">
|
||||||
|
<van-search
|
||||||
|
v-model="pageForm.searchKeyword"
|
||||||
|
class="specialcondolence-list-search"
|
||||||
|
placeholder="请输入姓名或者工号搜索"
|
||||||
|
shape="round"
|
||||||
|
clearable
|
||||||
|
@search="doSearch"
|
||||||
|
@clear="doSearch"
|
||||||
|
></van-search>
|
||||||
|
<van-dropdown-menu class="specialcondolence-list-filter" :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||||
|
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false"
|
||||||
|
@change="doSearch"></van-dropdown-item>
|
||||||
|
</van-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</van-sticky>
|
||||||
|
|
||||||
|
<main class="specialcondolence-list-content">
|
||||||
|
<div class="specialcondolence-list-skeleton" v-if="skeletonLoading">
|
||||||
|
<div class="specialcondolence-list-skeleton__card" v-for="index in 3" :key="'mine-skeleton-' + index">
|
||||||
|
<van-skeleton title :row="5" animated></van-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table-list api="/platform/special_condolence/mine/pageData" :page_form.sync="pageForm" ref="tableListRef"
|
||||||
|
v-show="!skeletonLoading" :show_loading_overlay="false" @ready="onReady"
|
||||||
|
@loading-change="handleListLoadingChange">
|
||||||
|
<template #header="{index,row}">
|
||||||
|
<div class="specialcondolence-card-header">
|
||||||
|
<div class="specialcondolence-card-heading">
|
||||||
|
<div class="specialcondolence-card-title">{{row.subject || '--'}}</div>
|
||||||
|
</div>
|
||||||
|
<enum-tag class="specialcondolence-card-status" v-if="row.instanceState" :value="row.instanceState"
|
||||||
|
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot="{index,row}">
|
||||||
|
<table-column label="申请人">{{row.applyUserName}}</table-column>
|
||||||
|
<table-column label="所属工会">{{row.applyUnionName}}</table-column>
|
||||||
|
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||||
|
<table-column label="慰问类型">{{row.typeName}}</table-column>
|
||||||
|
<table-column label="慰问人数">{{row.recipientCount}} 人</table-column>
|
||||||
|
<table-column label="当前节点">{{row.taskName}}</table-column>
|
||||||
|
</template>
|
||||||
|
<template #actions="{index,row}">
|
||||||
|
<div class="action-btn" @click="onView(row)">
|
||||||
|
<van-icon name="eye-o"></van-icon>
|
||||||
|
<span>查看</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn" @click="onEdit(row)"
|
||||||
|
v-if="row.taskKey === 'startTask' || !row.instanceId">
|
||||||
|
<van-icon name="edit"></van-icon>
|
||||||
|
<span>编辑</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn delete" @click="onRevoke(row)"
|
||||||
|
v-if="row.canRevoke">
|
||||||
|
<van-icon name="revoke"></van-icon>
|
||||||
|
<span>撤回</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn delete" @click="onDelete(row)"
|
||||||
|
v-if="row.taskKey === 'startTask' || !row.instanceId">
|
||||||
|
<van-icon name="delete-o"></van-icon>
|
||||||
|
<span>删除</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="specialcondolence-list-empty">
|
||||||
|
<img src="/assets/mobile/img/condolence/condolence-empty.png" alt="暂无慰问申请记录插画">
|
||||||
|
<div class="specialcondolence-list-empty__title">暂无慰问申请记录</div>
|
||||||
|
<div class="specialcondolence-list-empty__hint">当前筛选条件下暂时没有慰问申请</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</table-list>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<info ref="infoRef" page-key="specialcondolence-mine-detail"></info>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
components: {
|
||||||
|
info: specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
type: null
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
skeletonLoading: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// state.initial 表示当前查询前列表为空,仅此阶段使用整组卡片骨架屏。
|
||||||
|
handleListLoadingChange(state) {
|
||||||
|
if (state.initial) this.$set(this, "skeletonLoading", state.loading)
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
.then((typeList) => {
|
||||||
|
this.$set(this, "typeOptions", [
|
||||||
|
{
|
||||||
|
text: "全部慰问类型",
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
].concat(typeList.map((v) => ({ text: v.name, value: v.id }))))
|
||||||
|
if (this.typeOptions.length > 0) {
|
||||||
|
this.$set(this.pageForm, "type", this.typeOptions[0].value)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRevoke(row) {
|
||||||
|
this.$dialog.confirm({
|
||||||
|
title: "提示",
|
||||||
|
message: "您确定要撤回吗?"
|
||||||
|
}).then(() => {
|
||||||
|
this.$axios.post("/flow/common/revokeTask", { taskId: row.startTaskId }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$refs.infoRef.onOpen(row, "慰问详情")
|
||||||
|
},
|
||||||
|
onEdit(row) {
|
||||||
|
this.$pjaxReplace("/platform/special_condolence/apply/h5?taskId=" + (row.startTaskId || "") + "&bizId=" + row.id)
|
||||||
|
},
|
||||||
|
onDelete(row) {
|
||||||
|
this.$dialog.confirm({
|
||||||
|
title: "提示",
|
||||||
|
message: "您确定要删除吗?"
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$axios.post("/platform/special_condolence/mine/delete", { id: row.id }).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
} else {
|
||||||
|
this.$toast.fail(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
return this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType', {}, {h5SkeletonLoading: true})
|
||||||
|
.then((res) => res.data || [])
|
||||||
|
},
|
||||||
|
doSearch() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.pageForm.pageNumber = 1
|
||||||
|
this.pageForm.totalCount = 0
|
||||||
|
this.$refs.tableListRef.doSearch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+354
@@ -0,0 +1,354 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app { --color-primary: #1989fa; }
|
||||||
|
.specialcondolence-list-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar, .specialcondolence-list-page .van-sticky--fixed { background: #fff; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar .van-icon, .specialcondolence-list-page .van-nav-bar__text { color: #1989fa; }
|
||||||
|
.specialcondolence-list-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||||
|
.specialcondolence-list-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||||
|
.specialcondolence-list-search .van-field__control { color: #263548; font-size: 14px; }
|
||||||
|
.specialcondolence-list-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||||
|
.specialcondolence-list-filter { margin-bottom: 8px; overflow: hidden; border-radius: 10px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__bar { height: 44px; box-shadow: none; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item, .specialcondolence-list-filter .van-dropdown-menu__title { height: 44px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item { align-items: center; justify-content: center; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title { display: inline-flex; align-items: center; line-height: 20px; color: #66758a; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title--active, .specialcondolence-list-filter .van-dropdown-item__option--active, .specialcondolence-list-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__content { width: calc(100% - 24px); margin: 0 12px; overflow: hidden; box-sizing: border-box; border-radius: 0 0 12px 12px; box-shadow: 0 10px 24px rgba(31, 65, 108, .14); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option { display: flex; min-height: 48px; padding: 0 16px; align-items: center; color: #46566c; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option .van-cell__title { display: flex; min-height: 20px; align-items: center; line-height: 20px; }
|
||||||
|
.specialcondolence-list-content { padding: 0 12px; }
|
||||||
|
.specialcondolence-list-skeleton { padding-top: 2px; }
|
||||||
|
.specialcondolence-list-skeleton__card { margin-bottom: 12px; padding: 18px 14px 14px; border: 1px solid #e9eff7; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton { padding: 0; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__title { width: 42%; height: 18px; margin-bottom: 18px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row { height: 14px; margin-top: 12px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:nth-child(2n) { width: 72% !important; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:last-child { width: 34% !important; margin-top: 18px; margin-left: auto; }
|
||||||
|
.specialcondolence-list-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||||
|
.specialcondolence-card-heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||||
|
.specialcondolence-card-title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.specialcondolence-card-code { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-card-status { display: inline-flex; flex: none; }
|
||||||
|
.specialcondolence-card-status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn i { margin-right: 5px; font-size: 13px; }
|
||||||
|
.specialcondolence-list-page .empty-state { padding: 0; }
|
||||||
|
.specialcondolence-list-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||||
|
.specialcondolence-list-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||||
|
.specialcondolence-list-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||||
|
.specialcondolence-list-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style id="style-specialcondolence-info-h5">
|
||||||
|
<!--#include("../common/info.css"){}#-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<div class="specialcondolence-list-page">
|
||||||
|
<van-nav-bar title="校工会办公室主任审批" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||||
|
|
||||||
|
<van-sticky offset-top="46px">
|
||||||
|
<div class="specialcondolence-list-sticky">
|
||||||
|
<van-search
|
||||||
|
v-model="pageForm.searchKeyword"
|
||||||
|
class="specialcondolence-list-search"
|
||||||
|
placeholder="请输入姓名或者工号搜索"
|
||||||
|
shape="round"
|
||||||
|
clearable
|
||||||
|
@search="doSearch"
|
||||||
|
@clear="doSearch"
|
||||||
|
></van-search>
|
||||||
|
<van-dropdown-menu class="specialcondolence-list-filter" :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||||
|
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false"
|
||||||
|
@change="doSearch"></van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.approvalText" :options="approvalOptions" :multiple="false"
|
||||||
|
@change="onApprovalFilterChange"></van-dropdown-item>
|
||||||
|
</van-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</van-sticky>
|
||||||
|
|
||||||
|
<main class="specialcondolence-list-content">
|
||||||
|
<div class="specialcondolence-list-skeleton" v-if="skeletonLoading">
|
||||||
|
<div class="specialcondolence-list-skeleton__card" v-for="index in 3" :key="'school-principal-approval-skeleton-' + index">
|
||||||
|
<van-skeleton title :row="5" animated></van-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table-list api="/platform/special_condolence/schoolPrincipalApproval/pageData" :page_form.sync="pageForm" ref="tableListRef"
|
||||||
|
v-show="!skeletonLoading" :show_loading_overlay="false" @ready="onReady"
|
||||||
|
@loading-change="handleListLoadingChange">
|
||||||
|
<template #header="{index,row}">
|
||||||
|
<div class="specialcondolence-card-header">
|
||||||
|
<div class="specialcondolence-card-heading">
|
||||||
|
<div class="specialcondolence-card-title">{{row.subject || '--'}}</div>
|
||||||
|
</div>
|
||||||
|
<enum-tag class="specialcondolence-card-status" v-if="row.instanceState" :value="row.instanceState"
|
||||||
|
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot="{index,row}">
|
||||||
|
<table-column label="申请人">{{row.applyUserName}}</table-column>
|
||||||
|
<table-column label="所属工会">{{row.applyUnionName}}</table-column>
|
||||||
|
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||||
|
<table-column label="慰问类型">{{row.typeName}}</table-column>
|
||||||
|
<table-column label="慰问人数">{{row.recipientCount}} 人</table-column>
|
||||||
|
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||||
|
</template>
|
||||||
|
<template #actions="{index,row}">
|
||||||
|
<div class="action-btn" @click="onView(row)">
|
||||||
|
<van-icon name="eye-o"></van-icon>
|
||||||
|
<span>查看</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||||
|
<van-icon name="edit"></van-icon>
|
||||||
|
<span>审核</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||||
|
<van-icon name="revoke"></van-icon>
|
||||||
|
<span>撤回</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="specialcondolence-list-empty">
|
||||||
|
<img src="/assets/mobile/img/condolence/condolence-empty.png" alt="暂无慰问审核记录插画">
|
||||||
|
<div class="specialcondolence-list-empty__title">暂无慰问审核记录</div>
|
||||||
|
<div class="specialcondolence-list-empty__hint">当前筛选条件下暂时没有慰问申请</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</table-list>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<info ref="infoRef" page-key="specialcondolence-school-principal-detail">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<section class="specialcondolence-info-card">
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批意见<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-form ref="formRef" :show-error="true" :show-error-message="true">
|
||||||
|
<van-field
|
||||||
|
v-model="formData.tf_opinion"
|
||||||
|
class="specialcondolence-audit-field"
|
||||||
|
name="tf_opinion"
|
||||||
|
type="textarea"
|
||||||
|
rows="6"
|
||||||
|
placeholder="请输入审批意见"
|
||||||
|
:rules="[{ validator: value => !!String(value || '').trim(), message: '请填写审批意见' }]"
|
||||||
|
maxlength="100"
|
||||||
|
show-word-limit
|
||||||
|
></van-field>
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批签字<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
|
</van-field>
|
||||||
|
</van-form>
|
||||||
|
</section>
|
||||||
|
<div class="specialcondolence-popup-actions">
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||||
|
<van-button class="specialcondolence-action-primary" type="primary" block :loading="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</info>
|
||||||
|
<van-dialog
|
||||||
|
:value="confirmVisible"
|
||||||
|
title="提示"
|
||||||
|
:message="confirmActionType === 'revoke' ? '您确定要撤回吗?' : '您确定要提交吗?'"
|
||||||
|
show-cancel-button
|
||||||
|
confirm-button-color="#1989fa"
|
||||||
|
@confirm="confirmPendingAction"
|
||||||
|
@cancel="closeActionConfirm"
|
||||||
|
></van-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
components: {
|
||||||
|
info: specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
searchKeyword: '',
|
||||||
|
approvalText: "0",
|
||||||
|
approval: false,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
type: null,
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
approvalOptions: [
|
||||||
|
{text: "未审核", value: "0"},
|
||||||
|
{text: "已审核", value: "1"}
|
||||||
|
],
|
||||||
|
skeletonLoading: true,
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false,
|
||||||
|
formLoading: false,
|
||||||
|
confirmVisible: false,
|
||||||
|
confirmActionType: "task",
|
||||||
|
pendingSubmitType: null,
|
||||||
|
pendingRevokeRow: null,
|
||||||
|
historyLayerUnsubscribe: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// state.initial 表示当前查询前列表为空,仅此阶段使用整组卡片骨架屏。
|
||||||
|
handleListLoadingChange(state) {
|
||||||
|
if (state.initial) this.$set(this, "skeletonLoading", state.loading)
|
||||||
|
},
|
||||||
|
// 审核状态下拉值为字符串,接口参数 approval 继续使用布尔值。
|
||||||
|
onApprovalFilterChange(val) {
|
||||||
|
this.$set(this.pageForm, "approval", val === "1")
|
||||||
|
this.doSearch()
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$set(this, "showApprovalForm", false)
|
||||||
|
this.$refs.infoRef.onOpen(row, "慰问详情")
|
||||||
|
},
|
||||||
|
onApproval(row) {
|
||||||
|
this.$set(this, "showApprovalForm", true)
|
||||||
|
this.$set(this, "formData", {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
})
|
||||||
|
this.$refs.infoRef.onOpen(row, row.curTaskName || "慰问审核")
|
||||||
|
},
|
||||||
|
// val 为流程提交类型:1 同意、20 不同意、6 退回;校验通过后打开历史栈确认框。
|
||||||
|
handleTaskAction(val) {
|
||||||
|
this.$refs.formRef.validate()
|
||||||
|
.then(() => {
|
||||||
|
this.$set(this, "confirmActionType", "task")
|
||||||
|
this.$set(this, "pendingSubmitType", val)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
})
|
||||||
|
.catch(errors => {
|
||||||
|
if (!Array.isArray(errors) || !errors.length) return
|
||||||
|
this.$toast(errors[0].message || '请完善审批信息')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.formRef.scrollToField(errors[0].name)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 确认操作时先回退确认框历史,再根据操作类型调用办理或撤回接口。
|
||||||
|
confirmPendingAction() {
|
||||||
|
this.closeActionConfirm(() => {
|
||||||
|
if (this.confirmActionType === "revoke") {
|
||||||
|
this.revokeTask()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.submitTaskAction()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 提交 processTaskId、taskName、tf_opinion、tf_sign 和 submitType,接口返回统一响应对象。
|
||||||
|
submitTaskAction() {
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: this.pendingSubmitType
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
const afterClose = () => {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.closeAll(afterClose)) return
|
||||||
|
this.$refs.infoRef.onClose(afterClose)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
closeActionConfirm(afterClose = null) {
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("specialcondolence-action-confirm", afterClose)) return
|
||||||
|
this.$set(this, "confirmVisible", false)
|
||||||
|
if (typeof afterClose === "function") afterClose()
|
||||||
|
},
|
||||||
|
// row 提供待撤回任务 taskId,确认后保存当前行并由统一确认框执行撤回。
|
||||||
|
onRevoke(row){
|
||||||
|
this.$set(this, "confirmActionType", "revoke")
|
||||||
|
this.$set(this, "pendingRevokeRow", row)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
},
|
||||||
|
// 使用 pendingRevokeRow.taskId 撤回任务,接口返回统一响应对象。
|
||||||
|
revokeTask() {
|
||||||
|
if (!this.pendingRevokeRow) return
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: this.pendingRevokeRow.taskId})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType', {}, {h5SkeletonLoading: true})
|
||||||
|
.then((res) => {
|
||||||
|
const typeList = res.data || []
|
||||||
|
this.$set(this, "typeOptions", [
|
||||||
|
{
|
||||||
|
text: "全部慰问类型",
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
].concat(typeList.map((v) => ({ text: v.name, value: v.id }))))
|
||||||
|
if (this.typeOptions.length > 0) {
|
||||||
|
this.$set(this.pageForm, "type", this.typeOptions[0].value)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doSearch() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.pageForm.pageNumber = 1
|
||||||
|
this.pageForm.totalCount = 0
|
||||||
|
this.$refs.tableListRef.doSearch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!window.h5HistoryLayerManager) return
|
||||||
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
|
this.$set(this, "confirmVisible", stack.includes("specialcondolence-action-confirm"))
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (typeof this.historyLayerUnsubscribe === "function") this.historyLayerUnsubscribe()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
+354
@@ -0,0 +1,354 @@
|
|||||||
|
<!--#
|
||||||
|
layout("/layouts/platform_h5.html"){
|
||||||
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#app { --color-primary: #1989fa; }
|
||||||
|
.specialcondolence-list-page { min-height: 100vh; padding-bottom: calc(24px + env(safe-area-inset-bottom)); box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar, .specialcondolence-list-page .van-sticky--fixed { background: #fff; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar__title { color: #172033; font-size: 16px; font-weight: 600; }
|
||||||
|
.specialcondolence-list-page .van-nav-bar .van-icon, .specialcondolence-list-page .van-nav-bar__text { color: #1989fa; }
|
||||||
|
.specialcondolence-list-sticky { padding: 22px 12px 1px; box-sizing: border-box; background: #f3f7fd; }
|
||||||
|
.specialcondolence-list-search { margin: 0 0 8px; padding: 0; overflow: hidden; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .1); }
|
||||||
|
.specialcondolence-list-search .van-search__content { height: 42px; padding-left: 12px; align-items: center; border-radius: 12px; background: #fff; }
|
||||||
|
.specialcondolence-list-search .van-field__control { color: #263548; font-size: 14px; }
|
||||||
|
.specialcondolence-list-search .van-field__control::placeholder { color: #a7b0bf; }
|
||||||
|
.specialcondolence-list-filter { margin-bottom: 8px; overflow: hidden; border-radius: 10px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__bar { height: 44px; box-shadow: none; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item, .specialcondolence-list-filter .van-dropdown-menu__title { height: 44px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__item { align-items: center; justify-content: center; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title { display: inline-flex; align-items: center; line-height: 20px; color: #66758a; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-menu__title--active, .specialcondolence-list-filter .van-dropdown-item__option--active, .specialcondolence-list-filter .van-dropdown-item__option--active .van-dropdown-item__icon { color: #1989fa; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__content { width: calc(100% - 24px); margin: 0 12px; overflow: hidden; box-sizing: border-box; border-radius: 0 0 12px 12px; box-shadow: 0 10px 24px rgba(31, 65, 108, .14); }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option { display: flex; min-height: 48px; padding: 0 16px; align-items: center; color: #46566c; font-size: 14px; }
|
||||||
|
.specialcondolence-list-filter .van-dropdown-item__option .van-cell__title { display: flex; min-height: 20px; align-items: center; line-height: 20px; }
|
||||||
|
.specialcondolence-list-content { padding: 0 12px; }
|
||||||
|
.specialcondolence-list-skeleton { padding-top: 2px; }
|
||||||
|
.specialcondolence-list-skeleton__card { margin-bottom: 12px; padding: 18px 14px 14px; border: 1px solid #e9eff7; border-radius: 12px; background: #fff; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton { padding: 0; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__title { width: 42%; height: 18px; margin-bottom: 18px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row { height: 14px; margin-top: 12px; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:nth-child(2n) { width: 72% !important; }
|
||||||
|
.specialcondolence-list-skeleton__card .van-skeleton__row:last-child { width: 34% !important; margin-top: 18px; margin-left: auto; }
|
||||||
|
.specialcondolence-list-page .table-list-container { margin-top: 0; padding-bottom: 2px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item { margin-bottom: 12px; padding: 14px; border: 1px solid #e9eff7; border-radius: 12px; box-shadow: 0 5px 16px rgba(43, 73, 112, .08); }
|
||||||
|
.specialcondolence-card-header { display: flex; margin-bottom: 8px; align-items: flex-start; justify-content: space-between; }
|
||||||
|
.specialcondolence-card-heading { min-width: 0; padding-right: 10px; flex: 1; }
|
||||||
|
.specialcondolence-card-title { overflow: hidden; color: #253247; font-size: 15px; font-weight: 600; line-height: 22px; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.specialcondolence-card-code { margin-top: 1px; color: #9ba6b6; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-card-status { display: inline-flex; flex: none; }
|
||||||
|
.specialcondolence-card-status .van-tag { min-height: 24px; padding: 3px 9px; border: 0; border-radius: 12px; box-sizing: border-box; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .item-actions { margin-top: 10px; padding-top: 10px; border-top-color: #edf1f6; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn { min-height: 28px; padding: 4px 11px; border-radius: 14px; color: #1989fa; background: #eaf4ff; font-size: 12px; line-height: 18px; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn.delete { color: #f04444; background: #fff0f0; }
|
||||||
|
.specialcondolence-list-page .table-list-container .table-list-item .action-btn i { margin-right: 5px; font-size: 13px; }
|
||||||
|
.specialcondolence-list-page .empty-state { padding: 0; }
|
||||||
|
.specialcondolence-list-empty { display: flex; min-height: 280px; padding: 46px 18px 36px; align-items: center; justify-content: center; box-sizing: border-box; flex-direction: column; text-align: center; }
|
||||||
|
.specialcondolence-list-empty img { display: block; width: 86%; max-width: 290px; height: auto; object-fit: contain; }
|
||||||
|
.specialcondolence-list-empty__title { margin-top: 14px; color: #50627a; font-size: 15px; font-weight: 600; line-height: 22px; }
|
||||||
|
.specialcondolence-list-empty__hint { margin-top: 5px; color: #9aa7b8; font-size: 12px; line-height: 18px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style id="style-specialcondolence-info-h5">
|
||||||
|
<!--#include("../common/info.css"){}#-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="app">
|
||||||
|
<div class="specialcondolence-list-page">
|
||||||
|
<van-nav-bar title="校工会主席审批" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
|
||||||
|
|
||||||
|
<van-sticky offset-top="46px">
|
||||||
|
<div class="specialcondolence-list-sticky">
|
||||||
|
<van-search
|
||||||
|
v-model="pageForm.searchKeyword"
|
||||||
|
class="specialcondolence-list-search"
|
||||||
|
placeholder="请输入姓名或者工号搜索"
|
||||||
|
shape="round"
|
||||||
|
clearable
|
||||||
|
@search="doSearch"
|
||||||
|
@clear="doSearch"
|
||||||
|
></van-search>
|
||||||
|
<van-dropdown-menu class="specialcondolence-list-filter" :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||||
|
<year-van-dropdown-item :num="5" @change="doSearch" v-model="pageForm.year"></year-van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.type" :options="typeOptions" :multiple="false"
|
||||||
|
@change="doSearch"></van-dropdown-item>
|
||||||
|
<van-dropdown-item v-model="pageForm.approvalText" :options="approvalOptions" :multiple="false"
|
||||||
|
@change="onApprovalFilterChange"></van-dropdown-item>
|
||||||
|
</van-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</van-sticky>
|
||||||
|
|
||||||
|
<main class="specialcondolence-list-content">
|
||||||
|
<div class="specialcondolence-list-skeleton" v-if="skeletonLoading">
|
||||||
|
<div class="specialcondolence-list-skeleton__card" v-for="index in 3" :key="'school-union-approval-skeleton-' + index">
|
||||||
|
<van-skeleton title :row="5" animated></van-skeleton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table-list api="/platform/special_condolence/schoolUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef"
|
||||||
|
v-show="!skeletonLoading" :show_loading_overlay="false" @ready="onReady"
|
||||||
|
@loading-change="handleListLoadingChange">
|
||||||
|
<template #header="{index,row}">
|
||||||
|
<div class="specialcondolence-card-header">
|
||||||
|
<div class="specialcondolence-card-heading">
|
||||||
|
<div class="specialcondolence-card-title">{{row.subject || '--'}}</div>
|
||||||
|
</div>
|
||||||
|
<enum-tag class="specialcondolence-card-status" v-if="row.instanceState" :value="row.instanceState"
|
||||||
|
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-slot="{index,row}">
|
||||||
|
<table-column label="申请人">{{row.applyUserName}}</table-column>
|
||||||
|
<table-column label="所属工会">{{row.applyUnionName}}</table-column>
|
||||||
|
<table-column label="所属单位">{{row.applyUnitName}}</table-column>
|
||||||
|
<table-column label="慰问类型">{{row.typeName}}</table-column>
|
||||||
|
<table-column label="慰问人数">{{row.recipientCount}} 人</table-column>
|
||||||
|
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||||
|
</template>
|
||||||
|
<template #actions="{index,row}">
|
||||||
|
<div class="action-btn" @click="onView(row)">
|
||||||
|
<van-icon name="eye-o"></van-icon>
|
||||||
|
<span>查看</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||||
|
<van-icon name="edit"></van-icon>
|
||||||
|
<span>审核</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||||
|
<van-icon name="revoke"></van-icon>
|
||||||
|
<span>撤回</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="specialcondolence-list-empty">
|
||||||
|
<img src="/assets/mobile/img/condolence/condolence-empty.png" alt="暂无慰问审核记录插画">
|
||||||
|
<div class="specialcondolence-list-empty__title">暂无慰问审核记录</div>
|
||||||
|
<div class="specialcondolence-list-empty__hint">当前筛选条件下暂时没有慰问申请</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</table-list>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<info ref="infoRef" page-key="specialcondolence-school-union-detail">
|
||||||
|
<div v-if="showApprovalForm">
|
||||||
|
<section class="specialcondolence-info-card">
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批意见<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-form ref="formRef" :show-error="true" :show-error-message="true">
|
||||||
|
<van-field
|
||||||
|
v-model="formData.tf_opinion"
|
||||||
|
class="specialcondolence-audit-field"
|
||||||
|
name="tf_opinion"
|
||||||
|
type="textarea"
|
||||||
|
rows="6"
|
||||||
|
placeholder="请输入审批意见"
|
||||||
|
:rules="[{ validator: value => !!String(value || '').trim(), message: '请填写审批意见' }]"
|
||||||
|
maxlength="100"
|
||||||
|
show-word-limit
|
||||||
|
></van-field>
|
||||||
|
<h2 class="specialcondolence-info-card__title">
|
||||||
|
审批签字<span class="specialcondolence-audit-card__required">*</span>
|
||||||
|
</h2>
|
||||||
|
<van-field name="tf_sign" :value="formData.tf_sign" :rules="[{required:true,message:'请完成审批签字'}]">
|
||||||
|
<template #input><h5-signature v-model="formData.tf_sign" :key="formData.processTaskId"></h5-signature></template>
|
||||||
|
</van-field>
|
||||||
|
</van-form>
|
||||||
|
</section>
|
||||||
|
<div class="specialcondolence-popup-actions">
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||||
|
<van-button class="specialcondolence-action-danger" type="danger" block :loading="formLoading" @click="handleTaskAction(2)">不同意</van-button>
|
||||||
|
<van-button class="specialcondolence-action-primary" type="primary" block :loading="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</info>
|
||||||
|
<van-dialog
|
||||||
|
:value="confirmVisible"
|
||||||
|
title="提示"
|
||||||
|
:message="confirmActionType === 'revoke' ? '您确定要撤回吗?' : '您确定要提交吗?'"
|
||||||
|
show-cancel-button
|
||||||
|
confirm-button-color="#1989fa"
|
||||||
|
@confirm="confirmPendingAction"
|
||||||
|
@cancel="closeActionConfirm"
|
||||||
|
></van-dialog>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script nonce="${cspNonce!}">
|
||||||
|
<!--#include('../common/info.js'){}#-->
|
||||||
|
new Vue({
|
||||||
|
el: "#app",
|
||||||
|
store,
|
||||||
|
components: {
|
||||||
|
info: specialcondolenceInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
searchKeyword: '',
|
||||||
|
approvalText: "0",
|
||||||
|
approval: false,
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
type: null,
|
||||||
|
},
|
||||||
|
typeOptions: [],
|
||||||
|
approvalOptions: [
|
||||||
|
{text: "未审核", value: "0"},
|
||||||
|
{text: "已审核", value: "1"}
|
||||||
|
],
|
||||||
|
skeletonLoading: true,
|
||||||
|
formData: {},
|
||||||
|
showApprovalForm: false,
|
||||||
|
formLoading: false,
|
||||||
|
confirmVisible: false,
|
||||||
|
confirmActionType: "task",
|
||||||
|
pendingSubmitType: null,
|
||||||
|
pendingRevokeRow: null,
|
||||||
|
historyLayerUnsubscribe: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// state.initial 表示当前查询前列表为空,仅此阶段使用整组卡片骨架屏。
|
||||||
|
handleListLoadingChange(state) {
|
||||||
|
if (state.initial) this.$set(this, "skeletonLoading", state.loading)
|
||||||
|
},
|
||||||
|
// 审核状态下拉值为字符串,接口参数 approval 继续使用布尔值。
|
||||||
|
onApprovalFilterChange(val) {
|
||||||
|
this.$set(this.pageForm, "approval", val === "1")
|
||||||
|
this.doSearch()
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.querySpecialCondolenceType()
|
||||||
|
},
|
||||||
|
onView(row) {
|
||||||
|
this.$set(this, "showApprovalForm", false)
|
||||||
|
this.$refs.infoRef.onOpen(row, "慰问详情")
|
||||||
|
},
|
||||||
|
onApproval(row) {
|
||||||
|
this.$set(this, "showApprovalForm", true)
|
||||||
|
this.$set(this, "formData", {
|
||||||
|
processTaskId: row.taskId,
|
||||||
|
taskName: row.curTaskName,
|
||||||
|
tf_sign: "",
|
||||||
|
tf_opinion: ""
|
||||||
|
})
|
||||||
|
this.$refs.infoRef.onOpen(row, row.curTaskName || "慰问审核")
|
||||||
|
},
|
||||||
|
// val 为流程提交类型:1 同意、20 不同意、6 退回;校验通过后打开历史栈确认框。
|
||||||
|
handleTaskAction(val) {
|
||||||
|
this.$refs.formRef.validate()
|
||||||
|
.then(() => {
|
||||||
|
this.$set(this, "confirmActionType", "task")
|
||||||
|
this.$set(this, "pendingSubmitType", val)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
})
|
||||||
|
.catch(errors => {
|
||||||
|
if (!Array.isArray(errors) || !errors.length) return
|
||||||
|
this.$toast(errors[0].message || '请完善审批信息')
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.formRef.scrollToField(errors[0].name)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 确认操作时先回退确认框历史,再根据操作类型调用办理或撤回接口。
|
||||||
|
confirmPendingAction() {
|
||||||
|
this.closeActionConfirm(() => {
|
||||||
|
if (this.confirmActionType === "revoke") {
|
||||||
|
this.revokeTask()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.submitTaskAction()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 提交 processTaskId、taskName、tf_opinion、tf_sign 和 submitType,接口返回统一响应对象。
|
||||||
|
submitTaskAction() {
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/platform/special_condolence/approval/executeTask", {
|
||||||
|
data: JSON.stringify({
|
||||||
|
...this.formData,
|
||||||
|
submitType: this.pendingSubmitType
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res && res.code === 0) {
|
||||||
|
const afterClose = () => {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.closeAll(afterClose)) return
|
||||||
|
this.$refs.infoRef.onClose(afterClose)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
closeActionConfirm(afterClose = null) {
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.close("specialcondolence-action-confirm", afterClose)) return
|
||||||
|
this.$set(this, "confirmVisible", false)
|
||||||
|
if (typeof afterClose === "function") afterClose()
|
||||||
|
},
|
||||||
|
// row 提供待撤回任务 taskId,确认后保存当前行并由统一确认框执行撤回。
|
||||||
|
onRevoke(row){
|
||||||
|
this.$set(this, "confirmActionType", "revoke")
|
||||||
|
this.$set(this, "pendingRevokeRow", row)
|
||||||
|
if (window.h5HistoryLayerManager && window.h5HistoryLayerManager.open("specialcondolence-action-confirm")) return
|
||||||
|
this.$set(this, "confirmVisible", true)
|
||||||
|
},
|
||||||
|
// 使用 pendingRevokeRow.taskId 撤回任务,接口返回统一响应对象。
|
||||||
|
revokeTask() {
|
||||||
|
if (!this.pendingRevokeRow) return
|
||||||
|
this.$set(this, "formLoading", true)
|
||||||
|
this.$axios.post("/flow/common/revokeTask", {taskId: this.pendingRevokeRow.taskId})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$toast.success(res.msg)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.$set(this, "formLoading", false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
querySpecialCondolenceType() {
|
||||||
|
this.$axios.post('/platform/special_condolence/type/querySpecialCondolenceType', {}, {h5SkeletonLoading: true})
|
||||||
|
.then((res) => {
|
||||||
|
const typeList = res.data || []
|
||||||
|
this.$set(this, "typeOptions", [
|
||||||
|
{
|
||||||
|
text: "全部慰问类型",
|
||||||
|
value: null
|
||||||
|
}
|
||||||
|
].concat(typeList.map((v) => ({ text: v.name, value: v.id }))))
|
||||||
|
if (this.typeOptions.length > 0) {
|
||||||
|
this.$set(this.pageForm, "type", this.typeOptions[0].value)
|
||||||
|
this.doSearch()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doSearch() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.pageForm.pageNumber = 1
|
||||||
|
this.pageForm.totalCount = 0
|
||||||
|
this.$refs.tableListRef.doSearch()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
if (!window.h5HistoryLayerManager) return
|
||||||
|
this.$set(this, "historyLayerUnsubscribe", window.h5HistoryLayerManager.subscribe((stack) => {
|
||||||
|
this.$set(this, "confirmVisible", stack.includes("specialcondolence-action-confirm"))
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
if (typeof this.historyLayerUnsubscribe === "function") this.historyLayerUnsubscribe()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!--#
|
||||||
|
}
|
||||||
|
#-->
|
||||||
@@ -281,11 +281,13 @@ const todo = {
|
|||||||
// 处理任务
|
// 处理任务
|
||||||
onView(task) {
|
onView(task) {
|
||||||
const {taskId, taskKey, instanceId, businessNo, formKey, h5FormKey} = task;
|
const {taskId, taskKey, instanceId, businessNo, formKey, h5FormKey} = task;
|
||||||
if (!h5FormKey) {
|
const mobileFormKey = h5FormKey || (taskKey === "cbd41337-3c87-4959-9027-809df5c7ef5e"
|
||||||
|
? "/platform/condolence/fourthApproval/h5" : "");
|
||||||
|
if (!mobileFormKey) {
|
||||||
this.$toast("当前流程暂不支持手机端审核,请前往PC端页面审核!");
|
this.$toast("当前流程暂不支持手机端审核,请前往PC端页面审核!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.$pjaxReplace(h5FormKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
this.$pjaxReplace(mobileFormKey + "?taskId=" + taskId + "&bizId=" + businessNo + "&taskKey=" + taskKey + "&tab=" + this.activeTab)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 根据当前列表类型统一展示流程状态,发起列表保留流程实例的实际状态。
|
// 根据当前列表类型统一展示流程状态,发起列表保留流程实例的实际状态。
|
||||||
|
|||||||
Reference in New Issue
Block a user