新增活动电子档案模块;
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
package com.budwk.app.zhgh.archive.constant;
|
||||
|
||||
import org.nutz.lang.Strings;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 活动电子档案常量。
|
||||
*/
|
||||
public final class ArchiveConstant {
|
||||
|
||||
public static final int PROJECT_DRAFT = 0;
|
||||
public static final int PROJECT_FILING = 1;
|
||||
public static final int PROJECT_COMPLETED = 2;
|
||||
|
||||
public static final int DOCUMENT_DRAFT = 0;
|
||||
public static final int DOCUMENT_SUBMITTED = 1;
|
||||
|
||||
public static final String STAGE_PREPARE = "PREPARE";
|
||||
public static final String STAGE_PROCESS = "PROCESS";
|
||||
public static final String STAGE_SUMMARY = "SUMMARY";
|
||||
|
||||
public static final Map<String, String> STAGE_LABELS = Map.of(
|
||||
STAGE_PREPARE, "筹备阶段",
|
||||
STAGE_PROCESS, "实施阶段",
|
||||
STAGE_SUMMARY, "总结阶段"
|
||||
);
|
||||
|
||||
private ArchiveConstant() {
|
||||
}
|
||||
|
||||
public static boolean validStage(String stage) {
|
||||
return Strings.isNotBlank(stage) && STAGE_LABELS.containsKey(stage);
|
||||
}
|
||||
|
||||
public static String stageLabel(String stage) {
|
||||
return STAGE_LABELS.getOrDefault(stage, stage);
|
||||
}
|
||||
|
||||
public static String projectStatusLabel(Integer status) {
|
||||
if (status != null && status == PROJECT_COMPLETED) {
|
||||
return "已完成";
|
||||
}
|
||||
if (status != null && status == PROJECT_FILING) {
|
||||
return "归档中";
|
||||
}
|
||||
return "草稿";
|
||||
}
|
||||
|
||||
public static String documentStatusLabel(Integer status) {
|
||||
return status != null && status == DOCUMENT_SUBMITTED ? "已提交归档" : "草稿";
|
||||
}
|
||||
|
||||
public static List<Map<String, String>> stageOptions() {
|
||||
return List.of(
|
||||
Map.of("value", STAGE_PREPARE, "label", STAGE_LABELS.get(STAGE_PREPARE)),
|
||||
Map.of("value", STAGE_PROCESS, "label", STAGE_LABELS.get(STAGE_PROCESS)),
|
||||
Map.of("value", STAGE_SUMMARY, "label", STAGE_LABELS.get(STAGE_SUMMARY))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package com.budwk.app.zhgh.archive.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.archive.constant.ArchiveConstant;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveDocType;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveDocument;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveProject;
|
||||
import com.budwk.app.zhgh.archive.service.ArchiveService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
/**
|
||||
* 活动电子档案。
|
||||
*/
|
||||
@IocBean
|
||||
@Ok("json:full")
|
||||
@At("/platform/archive")
|
||||
@Api(tags = "活动电子档案")
|
||||
public class ArchiveController {
|
||||
|
||||
@Inject
|
||||
private ArchiveService archiveService;
|
||||
|
||||
@Inject
|
||||
private Dao dao;
|
||||
|
||||
@At("/docType")
|
||||
@Ok("beetl:/platform/zhgh/archive/docType/index.html")
|
||||
@SaCheckPermission("archive.docType")
|
||||
public void docTypeIndex() {
|
||||
}
|
||||
|
||||
@At("/docType/pageData")
|
||||
@SaCheckPermission("archive.docType")
|
||||
public Result docTypePageData(PageForm pageForm, String name,
|
||||
String projectStage, Boolean requiredFlag) {
|
||||
return Result.success(archiveService.pageDocTypes(
|
||||
pageForm, name, projectStage, requiredFlag));
|
||||
}
|
||||
|
||||
@At("/docType/listData")
|
||||
public Result docTypeListData(String projectStage) {
|
||||
return Result.success(archiveService.listDocTypes(projectStage));
|
||||
}
|
||||
|
||||
@At("/docType/fetchOne")
|
||||
@SaCheckPermission("archive.docType")
|
||||
public Result docTypeFetchOne(String id) {
|
||||
return Result.success(dao.fetch(ArchiveDocType.class, id));
|
||||
}
|
||||
|
||||
@At("/docType/onSubmit")
|
||||
@SLog(tag = "活动电子档案-文档类型", msg = "新增或修改文档类型")
|
||||
@SaCheckPermission("archive.docType")
|
||||
public Result docTypeOnSubmit(ArchiveDocType docType) {
|
||||
try {
|
||||
archiveService.saveDocType(docType);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@At("/docType/onDelete")
|
||||
@SLog(tag = "活动电子档案-文档类型", msg = "删除文档类型")
|
||||
@SaCheckPermission("archive.docType")
|
||||
public Result docTypeOnDelete(String id) {
|
||||
try {
|
||||
archiveService.deleteDocType(id);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@At("/project")
|
||||
@Ok("beetl:/platform/zhgh/archive/project/index.html")
|
||||
@SaCheckPermission("archive.project")
|
||||
public void projectIndex() {
|
||||
}
|
||||
|
||||
@At("/project/pageData")
|
||||
@SaCheckPermission("archive.project")
|
||||
public Result projectPageData(PageForm pageForm, Integer year,
|
||||
String projectName, String unionId, Integer status) {
|
||||
return Result.success(archiveService.pageProjects(
|
||||
pageForm, year, projectName, unionId, status));
|
||||
}
|
||||
|
||||
@At("/project/listData")
|
||||
public Result projectListData() {
|
||||
return Result.success(archiveService.listProjects());
|
||||
}
|
||||
|
||||
@At("/project/fetchOne")
|
||||
@SaCheckPermission("archive.project")
|
||||
public Result projectFetchOne(String id) {
|
||||
return Result.success(dao.fetch(ArchiveProject.class, id));
|
||||
}
|
||||
|
||||
@At("/project/onSubmit")
|
||||
@SLog(tag = "活动电子档案-归档项目", msg = "新增或修改归档项目")
|
||||
@SaCheckPermission("archive.project")
|
||||
public Result projectOnSubmit(ArchiveProject project) {
|
||||
try {
|
||||
archiveService.saveProject(project);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@At("/project/onDelete")
|
||||
@SLog(tag = "活动电子档案-归档项目", msg = "删除归档项目")
|
||||
@SaCheckPermission("archive.project")
|
||||
public Result projectOnDelete(String id) {
|
||||
try {
|
||||
archiveService.deleteProject(id);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@At("/filing")
|
||||
@Ok("beetl:/platform/zhgh/archive/filing/index.html")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public void filingIndex() {
|
||||
}
|
||||
|
||||
@At("/filing/pageData")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public Result filingPageData(PageForm pageForm, String projectId, Integer year,
|
||||
String projectStage, String docTypeId,
|
||||
String documentName, Integer status) {
|
||||
return Result.success(archiveService.pageDocuments(pageForm, projectId, year,
|
||||
projectStage, docTypeId, documentName, status));
|
||||
}
|
||||
|
||||
@At("/filing/fetchOne")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public Result filingFetchOne(String id) {
|
||||
return Result.success(archiveService.fetchDocument(id));
|
||||
}
|
||||
|
||||
@At("/filing/saveDraft")
|
||||
@ApiOperation("保存归档文档草稿")
|
||||
@SLog(tag = "活动电子档案-资料归档", msg = "保存归档文档草稿")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public Result filingSaveDraft(ArchiveDocument document) {
|
||||
return saveDocument(document, false);
|
||||
}
|
||||
|
||||
@At("/filing/submit")
|
||||
@ApiOperation("提交归档文档")
|
||||
@SLog(tag = "活动电子档案-资料归档", msg = "提交归档文档")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public Result filingSubmit(ArchiveDocument document) {
|
||||
return saveDocument(document, true);
|
||||
}
|
||||
|
||||
@At("/filing/onDelete")
|
||||
@SLog(tag = "活动电子档案-资料归档", msg = "删除归档文档")
|
||||
@SaCheckPermission("archive.filing")
|
||||
public Result filingOnDelete(String id) {
|
||||
archiveService.deleteDocument(id);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
@At("/ledger")
|
||||
@Ok("beetl:/platform/zhgh/archive/ledger/index.html")
|
||||
@SaCheckPermission("archive.ledger")
|
||||
public void ledgerIndex() {
|
||||
}
|
||||
|
||||
@At("/ledger/pageData")
|
||||
@SaCheckPermission("archive.ledger")
|
||||
public Result ledgerPageData(PageForm pageForm, Integer year,
|
||||
String projectName, String unionId, Integer status) {
|
||||
return Result.success(archiveService.pageProjects(
|
||||
pageForm, year, projectName, unionId, status));
|
||||
}
|
||||
|
||||
@At("/ledger/detail")
|
||||
@SaCheckPermission("archive.ledger")
|
||||
public Result ledgerDetail(PageForm pageForm, String projectId,
|
||||
String projectStage, String docTypeId,
|
||||
String documentName, Integer status) {
|
||||
return Result.success(archiveService.pageDocuments(pageForm, projectId,
|
||||
null, projectStage, docTypeId, documentName, status));
|
||||
}
|
||||
|
||||
@At("/common/stageOptions")
|
||||
public Result stageOptions() {
|
||||
return Result.success(ArchiveConstant.stageOptions());
|
||||
}
|
||||
|
||||
@At("/common/unionOptions")
|
||||
public Result unionOptions() {
|
||||
return Result.success(archiveService.listUnions());
|
||||
}
|
||||
|
||||
private Result saveDocument(ArchiveDocument document, boolean submit) {
|
||||
try {
|
||||
archiveService.saveDocument(document, submit);
|
||||
return Result.success();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return Result.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.budwk.app.zhgh.archive.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
|
||||
/**
|
||||
* 活动电子档案文档类型。
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("act_archive_doc_type")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("活动电子档案文档类型")
|
||||
public class ArchiveDocType extends BaseModel {
|
||||
|
||||
@Name
|
||||
@PrevInsert(uu32 = true)
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("主键")
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 150)
|
||||
@Comment("类型名称")
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("项目阶段")
|
||||
private String projectStage;
|
||||
|
||||
@Column
|
||||
@Comment("排序编号")
|
||||
private Integer sortNo;
|
||||
|
||||
@Column
|
||||
@Comment("是否必选")
|
||||
private Boolean requiredFlag;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 600)
|
||||
@Comment("备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.budwk.app.zhgh.archive.model;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 活动电子档案归档文档。
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("act_archive_document")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("活动电子档案归档文档")
|
||||
public class ArchiveDocument extends BaseModel {
|
||||
|
||||
@Name
|
||||
@PrevInsert(uu32 = true)
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("主键")
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("项目ID")
|
||||
private String projectId;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 300)
|
||||
@Comment("文档名称")
|
||||
private String documentName;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("项目阶段")
|
||||
private String projectStage;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("文档类型ID")
|
||||
private String docTypeId;
|
||||
|
||||
@Column
|
||||
@Comment("文档状态")
|
||||
private Integer status;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
@Comment("上传人")
|
||||
private String uploader;
|
||||
|
||||
@Column
|
||||
@Comment("上传时间")
|
||||
private Long uploadTime;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.MYSQL_JSON)
|
||||
@Comment("附件")
|
||||
private List<JSONObject> files;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 600)
|
||||
@Comment("备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.budwk.app.zhgh.archive.model;
|
||||
|
||||
import com.budwk.app.base.model.BaseModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.nutz.dao.entity.annotation.ColDefine;
|
||||
import org.nutz.dao.entity.annotation.ColType;
|
||||
import org.nutz.dao.entity.annotation.Column;
|
||||
import org.nutz.dao.entity.annotation.Comment;
|
||||
import org.nutz.dao.entity.annotation.Name;
|
||||
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||
import org.nutz.dao.entity.annotation.Table;
|
||||
import org.nutz.dao.entity.annotation.TableMeta;
|
||||
|
||||
/**
|
||||
* 活动电子档案项目。
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Table("act_archive_project")
|
||||
@TableMeta("{'mysql-charset':'utf8mb4'}")
|
||||
@Comment("活动电子档案项目")
|
||||
public class ArchiveProject extends BaseModel {
|
||||
|
||||
@Name
|
||||
@PrevInsert(uu32 = true)
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("主键")
|
||||
private String id;
|
||||
|
||||
@Column
|
||||
@Comment("年度")
|
||||
private Integer year;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 300)
|
||||
@Comment("项目名称")
|
||||
private String projectName;
|
||||
|
||||
@Column
|
||||
@Comment("项目状态")
|
||||
private Integer status;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@Comment("所属工会ID")
|
||||
private String unionId;
|
||||
|
||||
@Column
|
||||
@ColDefine(type = ColType.VARCHAR, width = 150)
|
||||
@Comment("所属工会名称")
|
||||
private String unionName;
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
package com.budwk.app.zhgh.archive.service;
|
||||
|
||||
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.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_union;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.archive.constant.ArchiveConstant;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveDocType;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveDocument;
|
||||
import com.budwk.app.zhgh.archive.model.ArchiveProject;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Strings;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 活动电子档案领域服务。
|
||||
*/
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ArchiveService extends BaseServiceImpl<ArchiveProject> {
|
||||
|
||||
public ArchiveService(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
public Pagination<NutMap> pageDocTypes(PageForm pageForm, String name,
|
||||
String projectStage, Boolean requiredFlag) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(Cnd.likeEX("adt.name", name));
|
||||
cnd.andEX("adt.projectStage", "=", projectStage);
|
||||
cnd.andEX("adt.requiredFlag", "=", requiredFlag);
|
||||
cnd.and("adt.delFlag", "=", false);
|
||||
cnd.asc("adt.projectStage").asc("adt.sortNo").asc("adt.createdAt");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT adt.*,
|
||||
(SELECT COUNT(1)
|
||||
FROM act_archive_document ad
|
||||
WHERE ad.docTypeId = adt.id
|
||||
AND ad.delFlag = 0) AS documentCount
|
||||
FROM act_archive_doc_type adt
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> page = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
page.getList().forEach(this::enrichDocType);
|
||||
return page;
|
||||
}
|
||||
|
||||
public List<NutMap> listDocTypes(String projectStage) {
|
||||
Cnd cnd = Cnd.where("adt.delFlag", "=", false);
|
||||
cnd.andEX("adt.projectStage", "=", projectStage);
|
||||
cnd.asc("adt.projectStage").asc("adt.sortNo").asc("adt.createdAt");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT adt.*,
|
||||
(SELECT COUNT(1)
|
||||
FROM act_archive_document ad
|
||||
WHERE ad.docTypeId = adt.id
|
||||
AND ad.delFlag = 0) AS documentCount
|
||||
FROM act_archive_doc_type adt
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
list.forEach(this::enrichDocType);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveDocType(ArchiveDocType docType) {
|
||||
if (docType == null || Strings.isBlank(docType.getName())) {
|
||||
throw new IllegalArgumentException("类型名称不能为空");
|
||||
}
|
||||
if (!ArchiveConstant.validStage(docType.getProjectStage())) {
|
||||
throw new IllegalArgumentException("项目阶段不正确");
|
||||
}
|
||||
docType.setName(docType.getName().trim());
|
||||
if (docType.getSortNo() == null) {
|
||||
docType.setSortNo(0);
|
||||
}
|
||||
if (docType.getRequiredFlag() == null) {
|
||||
docType.setRequiredFlag(false);
|
||||
}
|
||||
Cnd duplicate = Cnd.where("projectStage", "=", docType.getProjectStage())
|
||||
.and("name", "=", docType.getName())
|
||||
.and("delFlag", "=", false);
|
||||
if (Strings.isNotBlank(docType.getId())) {
|
||||
duplicate.and("id", "<>", docType.getId());
|
||||
}
|
||||
if (dao().count(ArchiveDocType.class, duplicate) > 0) {
|
||||
throw new IllegalArgumentException("同一项目阶段下类型名称不能重复");
|
||||
}
|
||||
if (Strings.isBlank(docType.getId())) {
|
||||
dao().insert(docType);
|
||||
} else {
|
||||
ArchiveDocType old = dao().fetch(ArchiveDocType.class, docType.getId());
|
||||
if (old == null) {
|
||||
throw new IllegalArgumentException("文档类型不存在");
|
||||
}
|
||||
dao().updateIgnoreNull(docType);
|
||||
}
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteDocType(String id) {
|
||||
if (Strings.isBlank(id)) {
|
||||
return;
|
||||
}
|
||||
if (dao().count(ArchiveDocument.class,
|
||||
Cnd.where("docTypeId", "=", id).and("delFlag", "=", false)) > 0) {
|
||||
throw new IllegalArgumentException("文档类型已被归档文档引用,不能删除");
|
||||
}
|
||||
dao().delete(ArchiveDocType.class, id);
|
||||
}
|
||||
|
||||
public Pagination<NutMap> pageProjects(PageForm pageForm, Integer year,
|
||||
String projectName, String unionId, Integer status) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("ap.year", "=", year);
|
||||
cnd.and(Cnd.likeEX("ap.projectName", projectName));
|
||||
cnd.andEX("ap.unionId", "=", unionId);
|
||||
cnd.andEX("ap.status", "=", status);
|
||||
cnd.and("ap.delFlag", "=", false);
|
||||
cnd.desc("ap.year").desc("ap.createdAt");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT ap.*,
|
||||
(SELECT COUNT(1)
|
||||
FROM act_archive_document ad
|
||||
WHERE ad.projectId = ap.id
|
||||
AND ad.delFlag = 0) AS documentCount
|
||||
FROM act_archive_project ap
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> page = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
page.getList().forEach(this::enrichProject);
|
||||
return page;
|
||||
}
|
||||
|
||||
public List<NutMap> listProjects() {
|
||||
Cnd cnd = Cnd.where("ap.delFlag", "=", false);
|
||||
cnd.desc("ap.year").desc("ap.createdAt");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT ap.*,
|
||||
(SELECT COUNT(1)
|
||||
FROM act_archive_document ad
|
||||
WHERE ad.projectId = ap.id
|
||||
AND ad.delFlag = 0) AS documentCount
|
||||
FROM act_archive_project ap
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> list = listMap(sql);
|
||||
list.forEach(this::enrichProject);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveProject(ArchiveProject project) {
|
||||
if (project == null || project.getYear() == null) {
|
||||
throw new IllegalArgumentException("年度不能为空");
|
||||
}
|
||||
if (Strings.isBlank(project.getProjectName())) {
|
||||
throw new IllegalArgumentException("项目名称不能为空");
|
||||
}
|
||||
if (Strings.isBlank(project.getUnionId())) {
|
||||
throw new IllegalArgumentException("所属工会不能为空");
|
||||
}
|
||||
Sys_union union = dao().fetch(Sys_union.class, project.getUnionId());
|
||||
if (union == null) {
|
||||
throw new IllegalArgumentException("所属工会不存在");
|
||||
}
|
||||
project.setProjectName(project.getProjectName().trim());
|
||||
project.setUnionName(union.getName());
|
||||
Cnd duplicate = Cnd.where("year", "=", project.getYear())
|
||||
.and("projectName", "=", project.getProjectName())
|
||||
.and("unionId", "=", project.getUnionId())
|
||||
.and("delFlag", "=", false);
|
||||
if (Strings.isNotBlank(project.getId())) {
|
||||
duplicate.and("id", "<>", project.getId());
|
||||
}
|
||||
if (dao().count(ArchiveProject.class, duplicate) > 0) {
|
||||
throw new IllegalArgumentException("同年度同工会下项目名称不能重复");
|
||||
}
|
||||
if (Strings.isBlank(project.getId())) {
|
||||
project.setStatus(ArchiveConstant.PROJECT_DRAFT);
|
||||
dao().insert(project);
|
||||
} else {
|
||||
ArchiveProject old = dao().fetch(ArchiveProject.class, project.getId());
|
||||
if (old == null) {
|
||||
throw new IllegalArgumentException("归档项目不存在");
|
||||
}
|
||||
project.setStatus(old.getStatus());
|
||||
dao().updateIgnoreNull(project);
|
||||
}
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteProject(String id) {
|
||||
if (Strings.isBlank(id)) {
|
||||
return;
|
||||
}
|
||||
if (dao().count(ArchiveDocument.class,
|
||||
Cnd.where("projectId", "=", id).and("delFlag", "=", false)) > 0) {
|
||||
throw new IllegalArgumentException("项目下已存在归档文档,不能删除");
|
||||
}
|
||||
dao().delete(ArchiveProject.class, id);
|
||||
}
|
||||
|
||||
public Pagination<NutMap> pageDocuments(PageForm pageForm, String projectId, Integer year,
|
||||
String projectStage, String docTypeId,
|
||||
String documentName, Integer status) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("ad.projectId", "=", projectId);
|
||||
cnd.andEX("ap.year", "=", year);
|
||||
cnd.andEX("ad.projectStage", "=", projectStage);
|
||||
cnd.andEX("ad.docTypeId", "=", docTypeId);
|
||||
cnd.and(Cnd.likeEX("ad.documentName", documentName));
|
||||
cnd.andEX("ad.status", "=", status);
|
||||
cnd.and("ad.delFlag", "=", false);
|
||||
cnd.and("ap.delFlag", "=", false);
|
||||
cnd.desc("ap.year").desc("ad.uploadTime").desc("ad.createdAt");
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT ad.*, ap.year, ap.projectName, ap.unionId, ap.unionName,
|
||||
adt.name AS docTypeName, adt.requiredFlag AS docTypeRequiredFlag
|
||||
FROM act_archive_document ad
|
||||
JOIN act_archive_project ap
|
||||
ON ap.id = ad.projectId
|
||||
LEFT JOIN act_archive_doc_type adt
|
||||
ON adt.id = ad.docTypeId
|
||||
AND adt.delFlag = 0
|
||||
$condition
|
||||
""");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> page = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
page.getList().forEach(this::enrichDocument);
|
||||
return page;
|
||||
}
|
||||
|
||||
public NutMap fetchDocument(String id) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT ad.*, ap.year, ap.projectName, ap.unionId, ap.unionName,
|
||||
adt.name AS docTypeName, adt.requiredFlag AS docTypeRequiredFlag
|
||||
FROM act_archive_document ad
|
||||
JOIN act_archive_project ap
|
||||
ON ap.id = ad.projectId
|
||||
LEFT JOIN act_archive_doc_type adt
|
||||
ON adt.id = ad.docTypeId
|
||||
AND adt.delFlag = 0
|
||||
WHERE ad.id = @id
|
||||
AND ad.delFlag = 0
|
||||
AND ap.delFlag = 0
|
||||
""");
|
||||
sql.params().set("id", id);
|
||||
NutMap map = fetchMap(sql);
|
||||
if (map != null) {
|
||||
enrichDocument(map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void saveDocument(ArchiveDocument document, boolean submit) {
|
||||
validateDocument(document, submit);
|
||||
ArchiveDocument old = Strings.isBlank(document.getId())
|
||||
? null : dao().fetch(ArchiveDocument.class, document.getId());
|
||||
if (Strings.isNotBlank(document.getId()) && old == null) {
|
||||
throw new IllegalArgumentException("归档文档不存在");
|
||||
}
|
||||
int targetStatus = submit ? ArchiveConstant.DOCUMENT_SUBMITTED : ArchiveConstant.DOCUMENT_DRAFT;
|
||||
if (old != null && old.getStatus() != null
|
||||
&& old.getStatus() == ArchiveConstant.DOCUMENT_SUBMITTED && !submit) {
|
||||
targetStatus = ArchiveConstant.DOCUMENT_SUBMITTED;
|
||||
}
|
||||
document.setStatus(targetStatus);
|
||||
if (targetStatus == ArchiveConstant.DOCUMENT_SUBMITTED) {
|
||||
String uploader = SecurityUtil.getUserUsername();
|
||||
if (Strings.isBlank(uploader)) {
|
||||
uploader = SecurityUtil.getUserLoginname();
|
||||
}
|
||||
document.setUploader(uploader);
|
||||
document.setUploadTime(System.currentTimeMillis());
|
||||
} else if (old != null) {
|
||||
document.setUploader(old.getUploader());
|
||||
document.setUploadTime(old.getUploadTime());
|
||||
}
|
||||
String oldProjectId = old == null ? null : old.getProjectId();
|
||||
if (old == null) {
|
||||
dao().insert(document);
|
||||
} else {
|
||||
dao().updateIgnoreNull(document);
|
||||
}
|
||||
refreshProjectStatus(document.getProjectId());
|
||||
if (Strings.isNotBlank(oldProjectId) && !oldProjectId.equals(document.getProjectId())) {
|
||||
refreshProjectStatus(oldProjectId);
|
||||
}
|
||||
}
|
||||
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void deleteDocument(String id) {
|
||||
ArchiveDocument document = dao().fetch(ArchiveDocument.class, id);
|
||||
if (document == null) {
|
||||
return;
|
||||
}
|
||||
dao().delete(ArchiveDocument.class, id);
|
||||
refreshProjectStatus(document.getProjectId());
|
||||
}
|
||||
|
||||
public List<Sys_union> listUnions() {
|
||||
return dao().query(Sys_union.class, Cnd.where("delFlag", "=", false).asc("unionCode"));
|
||||
}
|
||||
|
||||
private void validateDocument(ArchiveDocument document, boolean submit) {
|
||||
if (document == null || Strings.isBlank(document.getProjectId())) {
|
||||
throw new IllegalArgumentException("归档项目不能为空");
|
||||
}
|
||||
if (Strings.isBlank(document.getDocumentName())) {
|
||||
throw new IllegalArgumentException("文档名称不能为空");
|
||||
}
|
||||
ArchiveProject project = dao().fetch(ArchiveProject.class,
|
||||
Cnd.where("id", "=", document.getProjectId()).and("delFlag", "=", false));
|
||||
if (project == null) {
|
||||
throw new IllegalArgumentException("归档项目不存在");
|
||||
}
|
||||
if (!ArchiveConstant.validStage(document.getProjectStage())) {
|
||||
throw new IllegalArgumentException("项目阶段不正确");
|
||||
}
|
||||
document.setDocumentName(document.getDocumentName().trim());
|
||||
if (Strings.isNotBlank(document.getDocTypeId())) {
|
||||
ArchiveDocType docType = dao().fetch(ArchiveDocType.class,
|
||||
Cnd.where("id", "=", document.getDocTypeId()).and("delFlag", "=", false));
|
||||
if (docType == null) {
|
||||
throw new IllegalArgumentException("文档类型不存在");
|
||||
}
|
||||
if (!document.getProjectStage().equals(docType.getProjectStage())) {
|
||||
throw new IllegalArgumentException("文档类型与项目阶段不匹配");
|
||||
}
|
||||
}
|
||||
if (submit && (document.getFiles() == null || document.getFiles().isEmpty())) {
|
||||
throw new IllegalArgumentException("提交归档前请先上传附件");
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshProjectStatus(String projectId) {
|
||||
if (Strings.isBlank(projectId)) {
|
||||
return;
|
||||
}
|
||||
ArchiveProject project = dao().fetch(ArchiveProject.class, projectId);
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
List<ArchiveDocument> submitted = dao().query(ArchiveDocument.class,
|
||||
Cnd.where("projectId", "=", projectId)
|
||||
.and("status", "=", ArchiveConstant.DOCUMENT_SUBMITTED)
|
||||
.and("delFlag", "=", false));
|
||||
int status = ArchiveConstant.PROJECT_DRAFT;
|
||||
if (!submitted.isEmpty()) {
|
||||
List<ArchiveDocType> requiredTypes = dao().query(ArchiveDocType.class,
|
||||
Cnd.where("requiredFlag", "=", true).and("delFlag", "=", false));
|
||||
if (requiredTypes.isEmpty()) {
|
||||
status = ArchiveConstant.PROJECT_FILING;
|
||||
} else {
|
||||
Set<String> submittedKeys = new HashSet<>();
|
||||
submitted.forEach(item -> {
|
||||
if (Strings.isNotBlank(item.getDocTypeId())) {
|
||||
submittedKeys.add(item.getProjectStage() + "_" + item.getDocTypeId());
|
||||
}
|
||||
});
|
||||
boolean completed = requiredTypes.stream().allMatch(item ->
|
||||
submittedKeys.contains(item.getProjectStage() + "_" + item.getId()));
|
||||
status = completed ? ArchiveConstant.PROJECT_COMPLETED : ArchiveConstant.PROJECT_FILING;
|
||||
}
|
||||
}
|
||||
dao().update(ArchiveProject.class, Chain.make("status", status),
|
||||
Cnd.where("id", "=", projectId));
|
||||
}
|
||||
|
||||
private void enrichDocType(NutMap map) {
|
||||
map.put("projectStageLabel", ArchiveConstant.stageLabel(map.getString("projectStage")));
|
||||
}
|
||||
|
||||
private void enrichProject(NutMap map) {
|
||||
map.put("statusLabel", ArchiveConstant.projectStatusLabel(map.getInt("status")));
|
||||
}
|
||||
|
||||
private void enrichDocument(NutMap map) {
|
||||
map.put("projectStageLabel", ArchiveConstant.stageLabel(map.getString("projectStage")));
|
||||
map.put("statusLabel", ArchiveConstant.documentStatusLabel(map.getInt("status")));
|
||||
Object files = map.get("files");
|
||||
if (files == null || StrUtil.isBlank(String.valueOf(files))) {
|
||||
map.put("files", Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
-- 活动电子档案模块初始化脚本(MySQL 8)。
|
||||
-- 表结构、索引和菜单均可独立部署,不包含数据库名限定。
|
||||
|
||||
CREATE TABLE IF NOT EXISTS act_archive_doc_type (
|
||||
id VARCHAR(32) NOT NULL COMMENT '主键',
|
||||
name VARCHAR(150) NOT NULL COMMENT '类型名称',
|
||||
projectStage VARCHAR(32) NOT NULL COMMENT '项目阶段:PREPARE/PROCESS/SUMMARY',
|
||||
sortNo INT NOT NULL DEFAULT 0 COMMENT '排序编号',
|
||||
requiredFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否必选',
|
||||
remark VARCHAR(600) NULL COMMENT '备注',
|
||||
createdBy VARCHAR(32) NULL COMMENT '创建人',
|
||||
createdAt BIGINT NULL COMMENT '创建时间',
|
||||
updatedBy VARCHAR(32) NULL COMMENT '修改人',
|
||||
updatedAt BIGINT NULL COMMENT '修改时间',
|
||||
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_archive_doc_type_stage_name (projectStage, name),
|
||||
KEY idx_archive_doc_type_stage_sort (projectStage, sortNo, createdAt)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案文档类型';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS act_archive_project (
|
||||
id VARCHAR(32) NOT NULL COMMENT '主键',
|
||||
year INT NOT NULL COMMENT '年度',
|
||||
projectName VARCHAR(300) NOT NULL COMMENT '项目名称',
|
||||
status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0草稿、1归档中、2已完成',
|
||||
unionId VARCHAR(32) NOT NULL COMMENT '所属工会ID',
|
||||
unionName VARCHAR(150) NOT NULL COMMENT '所属工会名称',
|
||||
createdBy VARCHAR(32) NULL COMMENT '创建人',
|
||||
createdAt BIGINT NULL COMMENT '创建时间',
|
||||
updatedBy VARCHAR(32) NULL COMMENT '修改人',
|
||||
updatedAt BIGINT NULL COMMENT '修改时间',
|
||||
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_archive_project_year_name_union (year, projectName, unionId),
|
||||
KEY idx_archive_project_year_created (year, createdAt),
|
||||
KEY idx_archive_project_union (unionId)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案项目';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS act_archive_document (
|
||||
id VARCHAR(32) NOT NULL COMMENT '主键',
|
||||
projectId VARCHAR(32) NOT NULL COMMENT '归档项目ID',
|
||||
documentName VARCHAR(300) NOT NULL COMMENT '文档名称',
|
||||
projectStage VARCHAR(32) NOT NULL COMMENT '项目阶段:PREPARE/PROCESS/SUMMARY',
|
||||
docTypeId VARCHAR(32) NULL COMMENT '文档类型ID',
|
||||
status TINYINT NOT NULL DEFAULT 0 COMMENT '状态:0草稿、1已提交归档',
|
||||
uploader VARCHAR(100) NULL COMMENT '上传人',
|
||||
uploadTime BIGINT NULL COMMENT '上传时间',
|
||||
files JSON NULL COMMENT '附件上传结果',
|
||||
remark VARCHAR(600) NULL COMMENT '备注',
|
||||
createdBy VARCHAR(32) NULL COMMENT '创建人',
|
||||
createdAt BIGINT NULL COMMENT '创建时间',
|
||||
updatedBy VARCHAR(32) NULL COMMENT '修改人',
|
||||
updatedAt BIGINT NULL COMMENT '修改时间',
|
||||
delFlag TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标记',
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_archive_document_query (projectId, projectStage, docTypeId, uploadTime),
|
||||
KEY idx_archive_document_project_status (projectId, status),
|
||||
CONSTRAINT fk_archive_document_project
|
||||
FOREIGN KEY (projectId) REFERENCES act_archive_project (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='活动电子档案归档文档';
|
||||
|
||||
-- 一级菜单。
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit,
|
||||
disabled, permission, note, location, hasChildren, createdBy, createdAt,
|
||||
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
|
||||
initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'9a7d8d84b14f4d6e8ab2000000000001',
|
||||
'',
|
||||
LPAD(IFNULL(MAX(CAST(path AS UNSIGNED)), 0) + 1, 4, '0'),
|
||||
'活动电子档案',
|
||||
'Archive',
|
||||
'menu',
|
||||
'',
|
||||
'',
|
||||
'ti-folder',
|
||||
1,
|
||||
0,
|
||||
'archive',
|
||||
NULL,
|
||||
992,
|
||||
1,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
'',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000,
|
||||
0,
|
||||
'PC',
|
||||
NULL,
|
||||
NULL,
|
||||
'h',
|
||||
0,
|
||||
0
|
||||
FROM sys_menu
|
||||
WHERE (parentId = '' OR parentId IS NULL)
|
||||
AND CHAR_LENGTH(path) = 4
|
||||
HAVING NOT EXISTS (
|
||||
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive') t
|
||||
);
|
||||
|
||||
-- 文档类型设置。
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit,
|
||||
disabled, permission, note, location, hasChildren, createdBy, createdAt,
|
||||
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
|
||||
initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'9a7d8d84b14f4d6e8ab2000000000002', p.id, CONCAT(p.path, '0001'),
|
||||
'文档类型设置', 'Archive Doc Type', 'menu', '/platform/archive/docType',
|
||||
'data-pjax', '', 1, 0, 'archive.docType', NULL, 1, 0, '',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
|
||||
'PC', NULL, NULL, 'w', 0, 0
|
||||
FROM sys_menu p
|
||||
WHERE p.permission = 'archive'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.docType') t
|
||||
);
|
||||
|
||||
-- 创建项目。
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit,
|
||||
disabled, permission, note, location, hasChildren, createdBy, createdAt,
|
||||
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
|
||||
initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'9a7d8d84b14f4d6e8ab2000000000003', p.id, CONCAT(p.path, '0002'),
|
||||
'创建项目', 'Archive Project', 'menu', '/platform/archive/project',
|
||||
'data-pjax', '', 1, 0, 'archive.project', NULL, 2, 0, '',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
|
||||
'PC', NULL, NULL, 'c', 0, 0
|
||||
FROM sys_menu p
|
||||
WHERE p.permission = 'archive'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.project') t
|
||||
);
|
||||
|
||||
-- 资料归档。
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit,
|
||||
disabled, permission, note, location, hasChildren, createdBy, createdAt,
|
||||
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
|
||||
initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'9a7d8d84b14f4d6e8ab2000000000004', p.id, CONCAT(p.path, '0003'),
|
||||
'资料归档', 'Archive Filing', 'menu', '/platform/archive/filing',
|
||||
'data-pjax', '', 1, 0, 'archive.filing', NULL, 3, 0, '',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
|
||||
'PC', NULL, NULL, 'z', 0, 0
|
||||
FROM sys_menu p
|
||||
WHERE p.permission = 'archive'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.filing') t
|
||||
);
|
||||
|
||||
-- 档案台账。
|
||||
INSERT INTO sys_menu (
|
||||
id, parentId, path, name, aliasName, type, href, target, icon, showit,
|
||||
disabled, permission, note, location, hasChildren, createdBy, createdAt,
|
||||
updatedBy, updatedAt, delFlag, platform, moduleId, picIcon,
|
||||
initialPinyinName, isRecommendApp, isRecommendService
|
||||
)
|
||||
SELECT
|
||||
'9a7d8d84b14f4d6e8ab2000000000005', p.id, CONCAT(p.path, '0004'),
|
||||
'档案台账', 'Archive Ledger', 'menu', '/platform/archive/ledger',
|
||||
'data-pjax', '', 1, 0, 'archive.ledger', NULL, 4, 0, '',
|
||||
UNIX_TIMESTAMP(NOW()) * 1000, '', UNIX_TIMESTAMP(NOW()) * 1000, 0,
|
||||
'PC', NULL, NULL, 'd', 0, 0
|
||||
FROM sys_menu p
|
||||
WHERE p.permission = 'archive'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM (SELECT id FROM sys_menu WHERE permission = 'archive.ledger') t
|
||||
);
|
||||
|
||||
-- 系统管理员默认授权,其他角色可在角色管理中按需分配。
|
||||
INSERT INTO sys_role_menu (roleId, menuId)
|
||||
SELECT r.id, m.id
|
||||
FROM sys_role r
|
||||
JOIN sys_menu m ON m.permission IN (
|
||||
'archive',
|
||||
'archive.docType',
|
||||
'archive.project',
|
||||
'archive.filing',
|
||||
'archive.ledger'
|
||||
)
|
||||
LEFT JOIN sys_role_menu rm ON rm.roleId = r.id AND rm.menuId = m.id
|
||||
WHERE r.code = 'SYSADMIN'
|
||||
AND rm.roleId IS NULL;
|
||||
@@ -0,0 +1,166 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="类型名称">
|
||||
<el-input v-model="pageForm.name" clearable placeholder="请输入类型名称"
|
||||
@keyup.enter.native="doSearch"></el-input>
|
||||
</search-item>
|
||||
<search-item label="项目阶段">
|
||||
<el-select v-model="pageForm.projectStage" clearable placeholder="请选择项目阶段"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option v-for="item in stageOptions" :key="item.value"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="是否必选">
|
||||
<el-select v-model="pageForm.requiredFlag" clearable placeholder="请选择"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option label="是" :value="true"></el-option>
|
||||
<el-option label="否" :value="false"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="文档类型设置">
|
||||
<el-button type="primary" size="small" @click="openForm()">
|
||||
<i class="ti-plus"></i> 新增类型
|
||||
</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column label="项目阶段" prop="projectStageLabel" min-width="120" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small">{{row.projectStageLabel}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型名称" prop="name" min-width="160" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="排序编号" prop="sortNo" width="100" align="center"></el-table-column>
|
||||
<el-table-column label="是否必选" prop="requiredFlag" width="110" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small" :type="row.requiredFlag ? 'danger' : 'info'">
|
||||
{{row.requiredFlag ? '必选' : '非必选'}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="引用文档数" prop="documentCount" width="110" align="center"></el-table-column>
|
||||
<el-table-column label="备注" prop="remark" min-width="180" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="formData.id ? '编辑文档类型' : '新增文档类型'"
|
||||
:visible.sync="formVisible" width="560px" :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
|
||||
<el-form-item label="类型名称" prop="name">
|
||||
<el-input v-model.trim="formData.name" maxlength="150" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目阶段" prop="projectStage">
|
||||
<el-select v-model="formData.projectStage" placeholder="请选择项目阶段" style="width: 100%">
|
||||
<el-option v-for="item in stageOptions" :key="item.value"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序编号" prop="sortNo">
|
||||
<el-input-number v-model="formData.sortNo" :min="0" :step="1"
|
||||
step-strictly controls-position="right" style="width: 100%"></el-input-number>
|
||||
</el-form-item>
|
||||
<el-form-item label="必选类型" prop="requiredFlag">
|
||||
<el-switch v-model="formData.requiredFlag" active-text="是" inactive-text="否"></el-switch>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model.trim="formData.remark" type="textarea" :rows="3"
|
||||
maxlength="600" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="formVisible=false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
stageOptions: [],
|
||||
formVisible: false,
|
||||
formData: {},
|
||||
pageForm: {name: "", projectStage: "", requiredFlag: null},
|
||||
formRules: {
|
||||
name: [{required: true, message: "请输入类型名称", trigger: "blur"}],
|
||||
projectStage: [{required: true, message: "请选择项目阶段", trigger: "change"}],
|
||||
sortNo: [{required: true, message: "请输入排序编号", trigger: "blur"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pageData() {
|
||||
this.$axios.post("/platform/archive/docType/pageData", this.pageForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
loadStages() {
|
||||
this.$axios.post("/platform/archive/common/stageOptions").then(res => {
|
||||
if (res.code === 0) this.stageOptions = res.data || []
|
||||
})
|
||||
},
|
||||
openForm(row) {
|
||||
this.formData = row ? clone(row) : {sortNo: 0, requiredFlag: false}
|
||||
this.formVisible = true
|
||||
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate(async valid => {
|
||||
if (!valid) return
|
||||
const res = await this.$axios.post("/platform/archive/docType/onSubmit", this.formData)
|
||||
if (res.code === 0) {
|
||||
this.$message.success("保存成功")
|
||||
this.formVisible = false
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("确定删除文档类型“" + row.name + "”吗?", "提示", {type: "warning"})
|
||||
.then(async () => {
|
||||
const res = await this.$axios.post("/platform/archive/docType/onDelete", {id: row.id})
|
||||
if (res.code === 0) {
|
||||
this.$message.success("删除成功")
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadStages()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,371 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.archive-summary {display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px}
|
||||
.archive-summary-title {font-size:16px; font-weight:600}
|
||||
.archive-summary-meta {color:#909399; display:flex; gap:20px; flex-wrap:wrap}
|
||||
.archive-file-count {cursor:pointer; color:#409eff}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="年度">
|
||||
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
|
||||
clearable placeholder="请选择年度" style="width: 100%"
|
||||
@change="onYearChange"></el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="归档项目">
|
||||
<el-select v-model="pageForm.projectId" clearable filterable placeholder="请选择归档项目"
|
||||
style="width: 100%" @change="onProjectChange">
|
||||
<el-option v-for="item in filteredProjects" :key="item.id"
|
||||
:label="item.year + ' ' + item.projectName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="项目阶段">
|
||||
<el-select v-model="pageForm.projectStage" clearable placeholder="请选择项目阶段"
|
||||
style="width: 100%" @change="onStageSearchChange">
|
||||
<el-option v-for="item in stageOptions" :key="item.value"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="文档类型">
|
||||
<el-select v-model="pageForm.docTypeId" clearable filterable placeholder="请选择文档类型"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option v-for="item in searchDocTypeOptions" :key="item.id"
|
||||
:label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="文档名称">
|
||||
<el-input v-model="pageForm.documentName" clearable placeholder="请输入文档名称"
|
||||
@keyup.enter.native="doSearch"></el-input>
|
||||
</search-item>
|
||||
<search-item label="归档状态">
|
||||
<el-select v-model="pageForm.status" clearable placeholder="请选择归档状态"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option label="草稿" :value="0"></el-option>
|
||||
<el-option label="已提交归档" :value="1"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card v-if="currentProject" shadow="never" class="mt20">
|
||||
<div class="archive-summary">
|
||||
<div class="archive-summary-title">
|
||||
{{currentProject.projectName}}
|
||||
<el-tag size="small" :type="projectStatusType(currentProject.status)">
|
||||
{{currentProject.statusLabel}}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="archive-summary-meta">
|
||||
<span>年度:{{currentProject.year}}</span>
|
||||
<span>所属工会:{{currentProject.unionName}}</span>
|
||||
<span>归档文档:{{currentProject.documentCount || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="资料归档">
|
||||
<el-button type="primary" size="small" :disabled="!pageForm.projectId" @click="openForm()">
|
||||
<i class="ti-plus"></i> 新增归档文档
|
||||
</el-button>
|
||||
</table-tool>
|
||||
<el-alert v-if="!projectOptions.length" title="当前没有归档项目,请先到“创建项目”中新建项目。"
|
||||
type="warning" :closable="false" show-icon class="mb10"></el-alert>
|
||||
<el-table :data="tableData" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column label="项目阶段" prop="projectStageLabel" width="120" align="center">
|
||||
<template v-slot="{row}"><el-tag size="small">{{row.projectStageLabel}}</el-tag></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文档名称" prop="documentName" min-width="180" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="文档类型" prop="docTypeName" min-width="150" show-overflow-tooltip>
|
||||
<template v-slot="{row}">
|
||||
{{row.docTypeName || "-"}}
|
||||
<el-tag v-if="row.docTypeRequiredFlag" size="mini" type="danger">必选</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传人" prop="uploader" width="110" align="center"></el-table-column>
|
||||
<el-table-column label="上传时间" prop="uploadTime" width="170" align="center">
|
||||
<template v-slot="{row}">{{row.uploadTime ? $moment(row.uploadTime).format("YYYY-MM-DD HH:mm") : "-"}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="附件" width="90" align="center">
|
||||
<template v-slot="{row}">
|
||||
<span class="archive-file-count" @click="openPreview(row)">{{fileCount(row.files)}} 个</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" prop="status" width="120" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small" :type="row.status === 1 ? 'success' : 'info'">{{row.statusLabel}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" @click="openView(row)">查看</el-button>
|
||||
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="readonly ? '查看归档文档' : (formData.id ? '编辑归档文档' : '新增归档文档')"
|
||||
:visible.sync="formVisible" width="760px" :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
|
||||
<el-form-item label="归档项目" prop="projectId">
|
||||
<el-select v-model="formData.projectId" filterable placeholder="请选择归档项目"
|
||||
style="width: 100%" :disabled="readonly">
|
||||
<el-option v-for="item in projectOptions" :key="item.id"
|
||||
:label="item.year + ' ' + item.projectName" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="文档名称" prop="documentName">
|
||||
<el-input v-model.trim="formData.documentName" maxlength="300"
|
||||
show-word-limit :disabled="readonly"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目阶段" prop="projectStage">
|
||||
<el-select v-model="formData.projectStage" placeholder="请选择项目阶段"
|
||||
style="width: 100%" :disabled="readonly" @change="onFormStageChange">
|
||||
<el-option v-for="item in stageOptions" :key="item.value"
|
||||
:label="item.label" :value="item.value"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="文档类型" prop="docTypeId">
|
||||
<el-select v-model="formData.docTypeId" clearable filterable placeholder="请选择文档类型"
|
||||
style="width: 100%" :disabled="readonly">
|
||||
<el-option v-for="item in formDocTypeOptions" :key="item.id"
|
||||
:label="item.name + (item.requiredFlag ? '(必选)' : '')"
|
||||
:value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传附件" prop="files">
|
||||
<file-upload v-if="!readonly" :value.sync="formData.files" :upload_number="20"
|
||||
:upload_size="104857600" upload_result_type="url"
|
||||
upload_result_category="array" complete_result upload_mode="drag"
|
||||
accept=".doc,.docx,.pdf,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.bmp,.webp,.mp4,.mov,.avi,.wmv,.mkv">
|
||||
</file-upload>
|
||||
<file-preview v-else :files="formData.files" complete_result></file-preview>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.id" label="上传人">
|
||||
<el-input :value="formData.uploader || '-'" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.id" label="上传时间">
|
||||
<el-input :value="formData.uploadTime ? $moment(formData.uploadTime).format('YYYY-MM-DD HH:mm') : '-'" disabled></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model.trim="formData.remark" type="textarea" :rows="3"
|
||||
maxlength="600" show-word-limit :disabled="readonly"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="formVisible=false">关闭</el-button>
|
||||
<template v-if="!readonly">
|
||||
<el-button @click="saveDocument(false)">保存草稿</el-button>
|
||||
<el-button type="primary" @click="saveDocument(true)">提交归档</el-button>
|
||||
</template>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="附件预览" :visible.sync="previewVisible" width="760px">
|
||||
<file-preview :files="previewFiles" complete_result></file-preview>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
stageOptions: [],
|
||||
projectOptions: [],
|
||||
searchDocTypeOptions: [],
|
||||
formDocTypeOptions: [],
|
||||
currentProject: null,
|
||||
formVisible: false,
|
||||
previewVisible: false,
|
||||
readonly: false,
|
||||
previewFiles: [],
|
||||
formData: {},
|
||||
pageForm: {
|
||||
year: String(new Date().getFullYear()),
|
||||
projectId: "",
|
||||
projectStage: "",
|
||||
docTypeId: "",
|
||||
documentName: "",
|
||||
status: null
|
||||
},
|
||||
formRules: {
|
||||
projectId: [{required: true, message: "请选择归档项目", trigger: "change"}],
|
||||
documentName: [{required: true, message: "请输入文档名称", trigger: "blur"}],
|
||||
projectStage: [{required: true, message: "请选择项目阶段", trigger: "change"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredProjects() {
|
||||
if (!this.pageForm.year) return this.projectOptions
|
||||
return this.projectOptions.filter(item => String(item.year) === String(this.pageForm.year))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeFiles(files) {
|
||||
if (Array.isArray(files)) return files
|
||||
if (!files) return []
|
||||
try { return JSON.parse(files) || [] } catch (e) { return [] }
|
||||
},
|
||||
fileCount(files) {
|
||||
return this.normalizeFiles(files).length
|
||||
},
|
||||
projectStatusType(status) {
|
||||
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
|
||||
},
|
||||
pageData() {
|
||||
if (!this.pageForm.projectId) {
|
||||
this.tableData = []
|
||||
this.pageForm.totalCount = 0
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/archive/filing/pageData", this.pageForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = (res.data.list || []).map(item =>
|
||||
Object.assign({}, item, {files: this.normalizeFiles(item.files)}))
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
async loadBaseData() {
|
||||
const [stages, projects] = await Promise.all([
|
||||
this.$axios.post("/platform/archive/common/stageOptions"),
|
||||
this.$axios.post("/platform/archive/project/listData")
|
||||
])
|
||||
this.stageOptions = stages.data || []
|
||||
this.projectOptions = projects.data || []
|
||||
const queryProjectId = new URLSearchParams(window.location.search).get("projectId")
|
||||
if (queryProjectId && this.projectOptions.some(item => item.id === queryProjectId)) {
|
||||
this.pageForm.projectId = queryProjectId
|
||||
const project = this.projectOptions.find(item => item.id === queryProjectId)
|
||||
this.pageForm.year = String(project.year)
|
||||
} else if (this.filteredProjects.length) {
|
||||
this.pageForm.projectId = this.filteredProjects[0].id
|
||||
} else if (this.projectOptions.length) {
|
||||
this.pageForm.projectId = this.projectOptions[0].id
|
||||
this.pageForm.year = String(this.projectOptions[0].year)
|
||||
}
|
||||
this.syncProject()
|
||||
this.pageData()
|
||||
},
|
||||
loadDocTypes(stage, target) {
|
||||
if (!stage) {
|
||||
this[target] = []
|
||||
return Promise.resolve()
|
||||
}
|
||||
return this.$axios.post("/platform/archive/docType/listData", {projectStage: stage}).then(res => {
|
||||
this[target] = res.data || []
|
||||
})
|
||||
},
|
||||
syncProject() {
|
||||
this.currentProject = this.projectOptions.find(item => item.id === this.pageForm.projectId) || null
|
||||
},
|
||||
onYearChange() {
|
||||
if (!this.filteredProjects.some(item => item.id === this.pageForm.projectId)) {
|
||||
this.pageForm.projectId = this.filteredProjects.length ? this.filteredProjects[0].id : ""
|
||||
}
|
||||
this.onProjectChange()
|
||||
},
|
||||
onProjectChange() {
|
||||
this.syncProject()
|
||||
this.doSearch()
|
||||
},
|
||||
async onStageSearchChange() {
|
||||
this.pageForm.docTypeId = ""
|
||||
await this.loadDocTypes(this.pageForm.projectStage, "searchDocTypeOptions")
|
||||
this.doSearch()
|
||||
},
|
||||
async onFormStageChange() {
|
||||
this.formData.docTypeId = ""
|
||||
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
|
||||
},
|
||||
async openForm(row) {
|
||||
this.readonly = false
|
||||
this.formData = row ? Object.assign({}, clone(row), {files: this.normalizeFiles(row.files)}) : {
|
||||
projectId: this.pageForm.projectId,
|
||||
documentName: "",
|
||||
projectStage: "",
|
||||
docTypeId: "",
|
||||
files: [],
|
||||
remark: ""
|
||||
}
|
||||
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
|
||||
this.formVisible = true
|
||||
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
|
||||
},
|
||||
async openView(row) {
|
||||
this.readonly = true
|
||||
this.formData = Object.assign({}, clone(row), {files: this.normalizeFiles(row.files)})
|
||||
await this.loadDocTypes(this.formData.projectStage, "formDocTypeOptions")
|
||||
this.formVisible = true
|
||||
},
|
||||
openPreview(row) {
|
||||
this.previewFiles = this.normalizeFiles(row.files)
|
||||
if (!this.previewFiles.length) {
|
||||
this.$message.warning("当前文档没有附件")
|
||||
return
|
||||
}
|
||||
this.previewVisible = true
|
||||
},
|
||||
saveDocument(submit) {
|
||||
this.$refs.formRef.validate(async valid => {
|
||||
if (!valid) return
|
||||
if (submit && !this.normalizeFiles(this.formData.files).length) {
|
||||
this.$message.warning("提交归档前请先上传附件")
|
||||
return
|
||||
}
|
||||
const data = Object.assign({}, this.formData, {
|
||||
files: JSON.stringify(this.normalizeFiles(this.formData.files))
|
||||
})
|
||||
const url = submit ? "/platform/archive/filing/submit" : "/platform/archive/filing/saveDraft"
|
||||
const res = await this.$axios.post(url, data)
|
||||
if (res.code === 0) {
|
||||
this.$message.success(submit ? "提交归档成功" : "草稿保存成功")
|
||||
this.formVisible = false
|
||||
await this.reloadProjects()
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("确定删除归档文档“" + row.documentName + "”吗?", "提示", {type: "warning"})
|
||||
.then(async () => {
|
||||
const res = await this.$axios.post("/platform/archive/filing/onDelete", {id: row.id})
|
||||
if (res.code === 0) {
|
||||
this.$message.success("删除成功")
|
||||
await this.reloadProjects()
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
async reloadProjects() {
|
||||
const res = await this.$axios.post("/platform/archive/project/listData")
|
||||
this.projectOptions = res.data || []
|
||||
this.syncProject()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadBaseData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,186 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
.archive-ledger-header {margin-bottom:16px}
|
||||
.archive-ledger-title {font-size:17px; font-weight:600; margin-bottom:10px}
|
||||
.archive-ledger-meta {display:flex; gap:20px; flex-wrap:wrap; color:#909399}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="年度">
|
||||
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
|
||||
clearable placeholder="请选择年度" style="width: 100%"
|
||||
@change="doSearch"></el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="项目名称">
|
||||
<el-input v-model="pageForm.projectName" clearable placeholder="请输入项目名称"
|
||||
@keyup.enter.native="doSearch"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option v-for="item in unionOptions" :key="item.id"
|
||||
:label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="档案台账"></table-tool>
|
||||
<el-table :data="tableData" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column label="年度" prop="year" width="90" align="center"></el-table-column>
|
||||
<el-table-column label="项目名称" prop="projectName" min-width="210" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="项目状态" width="110" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small" :type="projectStatusType(row.status)">{{row.statusLabel}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="170" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="归档文档数" prop="documentCount" width="120" align="center"></el-table-column>
|
||||
<el-table-column label="创建时间" prop="createdAt" width="170" align="center">
|
||||
<template v-slot="{row}">{{$moment(row.createdAt).format("YYYY-MM-DD HH:mm")}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" type="primary" @click="openLedger(row)">查阅</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<el-drawer title="项目归档台账" :visible.sync="drawerVisible" size="82%" :destroy-on-close="true">
|
||||
<div v-if="currentProject" style="padding:0 20px 20px">
|
||||
<div class="archive-ledger-header">
|
||||
<div class="archive-ledger-title">
|
||||
{{currentProject.projectName}}
|
||||
<el-tag size="small" :type="projectStatusType(currentProject.status)">
|
||||
{{currentProject.statusLabel}}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="archive-ledger-meta">
|
||||
<span>年度:{{currentProject.year}}</span>
|
||||
<span>所属工会:{{currentProject.unionName}}</span>
|
||||
<span>归档文档:{{currentProject.documentCount || 0}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="detailData" size="small">
|
||||
<el-table-column label="序号" type="index" width="60"></el-table-column>
|
||||
<el-table-column label="项目阶段" prop="projectStageLabel" width="120"></el-table-column>
|
||||
<el-table-column label="文档名称" prop="documentName" min-width="180" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="文档类型" prop="docTypeName" min-width="140" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="上传人" prop="uploader" width="110"></el-table-column>
|
||||
<el-table-column label="上传时间" width="160">
|
||||
<template v-slot="{row}">{{row.uploadTime ? $moment(row.uploadTime).format("YYYY-MM-DD HH:mm") : "-"}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="120" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small" :type="row.status === 1 ? 'success' : 'info'">{{row.statusLabel}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" type="primary" @click="preview(row)">查看附件</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination style="margin-top:15px;text-align:center"
|
||||
:current-page="detailForm.pageNumber"
|
||||
:page-size="detailForm.pageSize"
|
||||
:page-sizes="[10,20,50]"
|
||||
:total="detailForm.totalCount"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
@current-change="val=>{detailForm.pageNumber=val;loadDetail()}"
|
||||
@size-change="val=>{detailForm.pageSize=val;detailForm.pageNumber=1;loadDetail()}">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-drawer>
|
||||
|
||||
<el-dialog title="附件预览" :visible.sync="previewVisible" width="760px">
|
||||
<file-preview :files="previewFiles" complete_result></file-preview>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
detailData: [],
|
||||
unionOptions: [],
|
||||
drawerVisible: false,
|
||||
previewVisible: false,
|
||||
previewFiles: [],
|
||||
currentProject: null,
|
||||
pageForm: {
|
||||
year: String(new Date().getFullYear()),
|
||||
projectName: "",
|
||||
unionId: ""
|
||||
},
|
||||
detailForm: {pageNumber: 1, pageSize: 10, totalCount: 0, projectId: ""}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
normalizeFiles(files) {
|
||||
if (Array.isArray(files)) return files
|
||||
if (!files) return []
|
||||
try { return JSON.parse(files) || [] } catch (e) { return [] }
|
||||
},
|
||||
projectStatusType(status) {
|
||||
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post("/platform/archive/ledger/pageData", this.pageForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
loadUnions() {
|
||||
this.$axios.post("/platform/archive/common/unionOptions").then(res => {
|
||||
if (res.code === 0) this.unionOptions = res.data || []
|
||||
})
|
||||
},
|
||||
openLedger(row) {
|
||||
this.currentProject = row
|
||||
this.detailForm = {pageNumber: 1, pageSize: 10, totalCount: 0, projectId: row.id}
|
||||
this.drawerVisible = true
|
||||
this.loadDetail()
|
||||
},
|
||||
loadDetail() {
|
||||
this.$axios.post("/platform/archive/ledger/detail", this.detailForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.detailData = (res.data.list || []).map(item =>
|
||||
Object.assign({}, item, {files: this.normalizeFiles(item.files)}))
|
||||
this.detailForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
preview(row) {
|
||||
this.previewFiles = this.normalizeFiles(row.files)
|
||||
if (!this.previewFiles.length) {
|
||||
this.$message.warning("当前文档没有附件")
|
||||
return
|
||||
}
|
||||
this.previewVisible = true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadUnions()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
@@ -0,0 +1,183 @@
|
||||
<!--#
|
||||
layout("/layouts/platform.html"){
|
||||
#-->
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<el-card shadow="never">
|
||||
<search @search="doSearch">
|
||||
<search-item label="年度">
|
||||
<el-date-picker v-model="pageForm.year" type="year" value-format="yyyy"
|
||||
clearable placeholder="请选择年度" style="width: 100%"
|
||||
@change="doSearch"></el-date-picker>
|
||||
</search-item>
|
||||
<search-item label="项目名称">
|
||||
<el-input v-model="pageForm.projectName" clearable placeholder="请输入项目名称"
|
||||
@keyup.enter.native="doSearch"></el-input>
|
||||
</search-item>
|
||||
<search-item label="所属工会">
|
||||
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option v-for="item in unionOptions" :key="item.id"
|
||||
:label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
<search-item label="项目状态">
|
||||
<el-select v-model="pageForm.status" clearable placeholder="请选择项目状态"
|
||||
style="width: 100%" @change="doSearch">
|
||||
<el-option label="草稿" :value="0"></el-option>
|
||||
<el-option label="归档中" :value="1"></el-option>
|
||||
<el-option label="已完成" :value="2"></el-option>
|
||||
</el-select>
|
||||
</search-item>
|
||||
</search>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt20">
|
||||
<table-tool label="归档项目">
|
||||
<el-button type="primary" size="small" @click="openForm()">
|
||||
<i class="ti-plus"></i> 新建项目
|
||||
</el-button>
|
||||
</table-tool>
|
||||
<el-table :data="tableData" :size="tableSize">
|
||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||
<el-table-column label="年度" prop="year" width="90" align="center"></el-table-column>
|
||||
<el-table-column label="项目名称" prop="projectName" min-width="200" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="项目状态" prop="status" width="110" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-tag size="small" :type="statusType(row.status)">{{row.statusLabel}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="所属工会" prop="unionName" min-width="160" show-overflow-tooltip></el-table-column>
|
||||
<el-table-column label="归档文档数" prop="documentCount" width="110" align="center"></el-table-column>
|
||||
<el-table-column label="创建时间" prop="createdAt" width="170" align="center">
|
||||
<template v-slot="{row}">{{$moment(row.createdAt).format("YYYY-MM-DD HH:mm")}}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="240" align="center">
|
||||
<template v-slot="{row}">
|
||||
<el-button size="mini" type="primary" @click="openForm(row)">编辑</el-button>
|
||||
<el-button size="mini" type="success" @click="goFiling(row)">资料归档</el-button>
|
||||
<el-button size="mini" type="danger" @click="onDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--#include("/layouts/pagination.html"){}#-->
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="formData.id ? '编辑归档项目' : '新建归档项目'"
|
||||
:visible.sync="formVisible" width="560px" :close-on-click-modal="false">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
|
||||
<el-form-item label="年度" prop="year">
|
||||
<el-date-picker v-model="formData.year" type="year" value-format="yyyy"
|
||||
placeholder="请选择年度" style="width: 100%"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input v-model.trim="formData.projectName" maxlength="300" show-word-limit></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属工会" prop="unionId">
|
||||
<el-select v-model="formData.unionId" filterable placeholder="请选择所属工会"
|
||||
style="width: 100%">
|
||||
<el-option v-for="item in unionOptions" :key="item.id"
|
||||
:label="item.name" :value="item.id"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.id" label="项目状态">
|
||||
<el-input :value="formData.statusLabel || '草稿'" disabled></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer">
|
||||
<el-button @click="formVisible=false">取消</el-button>
|
||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
el: "#app",
|
||||
mixins: [initTableMixins],
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
unionOptions: [],
|
||||
formVisible: false,
|
||||
formData: {},
|
||||
pageForm: {
|
||||
year: String(new Date().getFullYear()),
|
||||
projectName: "",
|
||||
unionId: "",
|
||||
status: null
|
||||
},
|
||||
formRules: {
|
||||
year: [{required: true, message: "请选择年度", trigger: "change"}],
|
||||
projectName: [{required: true, message: "请输入项目名称", trigger: "blur"}],
|
||||
unionId: [{required: true, message: "请选择所属工会", trigger: "change"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
statusType(status) {
|
||||
return status === 2 ? "success" : (status === 1 ? "warning" : "info")
|
||||
},
|
||||
pageData() {
|
||||
this.$axios.post("/platform/archive/project/pageData", this.pageForm).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.tableData = res.data.list
|
||||
this.pageForm.totalCount = res.data.totalCount
|
||||
}
|
||||
})
|
||||
},
|
||||
loadUnions() {
|
||||
this.$axios.post("/platform/archive/common/unionOptions").then(res => {
|
||||
if (res.code === 0) this.unionOptions = res.data || []
|
||||
})
|
||||
},
|
||||
openForm(row) {
|
||||
this.formData = row ? clone(row) : {
|
||||
year: String(new Date().getFullYear()),
|
||||
projectName: "",
|
||||
unionId: ""
|
||||
}
|
||||
if (this.formData.year != null) this.formData.year = String(this.formData.year)
|
||||
this.formVisible = true
|
||||
this.$nextTick(() => this.$refs.formRef && this.$refs.formRef.clearValidate())
|
||||
},
|
||||
onSubmit() {
|
||||
this.$refs.formRef.validate(async valid => {
|
||||
if (!valid) return
|
||||
const data = Object.assign({}, this.formData, {year: Number(this.formData.year)})
|
||||
const res = await this.$axios.post("/platform/archive/project/onSubmit", data)
|
||||
if (res.code === 0) {
|
||||
this.$message.success("保存成功")
|
||||
this.formVisible = false
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
onDelete(row) {
|
||||
this.$confirm("确定删除归档项目“" + row.projectName + "”吗?", "提示", {type: "warning"})
|
||||
.then(async () => {
|
||||
const res = await this.$axios.post("/platform/archive/project/onDelete", {id: row.id})
|
||||
if (res.code === 0) {
|
||||
this.$message.success("删除成功")
|
||||
this.pageData()
|
||||
} else {
|
||||
this.$message.warning(res.msg)
|
||||
}
|
||||
}).catch(() => {})
|
||||
},
|
||||
goFiling(row) {
|
||||
window.location.href = "/platform/archive/filing?projectId=" + encodeURIComponent(row.id)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadUnions()
|
||||
this.pageData()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Reference in New Issue
Block a user