Merge remote-tracking branch 'origin/main'

This commit is contained in:
2026-07-23 13:58:17 +08:00
132 changed files with 9540 additions and 506 deletions
@@ -0,0 +1,330 @@
-- 申诉管理初始化脚本
-- 说明:本脚本依赖系统基础表 sys_menu、sys_role 已存在;如 sys_role_menu 不存在会自动创建。
SET @now := CAST(UNIX_TIMESTAMP(NOW()) * 1000 AS UNSIGNED);
CREATE TABLE IF NOT EXISTS `appeal_type` (
`id` varchar(32) NOT NULL COMMENT 'ID',
`name` varchar(100) DEFAULT NULL COMMENT '类型名称',
`sort` int DEFAULT 0 COMMENT '排序',
`enabled` tinyint(1) DEFAULT 1 COMMENT '是否启用',
`remark` varchar(500) 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`),
KEY `INDEX_APPEAL_TYPE_ENABLED` (`enabled`),
KEY `INDEX_APPEAL_TYPE_SORT` (`sort`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='申诉类型';
CREATE TABLE IF NOT EXISTS `appeal_info` (
`id` varchar(32) NOT NULL COMMENT 'ID',
`userId` varchar(32) DEFAULT NULL COMMENT '申诉人ID',
`userName` varchar(50) DEFAULT NULL COMMENT '申诉人姓名',
`loginName` varchar(50) DEFAULT NULL COMMENT '申诉人工号',
`sex` varchar(20) DEFAULT NULL COMMENT '性别',
`birthday` date DEFAULT NULL COMMENT '出生年月',
`political` varchar(100) DEFAULT NULL COMMENT '政治面貌',
`unitId` varchar(32) DEFAULT NULL COMMENT '所在单位ID',
`unitName` varchar(100) DEFAULT NULL COMMENT '所在单位',
`positionName` varchar(100) DEFAULT NULL COMMENT '岗位',
`address` varchar(300) DEFAULT NULL COMMENT '住址',
`mobile` varchar(100) DEFAULT NULL COMMENT '联系方式',
`appealTypeId` varchar(32) DEFAULT NULL COMMENT '申诉类型ID',
`appealTypeName` varchar(100) DEFAULT NULL COMMENT '申诉类型名称',
`defendantUnitId` varchar(32) DEFAULT NULL COMMENT '被申诉单位ID',
`defendantUnitName` varchar(100) DEFAULT NULL COMMENT '被申诉单位',
`defendantAddress` varchar(300) DEFAULT NULL COMMENT '被申诉单位地址',
`defendantContact` varchar(100) DEFAULT NULL COMMENT '被申诉单位联系方式',
`title` varchar(200) DEFAULT NULL COMMENT '申诉标题',
`appealMatter` text COMMENT '申诉事项',
`reason` text COMMENT '申诉理由',
`request` text COMMENT '申诉要求',
`applyDate` date DEFAULT NULL COMMENT '申请日期',
`signature` varchar(255) DEFAULT NULL COMMENT '申诉人签名',
`files` json COMMENT '附件',
`state` varchar(50) DEFAULT NULL COMMENT '业务状态',
`acceptUserId` varchar(32) DEFAULT NULL COMMENT '受理人ID',
`acceptUserName` varchar(50) DEFAULT NULL COMMENT '受理人姓名',
`acceptTime` datetime DEFAULT NULL COMMENT '受理时间',
`decisionContent` text COMMENT '处理决定',
`legalBasis` text COMMENT '事实理由及适用依据',
`decisionDate` date DEFAULT NULL COMMENT '作出决定日期',
`decisionFiles` json COMMENT '决定书附件',
`executeUserId` varchar(32) DEFAULT NULL COMMENT '执行人ID',
`executeUserName` varchar(50) DEFAULT NULL COMMENT '执行人姓名',
`executeTime` datetime DEFAULT NULL COMMENT '执行时间',
`executeContent` text COMMENT '执行情况',
`executeFiles` json 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 `INDEX_APPEAL_INFO_USER` (`userId`),
KEY `INDEX_APPEAL_INFO_UNIT` (`unitId`),
KEY `INDEX_APPEAL_INFO_TYPE` (`appealTypeId`),
KEY `INDEX_APPEAL_INFO_DEFENDANT_UNIT` (`defendantUnitId`),
KEY `INDEX_APPEAL_INFO_STATE` (`state`),
KEY `INDEX_APPEAL_INFO_APPLY_DATE` (`applyDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教职工申诉';
CREATE TABLE IF NOT EXISTS `sys_role_menu` (
`roleId` varchar(32) NOT NULL,
`menuId` varchar(32) NOT NULL,
KEY `INDEX_SYS_ROLE_MENU_ROLE` (`roleId`),
KEY `INDEX_SYS_ROLE_MENU_MENU` (`menuId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色菜单关系';
INSERT INTO `sys_role` (`id`, `name`, `code`, `aliasName`, `disabled`, `unitid`, `note`, `sort`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c002000000000000000000000001', '申诉处理委员会成员', 'APPEAL_COMMITTEE_MEMBER', 'AppealCommitteeMember', 0, NULL, '申诉受理环节处理角色', 60, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `sys_role` WHERE `code` = 'APPEAL_COMMITTEE_MEMBER');
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`)
SELECT 'a0e9c001000000000000000000000001', '', '9901', '申诉管理', 'Appeal', 'menu', '', '', 'ti-comments', 1, 0, 'appeal', NULL, 9901, 1, '', @now, '', @now, 0, 'PC'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal' OR `path` = '9901');
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`)
SELECT 'a0e9c001000000000000000000000002', parent.`id`, '99010001', '申诉类型', 'AppealType', 'menu', '/platform/appeal/type', 'data-pjax', '', 1, 0, 'appeal.type', NULL, 990101, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.type' OR `path` = '99010001');
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`)
SELECT 'a0e9c001000000000000000000000003', parent.`id`, '99010002', '提交申诉', 'AppealWrite', 'menu', '/platform/appeal/write', 'data-pjax', '', 1, 0, 'appeal.write', NULL, 990102, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.write' OR `path` = '99010002');
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`)
SELECT 'a0e9c001000000000000000000000004', parent.`id`, '99010003', '我的申诉', 'AppealMine', 'menu', '/platform/appeal/mine', 'data-pjax', '', 1, 0, 'appeal.mine', NULL, 990103, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.mine' OR `path` = '99010003');
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`)
SELECT 'a0e9c001000000000000000000000005', parent.`id`, '99010004', '申诉受理', 'AppealAccept', 'menu', '/platform/appeal/accept', 'data-pjax', '', 1, 0, 'appeal.accept', NULL, 990104, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.accept' OR `path` = '99010004');
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`)
SELECT 'a0e9c001000000000000000000000006', parent.`id`, '99010005', '申诉执行', 'AppealExecute', 'menu', '/platform/appeal/execute', 'data-pjax', '', 1, 0, 'appeal.execute', NULL, 990105, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.execute' OR `path` = '99010005');
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`)
SELECT 'a0e9c001000000000000000000000007', parent.`id`, '99010006', '查询统计', 'AppealQuery', 'menu', '/platform/appeal/query', 'data-pjax', '', 1, 0, 'appeal.query', NULL, 990106, 0, '', @now, '', @now, 0, 'PC'
FROM `sys_menu` parent
WHERE parent.`permission` = 'appeal'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'appeal.query' OR `path` = '99010006');
UPDATE `sys_menu`
SET `platform` = 'PC'
WHERE `permission` IN ('appeal', 'appeal.type', 'appeal.write', 'appeal.mine', 'appeal.accept', 'appeal.execute', 'appeal.query')
AND (`platform` IS NULL OR `platform` = '');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000001', '处分', 1, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '处分');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000002', '岗位聘用', 2, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '岗位聘用');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000003', '撤销奖励', 3, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '撤销奖励');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000004', '考核结果定为基本合格或不合格', 4, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '考核结果定为基本合格或不合格');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000005', '未按国家规定确定或扣减工资福利待遇', 5, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '未按国家规定确定或扣减工资福利待遇');
INSERT INTO `appeal_type` (`id`, `name`, `sort`, `enabled`, `remark`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c003000000000000000000000006', '法律法规和规章制度规定可以提出申诉的其他事项', 6, 1, NULL, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `appeal_type` WHERE `name` = '法律法规和规章制度规定可以提出申诉的其他事项');
/* todo 系统上线时手动录入工作流程
INSERT INTO `wf_process_category` (`id`, `name`, `picIcon`, `icon`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c004000000000000000000000001', '申诉管理', NULL, 'ti-comments', '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `wf_process_category` WHERE `id` = 'a0e9c004000000000000000000000001' OR `name` = '申诉管理');
SET @appeal_flow_json := '{
"name": "SSGL",
"displayName": "申诉管理",
"type": "appeal",
"category": "a0e9c004000000000000000000000001",
"description": "教职工申诉审核流程",
"instanceUrl": "/platform/appeal/write",
"instanceViewUrl": "/platform/appeal/mine",
"nodes": [
{
"id": "startTask",
"type": "snaker:start",
"x": 120,
"y": 160,
"text": {"value": "提交申诉"},
"properties": {"width": 90, "height": 50}
},
{
"id": "appealAccept",
"type": "snaker:task",
"x": 330,
"y": 160,
"text": {"value": "受理"},
"properties": {
"width": 120,
"height": 60,
"form": "/platform/appeal/accept",
"taskType": 0,
"performType": 0,
"assignmentHandler": "com.budwk.app.flow.handler.FlowAppealCommitteeAssignmentHandler"
}
},
{
"id": "appealExecute",
"type": "snaker:task",
"x": 560,
"y": 160,
"text": {"value": "执行"},
"properties": {
"width": 120,
"height": 60,
"form": "/platform/appeal/execute",
"taskType": 0,
"performType": 0,
"assignmentHandler": "com.budwk.app.flow.handler.FlowAppealDefendantUnitAssignmentHandler"
}
},
{
"id": "endTask",
"type": "snaker:end",
"x": 780,
"y": 160,
"text": {"value": "结束"},
"properties": {"width": 90, "height": 50}
}
],
"edges": [
{
"id": "edge_start_accept",
"type": "polyline",
"sourceNodeId": "startTask",
"targetNodeId": "appealAccept",
"properties": {},
"text": {"value": ""},
"startPoint": {"x": 165, "y": 160},
"endPoint": {"x": 270, "y": 160},
"pointsList": [{"x": 165, "y": 160}, {"x": 270, "y": 160}]
},
{
"id": "edge_accept_execute",
"type": "polyline",
"sourceNodeId": "appealAccept",
"targetNodeId": "appealExecute",
"properties": {"expr": "#submitType==1"},
"text": {"value": "受理"},
"startPoint": {"x": 390, "y": 160},
"endPoint": {"x": 500, "y": 160},
"pointsList": [{"x": 390, "y": 160}, {"x": 500, "y": 160}]
},
{
"id": "edge_accept_end",
"type": "polyline",
"sourceNodeId": "appealAccept",
"targetNodeId": "endTask",
"properties": {"expr": "#submitType==2"},
"text": {"value": "不予受理"},
"startPoint": {"x": 330, "y": 220},
"endPoint": {"x": 780, "y": 220},
"pointsList": [{"x": 330, "y": 220}, {"x": 780, "y": 220}, {"x": 780, "y": 185}]
},
{
"id": "edge_execute_end",
"type": "polyline",
"sourceNodeId": "appealExecute",
"targetNodeId": "endTask",
"properties": {},
"text": {"value": ""},
"startPoint": {"x": 620, "y": 160},
"endPoint": {"x": 735, "y": 160},
"pointsList": [{"x": 620, "y": 160}, {"x": 735, "y": 160}]
}
]
}';
INSERT INTO `wf_process_define` (`name`, `displayName`, `type`, `category`, `instanceUrl`, `instanceViewUrl`, `icon`, `state`, `content`, `version`, `pinyinName`, `description`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'SSGL', '申诉管理', 'appeal', 'a0e9c004000000000000000000000001', '/platform/appeal/write', '/platform/appeal/mine', 'ti-comments', 1, @appeal_flow_json, 1, 'S', '教职工申诉审核流程', '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `wf_process_define` WHERE `name` = 'SSGL');
UPDATE `wf_process_define`
SET `state` = 1,
`type` = 'appeal',
`category` = 'a0e9c004000000000000000000000001',
`pinyinName` = 'S',
`icon` = 'ti-comments',
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND (`state` IS NULL OR `state` <> 1 OR IFNULL(`type`, '') <> 'appeal' OR IFNULL(`category`, '') <> 'a0e9c004000000000000000000000001' OR IFNULL(`pinyinName`, '') <> 'S' OR IFNULL(`icon`, '') <> 'ti-comments');
UPDATE `wf_process_define`
SET `content` = @appeal_flow_json,
`displayName` = IFNULL(`displayName`, '申诉管理'),
`instanceUrl` = IFNULL(`instanceUrl`, '/platform/appeal/write'),
`instanceViewUrl` = IFNULL(`instanceViewUrl`, '/platform/appeal/mine'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND (`content` IS NULL OR `content` = '');*/
/*
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('appeal', 'appeal.write', 'appeal.mine')
WHERE r.`code` = 'MEMBER'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('appeal', 'appeal.accept', 'appeal.query')
WHERE r.`code` = 'APPEAL_COMMITTEE_MEMBER'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('appeal', 'appeal.execute', 'appeal.query')
WHERE r.`code` = 'BRANCH_UNION_ADMIN'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('appeal', 'appeal.type', 'appeal.write', 'appeal.mine', 'appeal.accept', 'appeal.execute', 'appeal.query')
WHERE r.`code` IN ('SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_DC_ADMIN')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
*/
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('appeal', 'appeal.type', 'appeal.write', 'appeal.mine', 'appeal.accept', 'appeal.execute', 'appeal.query')
WHERE r.`code` IN ('SYSADMIN')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
@@ -0,0 +1,146 @@
-- 申诉管理手机端初始化脚本
-- 说明:PC端申诉模块已部署时,只需要执行本脚本新增手机端入口和权限。
SET @now := CAST(UNIX_TIMESTAMP(NOW()) * 1000 AS UNSIGNED);
INSERT INTO `sys_module` (`id`, `platform`, `name`, `icon`, `faIcon`, `sortNum`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`)
SELECT 'a0e9c005000000000000000000000001', 'H5', '民主管理', NULL, 'ti-comments', 9901, '', @now, '', @now, 0
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `sys_module` WHERE `id` = 'a0e9c005000000000000000000000001' OR (`platform` = 'H5' AND `name` = '民主管理'));
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'a0e9c006000000000000000000000001', '', 'H9901', '申诉管理', 'S', '', 'menu', '/platform/appeal/h5', 'data-pjax', 'comment-o', NULL, 1, 0, 'h5.appeal', NULL, 9901, 1, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '民主管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.appeal' OR `path` = 'H9901');
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'a0e9c006000000000000000000000002', 'a0e9c006000000000000000000000001', 'H9901H9902', '提交申诉', 'T', '', 'menu', '/platform/appeal/write/h5', 'data-pjax', 'edit', NULL, 1, 0, 'h5.appeal.write', NULL, 9902, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '民主管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.appeal.write' OR `path` = 'H9902');
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'a0e9c006000000000000000000000003', 'a0e9c006000000000000000000000001', 'H9901H9903', '我的申诉', 'W', '', 'menu', '/platform/appeal/mine/h5', 'data-pjax', 'records', NULL, 1, 0, 'h5.appeal.mine', NULL, 9903, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '民主管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.appeal.mine' OR `path` = 'H9903');
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'a0e9c006000000000000000000000004', 'a0e9c006000000000000000000000001', 'H9901H9904', '申诉受理', 'S', '', 'menu', '/platform/appeal/accept/h5', 'data-pjax', 'todo-list-o', NULL, 1, 0, 'h5.appeal.accept', NULL, 9904, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '民主管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.appeal.accept' OR `path` = 'H9904');
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'a0e9c006000000000000000000000005', 'a0e9c006000000000000000000000001', 'H9901H9905', '申诉执行', 'S', '', 'menu', '/platform/appeal/execute/h5', 'data-pjax', 'passed', NULL, 1, 0, 'h5.appeal.execute', NULL, 9905, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '民主管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.appeal.execute' OR `path` = 'H9905');
UPDATE `sys_menu`
SET `href` = '/platform/appeal/h5',
`hasChildren` = 1,
`isRecommendService` = 1,
`updatedAt` = @now
WHERE `permission` = 'h5.appeal';
UPDATE `sys_menu`
SET `parentId` = 'a0e9c006000000000000000000000001',
`path` = CONCAT('H9901', RIGHT(`path`, 5)),
`isRecommendService` = 0,
`updatedAt` = @now
WHERE `permission` IN ('h5.appeal.write', 'h5.appeal.mine', 'h5.appeal.accept', 'h5.appeal.execute');
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('h5.appeal', 'h5.appeal.write', 'h5.appeal.mine', 'h5.appeal.accept', 'h5.appeal.execute')
WHERE r.`code` = 'SYSADMIN'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('h5.appeal', 'h5.appeal.write', 'h5.appeal.mine')
WHERE r.`code` IN ('SYSADMIN', 'MEMBER')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('h5.appeal', 'h5.appeal.accept', 'h5.appeal.execute')
WHERE r.`code` = 'APPEAL_COMMITTEE_MEMBER'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
/* 分工会管理员不需要权限
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` IN ('h5.appeal', 'h5.appeal.execute')
WHERE r.`code` = 'BRANCH_UNION_ADMIN'
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);*/
UPDATE `wf_process_define`
SET `content` = REPLACE(`content`, '"form": "/platform/appeal/accept",', '"form": "/platform/appeal/accept", "h5form": "/platform/appeal/accept/h5",'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND `content` LIKE '%"id": "appealAccept"%'
AND `content` LIKE '%"form": "/platform/appeal/accept"%'
AND `content` NOT LIKE '%"h5form": "/platform/appeal/accept/h5"%';
UPDATE `wf_process_define`
SET `content` = REPLACE(`content`, '"form":"/platform/appeal/accept",', '"form":"/platform/appeal/accept","h5form":"/platform/appeal/accept/h5",'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND `content` LIKE '%"id":"appealAccept"%'
AND `content` LIKE '%"form":"/platform/appeal/accept"%'
AND `content` NOT LIKE '%"h5form":"/platform/appeal/accept/h5"%'
AND `content` NOT LIKE '%"h5form": "/platform/appeal/accept/h5"%';
UPDATE `wf_process_define`
SET `content` = REPLACE(`content`, '"form": "/platform/appeal/execute",', '"form": "/platform/appeal/execute", "h5form": "/platform/appeal/execute/h5",'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND `content` LIKE '%"id": "appealExecute"%'
AND `content` LIKE '%"form": "/platform/appeal/execute"%'
AND `content` NOT LIKE '%"h5form": "/platform/appeal/execute/h5"%';
UPDATE `wf_process_define`
SET `content` = REPLACE(`content`, '"form":"/platform/appeal/execute",', '"form":"/platform/appeal/execute","h5form":"/platform/appeal/execute/h5",'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND `content` LIKE '%"id":"appealExecute"%'
AND `content` LIKE '%"form":"/platform/appeal/execute"%'
AND `content` NOT LIKE '%"h5form":"/platform/appeal/execute/h5"%'
AND `content` NOT LIKE '%"h5form": "/platform/appeal/execute/h5"%';
UPDATE `wf_process_define`
SET `h5InstanceUrl` = IFNULL(NULLIF(`h5InstanceUrl`, ''), '/platform/appeal/write/h5'),
`h5InstanceViewUrl` = IFNULL(NULLIF(`h5InstanceViewUrl`, ''), '/platform/appeal/mine/h5'),
`updatedAt` = @now
WHERE `name` = 'SSGL'
AND (IFNULL(`h5InstanceUrl`, '') = '' OR IFNULL(`h5InstanceViewUrl`, '') = '');
UPDATE `wf_process_task` t
JOIN `wf_process_instance` ins ON ins.`id` = t.`processInstanceId`
JOIN `wf_process_define` def ON def.`id` = ins.`processDefineId`
SET t.`h5FormKey` = '/platform/appeal/accept/h5',
t.`updatedAt` = @now
WHERE def.`name` = 'SSGL'
AND t.`taskName` = 'appealAccept'
AND IFNULL(t.`h5FormKey`, '') = '';
UPDATE `wf_process_task` t
JOIN `wf_process_instance` ins ON ins.`id` = t.`processInstanceId`
JOIN `wf_process_define` def ON def.`id` = ins.`processDefineId`
SET t.`h5FormKey` = '/platform/appeal/execute/h5',
t.`updatedAt` = @now
WHERE def.`name` = 'SSGL'
AND t.`taskName` = 'appealExecute'
AND IFNULL(t.`h5FormKey`, '') = '';
@@ -0,0 +1,18 @@
-- 离退休人员档案手机端初始化脚本
-- 说明:PC端离退休人员档案已部署时,只需要执行本脚本新增手机端入口和权限,菜单挂载到H5端已有的人员管理模块。
SET @now := CAST(UNIX_TIMESTAMP(NOW()) * 1000 AS UNSIGNED);
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'b1f00006000000000000000000000003', '', 'H9913', '离退休人员档案', 'L', NULL, 'menu', '/platform/retired/list/h5', 'data-pjax', 'manager-o', NULL, 1, 0, 'h5.retired.list', NULL, 9913, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '人员管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.retired.list' OR `path` = 'H9913');
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` = 'h5.retired.list'
WHERE r.`code` IN ('SYSADMIN', 'SCHOOL_UNION_ADMIN')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
@@ -0,0 +1,18 @@
-- 单身教职工管理手机端初始化脚本
-- 说明:PC端单身教职工管理已部署时,只需要执行本脚本新增手机端入口和权限,菜单挂载到H5端已有的人员管理模块。
SET @now := CAST(UNIX_TIMESTAMP(NOW()) * 1000 AS UNSIGNED);
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'b1f00006000000000000000000000001', '', 'H9911', '单身教职工管理', 'D', NULL, 'menu', '/platform/singleTeacher/ledger/h5', 'data-pjax', 'friends-o', NULL, 1, 0, 'h5.singleTeacher.ledger', NULL, 9911, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '人员管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.singleTeacher.ledger' OR `path` = 'H9911');
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` = 'h5.singleTeacher.ledger'
WHERE r.`code` IN ('SYSADMIN', 'SCHOOL_UNION_ADMIN')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
@@ -0,0 +1,18 @@
-- 30教龄教职工管理手机端初始化脚本
-- 说明:PC端30教龄教职工管理已部署时,只需要执行本脚本新增手机端入口和权限,菜单挂载到H5端已有的人员管理模块。
SET @now := CAST(UNIX_TIMESTAMP(NOW()) * 1000 AS UNSIGNED);
INSERT INTO `sys_menu` (`id`, `parentId`, `path`, `name`, `initialPinyinName`, `aliasName`, `type`, `href`, `target`, `icon`, `picIcon`, `showit`, `disabled`, `permission`, `note`, `location`, `hasChildren`, `createdBy`, `createdAt`, `updatedBy`, `updatedAt`, `delFlag`, `platform`, `moduleId`, `isRecommendApp`, `isRecommendService`)
SELECT 'b1f00006000000000000000000000002', '', 'H9912', '30教龄教职工管理', 'S', NULL, 'menu', '/platform/thirtyTeach/manage/h5', 'data-pjax', 'medal-o', NULL, 1, 0, 'h5.thirtyTeach.manage', NULL, 9912, 0, '', @now, '', @now, 0, 'H5', module.`id`, 0, 0
FROM `sys_module` module
WHERE module.`platform` = 'H5'
AND module.`name` = '人员管理'
AND NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission` = 'h5.thirtyTeach.manage' OR `path` = 'H9912');
INSERT INTO `sys_role_menu` (`roleId`, `menuId`)
SELECT r.`id`, m.`id`
FROM `sys_role` r
JOIN `sys_menu` m ON m.`permission` = 'h5.thirtyTeach.manage'
WHERE r.`code` IN ('SYSADMIN', 'SCHOOL_UNION_ADMIN')
AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rm WHERE rm.`roleId` = r.`id` AND rm.`menuId` = m.`id`);
+89 -9
View File
@@ -1,17 +1,85 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration scan="false" scanPeriod="60000" debug="false">
<!-- 定义日志文件的存储路径 -->
<!-- 日志存储路径 -->
<property name="LOG_HOME" value="./logs"/>
<!-- 控制台输出配置 -->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- INFO级别日志文件配置 -->
<!--
#################################################################################
# #
# 全文输出日志(一个文件存储)start #
# #
#################################################################################
-->
<!-- 所有级别日志写入同一个文件 -->
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/app.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>300</maxHistory>
</rollingPolicy>
</appender>
<!-- 框架日志级别(按需调整) -->
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="org.quartz" level="INFO"/>
<logger name="org.nutz" level="DEBUG"/>
<!-- root logger:DEBUG 级别,输出到控制台和全量文件 -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ALL_FILE"/>
</root>
<!--
#################################################################################
# #
# 全文输出日志(一个文件存储)end #
# #
#################################################################################
-->
<!--
#################################################################################
# #
# debug、info、error分文件输出 start #
# #
#################################################################################
-->
<!-- DEBUG级别日志文件配置 -->
<!--<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/debug.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/debug-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>300</maxHistory>
</rollingPolicy>
</appender>
&lt;!&ndash; INFO级别日志文件配置 &ndash;&gt;
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/info.log</file>
<encoder>
@@ -24,11 +92,11 @@
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxHistory>300</maxHistory>
</rollingPolicy>
</appender>
<!-- ERROR级别日志文件配置 -->
&lt;!&ndash; ERROR级别日志文件配置 &ndash;&gt;
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/error.log</file>
<encoder>
@@ -41,19 +109,31 @@
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
<maxHistory>300</maxHistory>
</rollingPolicy>
</appender>
<logger name="java" additivity="false" />
&lt;!&ndash; 框架日志级别 &ndash;&gt;
&lt;!&ndash; <logger name="java" additivity="false" />&ndash;&gt;
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="org.quartz" level="INFO"/>
<logger name="org.nutz" level="DEBUG"/>
<!-- 日志级别和appender的关联 -->
&lt;!&ndash; 日志级别和appender的关联 &ndash;&gt;
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="DEBUG_FILE"/>
<appender-ref ref="INFO_FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</root>-->
<!--
#################################################################################
# #
# debug、info、error分文件输出 end #
# #
#################################################################################
-->
</configuration>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 2.1 MiB

@@ -0,0 +1,296 @@
/**
*Desc:
*Create by: jug
*Create time:2023/11/20/16:49
*/
<template>
<div>
<el-form :model="formData" :rules="formRules" label-width="0" ref="form" class="flow-task-form">
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">
<el-form-item prop="loginname">
<el-input v-model="formData.loginname" maxlength="120" size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="姓名">
<el-form-item prop="username">
<el-input v-model="formData.username" maxlength="100" size="small"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="籍贯">
<el-form-item prop="nativePlace">
<el-input v-model="formData.nativePlace" maxlength="100" placeholder="请输入籍贯"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="性别">
<el-form-item prop="sex">
<el-radio-group v-model="formData.sex" size="small">
<el-radio border label="男">男</el-radio>
<el-radio border label="女">女</el-radio>
</el-radio-group>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="出生日期">
<el-form-item prop="birthday">
<el-date-picker v-model="formData.birthday" type="date"
placeholder="请选择出生日期"
value-format="yyyy-MM-dd"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="身份证号码">
<el-form-item prop="idCard">
<el-input v-model="formData.idCard" maxlength="30" placeholder="请输入身份证号码"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="政治面貌">
<el-form-item prop="political">
<dict-select style="width: 100%" placeholder="请选择政治面貌" v-model="formData.political"
code="USER_POLITICAL"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="参加工作时间">
<el-form-item prop="arrivalAtSchoolDate">
<el-input v-model="formData.arrivalAtSchoolDate" maxlength="20" placeholder="请输入参加工作时间"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="单位">
<el-form-item prop="unitId">
<el-select clearable filterable placeholder="请选择单位" style="width: 100%"
v-model="formData.unitId" @change="handleUnitChange">
<el-option :key="item.id" :label="item.name" :value="item.id"
v-for="item in units"></el-option>
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="工会">
<el-form-item prop="unionName">
<el-input v-model="formData.unionName" readonly placeholder="系统自动显示"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="职务">
<el-form-item prop="position">
<el-input v-model="formData.position" maxlength="50" placeholder="请输入职务"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="职称">
<el-form-item prop="professionalTitle">
<el-input v-model="formData.professionalTitle" maxlength="50" placeholder="请输入职称"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="退休时间">
<el-form-item prop="retireDate">
<el-date-picker v-model="formData.retireDate" type="date"
placeholder="请选择退休时间"
value-format="yyyy-MM-dd"
style="width: 100%"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="电话">
<el-form-item prop="mobile">
<el-input v-model="formData.mobile" maxlength="32" placeholder="请输入电话"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="工龄">
<el-form-item>
<el-input :value="workAgeText(formData.arrivalAtSchoolDate)" readonly placeholder="系统自动计算"></el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="在职状态">
<el-form-item prop="userState">
<dict-select v-model="formData.userState" code="USER_STATE" style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="人员类型">
<el-form-item prop="personType">
<dict-select v-model="formData.personType" code="USER_PERSON_TYPE" style="width: 100%"></dict-select>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
</el-form>
<el-row :gutter="10" class="mt10" type="flex" justify="end">
<el-button @click="doSubmit" type="primary">确定</el-button>
</el-row>
</div>
</template>
<script>
module.exports = {
name: "userEdit",
data() {
return {
userId: null,
units: [],
formData: this.defaultFormData(),
formRules: {
loginname: [{required: true, message: "必填", trigger: ["change", "blur"]}],
username: [{required: true, message: "必填", trigger: ["change", "blur"]}],
sex: [{required: true, message: "必填", trigger: ["change", "blur"]}],
userState: [{required: true, message: "必填", trigger: ["change", "blur"]}],
personType: [{required: true, message: "必填", trigger: ["change", "blur"]}]
}
}
},
components: {
'dict-select': httpVueLoader('/components/plugins/sysDict/DictSelect.vue?v=1.0.0')
},
methods: {
// 新增和重置共用默认值,避免页面直接修改同一个对象引用。
defaultFormData() {
return {
userState: '退休',
personType: '离退休人员',
families: []
}
},
doSubmit() {
this.$refs.form.validate(async valid => {
if (valid) {
const {code, msg} = await $.post('/platform/retired/list/doSubmit', {
user: JSON.stringify(this.formData),
userId: this.userId
})
if (code === 0) {
this.$message.success(msg)
this.$emit('finish')
} else {
this.$message.warning(msg)
}
}
})
},
reset() {
this.$set(this, "userId", null)
this.$set(this, "formData", this.defaultFormData())
this.$nextTick(() => {
if (this.$refs.form) {
this.$refs.form.clearValidate()
}
})
},
async getInfo(id) {
this.$set(this, "userId", id)
const resp = await $.post('/platform/retired/list/userInfo', {userId: this.userId})
const data = this.normalizeUserData(resp.data || {})
this.$set(this, "formData", data)
this.$nextTick(() => {
if (this.$refs.form) {
this.$refs.form.clearValidate()
}
})
},
handleUnitChange(unitId) {
const unit = this.units.find(item => item.id === unitId)
this.$set(this.formData, "unitName", unit ? unit.name : null)
const unionId = unit ? (unit.unionId || unit.unionid || null) : null
const unionName = unit ? (unit.unionName || unit.unionname || null) : null
this.$set(this.formData, "unionId", unionId)
this.$set(this.formData, "unionName", unionName)
},
addFamily() {
const families = (this.formData.families || []).concat([{}])
this.$set(this.formData, "families", families)
},
removeFamily(index) {
const families = (this.formData.families || []).slice()
families.splice(index, 1)
this.$set(this.formData, "families", families)
},
async loadUnits() {
const units = await this.$businessTool.listUnit()
this.$set(this, "units", units || [])
},
// 工龄不落库,根据参加工作时间实时计算,兼容 yyyy、yyyy-MM、yyyy-MM-dd 三种输入。
workAgeText(val) {
const start = this.parseWorkDate(val)
if (!start) {
return ""
}
const today = new Date()
let years = today.getFullYear() - start.getFullYear()
if (today.getMonth() < start.getMonth() ||
(today.getMonth() === start.getMonth() && today.getDate() < start.getDate())) {
years = years - 1
}
if (years < 0) {
years = 0
}
return years + "年"
},
parseWorkDate(val) {
if (!val) {
return null
}
const parts = String(val).split("-")
const year = Number(parts[0])
const month = parts.length > 1 ? Number(parts[1]) : 1
const day = parts.length > 2 ? Number(parts[2]) : 1
if (!year || !month || !day) {
return null
}
const date = new Date(year, month - 1, day)
if (isNaN(date.getTime())) {
return null
}
return date
},
normalizeUserData(user) {
const data = Object.assign(this.defaultFormData(), user)
// 详情数据可能来自视图或实体,统一把大小写差异字段整理成页面绑定的驼峰字段。
const fieldMap = {
idcard: "idCard",
idcardtype: "idCardType",
unitid: "unitId",
unitname: "unitName",
unionid: "unionId",
unionname: "unionName",
uniongroupid: "unionGroupId",
uniongroupname: "unionGroupName",
joinpartydate: "joinPartyDate",
nativeplace: "nativePlace",
academicdegree: "academicDegree",
professionaltitle: "professionalTitle",
arrivalatschooldate: "arrivalAtSchoolDate",
teachingtime: "teachingTime",
userstate: "userState",
persontype: "personType",
retiredate: "retireDate",
membertime: "memberTime",
personaldata: "personalData",
campusname: "campusName",
threeunitname: "threeUnitName",
retiredgroupname: "retiredGroupName",
retiredpartybranchname: "retiredPartyBranchName"
}
Object.keys(fieldMap).forEach(key => {
if ((data[fieldMap[key]] === undefined || data[fieldMap[key]] === null) && user[key] !== undefined) {
this.$set(data, fieldMap[key], user[key])
}
})
if (typeof data.families === "string") {
try {
this.$set(data, "families", JSON.parse(data.families))
} catch (e) {
this.$set(data, "families", [])
}
} else if (!data.families) {
this.$set(data, "families", [])
}
return data
}
},
created() {
this.loadUnits()
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,173 @@
/**
*Desc:
*Create by: jug
*Create time:2023/7/25/9:14
*/
<template>
<div>
<el-descriptions :column="3" border>
<el-descriptions-item label="工号">{{ emptyText(formData.loginname) }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ emptyText(formData.username) }}</el-descriptions-item>
<el-descriptions-item label="籍贯">{{ emptyText(formData.nativePlace) }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ emptyText(formData.sex) }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ formatDate(formData.birthday) }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ emptyText(formData.idCard) }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ emptyText(formData.political) }}</el-descriptions-item>
<el-descriptions-item label="参加工作时间">{{ displayDate(formData.arrivalAtSchoolDate) }}</el-descriptions-item>
<el-descriptions-item label="单位">{{ emptyText(formData.unitName) }}</el-descriptions-item>
<el-descriptions-item label="工会">{{ emptyText(formData.unionName) }}</el-descriptions-item>
<el-descriptions-item label="职务">{{ emptyText(formData.position) }}</el-descriptions-item>
<el-descriptions-item label="职称">{{ emptyText(formData.professionalTitle) }}</el-descriptions-item>
<el-descriptions-item label="退休时间">{{ formatDate(formData.retireDate) }}</el-descriptions-item>
<el-descriptions-item label="电话">{{ emptyText(formData.mobile) }}</el-descriptions-item>
<el-descriptions-item label="工龄">{{ workAgeText(formData.arrivalAtSchoolDate) || '暂无' }}</el-descriptions-item>
<el-descriptions-item label="在职状态">{{ emptyText(formData.userState) }}</el-descriptions-item>
<el-descriptions-item label="人员类型">{{ emptyText(formData.personType) }}</el-descriptions-item>
</el-descriptions>
<slot></slot>
</div>
</template>
<script>
module.exports = {
name: "userInfo",
props: {
id: {
type: String,
required: true
}
},
data() {
return {
formData: {}
}
},
methods: {
formatDate(val) {
if (val) {
return moment(val).format('YYYY-MM-DD')
}
return '暂无'
},
displayDate(val) {
if (!val) {
return '暂无'
}
return String(val)
},
emptyText(val) {
if (val === undefined || val === null || val === '') {
return '暂无'
}
return val
},
// 工龄不落库,根据参加工作时间实时计算,兼容 yyyy、yyyy-MM、yyyy-MM-dd 三种输入。
workAgeText(val) {
const start = this.parseWorkDate(val)
if (!start) {
return ""
}
const today = new Date()
let years = today.getFullYear() - start.getFullYear()
if (today.getMonth() < start.getMonth() ||
(today.getMonth() === start.getMonth() && today.getDate() < start.getDate())) {
years = years - 1
}
if (years < 0) {
years = 0
}
return years + "年"
},
parseWorkDate(val) {
if (!val) {
return null
}
const parts = String(val).split("-")
const year = Number(parts[0])
const month = parts.length > 1 ? Number(parts[1]) : 1
const day = parts.length > 2 ? Number(parts[2]) : 1
if (!year || !month || !day) {
return null
}
const date = new Date(year, month - 1, day)
if (isNaN(date.getTime())) {
return null
}
return date
},
getInfo() {
if (this.id) {
$.post('/platform/retired/list/userInfo', {userId: this.id}).then(res => {
this.$set(this, "formData", this.normalizeUserData(res.data || {}))
})
} else {
this.$set(this, "formData", {})
}
},
normalizeUserData(user) {
const data = Object.assign({}, user)
// 兼容视图查询和实体查询返回字段大小写不一致的情况,保证查看页字段能正常回显。
const fieldMap = {
idcard: "idCard",
idcardtype: "idCardType",
unitid: "unitId",
unitname: "unitName",
unionid: "unionId",
unionname: "unionName",
uniongroupid: "unionGroupId",
uniongroupname: "unionGroupName",
joinpartydate: "joinPartyDate",
nativeplace: "nativePlace",
academicdegree: "academicDegree",
professionaltitle: "professionalTitle",
arrivalatschooldate: "arrivalAtSchoolDate",
teachingtime: "teachingTime",
userstate: "userState",
persontype: "personType",
retiredate: "retireDate",
membertime: "memberTime",
personaldata: "personalData",
campusname: "campusName",
threeunitname: "threeUnitName",
retiredgroupname: "retiredGroupName",
retiredpartybranchname: "retiredPartyBranchName"
}
Object.keys(fieldMap).forEach(key => {
if ((data[fieldMap[key]] === undefined || data[fieldMap[key]] === null) && user[key] !== undefined) {
this.$set(data, fieldMap[key], user[key])
}
})
if (typeof data.families === "string") {
try {
this.$set(data, "families", JSON.parse(data.families))
} catch (e) {
this.$set(data, "families", [])
}
} else if (!data.families) {
this.$set(data, "families", [])
}
return data
}
},
watch: {
id: {
handler: function (val) {
this.getInfo()
},
immediate: true
}
},
created() {
}
}
</script>
<style scoped>
</style>
@@ -0,0 +1,101 @@
<template>
<div class="v-tree-layout">
<div class="shrink" :style="'left:' + (showTree ? 'calc(20% - 15px)' : '0')" @click="shrink">
<i v-if="!showTree" class="el-icon-arrow-right"></i>
<i v-else class="el-icon-arrow-left"></i>
</div>
<div class="v-tree-layout-left" :style="{width: showTree ? '20%' : '0'}">
<slot name="tree"></slot>
</div>
<div class="v-tree-layout-right" :style="{width: showTree ? '80%' : '100%'}">
<slot></slot>
</div>
</div>
</template>
<script>
module.exports = {
props: {},
data() {
return {
showTree: true
}
},
methods: {
shrink() {
this.showTree = !this.showTree
}
}
}
</script>
<style>
.shrink {
position: absolute;
height: 30px;
width: 30px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 15px;
background-color: white;
z-index: 99;
top: 0;
bottom: 0;
margin: auto;
box-shadow: 0 0 5px rgb(200, 200, 200);
cursor: pointer;
transition: all 500ms;
}
.shrink:hover {
box-shadow: 0 0 10px rgb(150, 150, 150);
}
.v-tree-layout-left::-webkit-scrollbar {
width: 4px;
height: 10px;
}
.v-tree-layout-left::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #dcdcdc;
}
.v-tree-layout-left::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px transparent;
border-radius: 10px;
background: transparent;
}
.v-tree-layout {
width: 100%;
height: 100%;
position: relative;
display: flex;
flex-direction: row;
}
.v-tree-layout-left {
width: 20%;
}
.v-tree-layout-left,
.v-tree-layout-left .el-tree {
background-color: #ffffff;
}
.v-tree-layout-right {
width: 80%;
border-left: 1px solid rgb(240, 240, 240);
}
.v-tree-layout-left,
.v-tree-layout-right {
height: 100%;
box-sizing: border-box;
overflow: auto;
transition: all 500ms;
position: relative;
}
</style>
@@ -3,6 +3,12 @@
<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="select">
<el-radio-group v-model="formData.select" size="small">
<el-radio label="need" border>是</el-radio>
<el-radio label="notNeeded" border>否</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<snaker-flow-task-form-action @task-action="handleTaskAction" @cancel="handleCancel"></snaker-flow-task-form-action>
</div>
@@ -18,8 +24,16 @@
},
}
},
mounted() {
this.$set(this.formData, "select", "")
},
methods: {
handleTaskAction(val) {
// 同意流转时必须带流程分支变量 select,供 HDBX 条件线判断是否进入副主席审核。
if (val.submitType === 1 && !this.formData.select) {
this.$message.warning("请选择是否需要副主席审核")
return
}
this.$refs.formRef.validate(valid => {
if (valid) {
console.log(val)
@@ -127,6 +127,12 @@ layout("/layouts/platform.html"){
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<pc-signature v-model="formData.tf_userSign"></pc-signature>
</el-form-item>
<el-form-item label="是否需要副主席审核" prop="select">
<el-radio-group v-model="formData.select" size="small">
<el-radio label="need" border>是</el-radio>
<el-radio label="notNeeded" border>否</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<el-row type="flex" justify="end">
<el-button @click="$refs.guava.index()" size="small">取消</el-button>
@@ -194,11 +200,17 @@ layout("/layouts/platform.html"){
processTaskId: row.taskId,
taskName: row.curTaskName
}
this.$set(this.formData, "select", "")
this.$refs.infoRef.onOpen(row)
})
},
handleTaskAction(val) {
// 同意流转时必须带流程分支变量 select,供 HDBX 条件线判断是否进入副主席审核。
if (val === 1 && !this.formData.select) {
this.$message.warning("请选择是否需要副主席审核")
return
}
this.$refs.formRef.validate((valid) => {
if (valid) {
this.$confirm("您确定要提交吗?", "提示", {
@@ -51,7 +51,9 @@ layout("/layouts/platform.html"){
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item label="职称">
{{formData.professionalTitle}}
</el-descriptions-item>
<el-descriptions-item label="子女姓名">
<el-form-item prop="childrenName"
@@ -132,8 +134,7 @@ layout("/layouts/platform.html"){
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="户口簿照片" :span="2">
<el-form-item prop="huKouFiles"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-form-item prop="huKouFiles">
<file-upload :upload_number="10" :value.sync="formData.huKouFiles"
upload_result_type="url"
upload_text="请上传户口首页、户主页、父母和子女页"
@@ -337,22 +338,38 @@ layout("/layouts/platform.html"){
return resp.data
}
},
async ensureUserLoaded() {
if (this.$store.state.user && this.$store.state.user.id) {
return
}
const resp = await $.get("/platform/sys/user/getLogonUser")
if (resp.code === 0) {
window.sessionStorage.setItem("user", JSON.stringify(resp.data))
this.$store.commit("setUser", resp.data)
}
},
init() {
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
if (!this.formData.professionalTitle) {
this.$set(this.formData, "professionalTitle", (this.$store.state.user && this.$store.state.user.professionalTitle) || "")
}
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
const user = this.$store.state.user || {}
const unit = user.unit || {}
const union = user.union || {}
this.formData = {
userId: id,
userName: username,
loginName: loginname,
unitName: unit.name,
unitId: unit.id,
unionName: union.name,
unionId: union.id,
mobile: mobile,
userId: user.id,
userName: user.username,
loginName: user.loginname,
professionalTitle: user.professionalTitle || "",
unitName: unit.name || "",
unitId: unit.id || "",
unionName: union.name || "",
unionId: union.id || "",
mobile: user.mobile,
}
}
@@ -360,6 +377,7 @@ layout("/layouts/platform.html"){
}
},
async created() {
await this.ensureUserLoaded()
this.init()
this.getEnrollmentRegistrationPlan()
@@ -9,6 +9,7 @@ const ENROLLMENT_REGISTRATION_INFO = {
<el-descriptions :column="3" border>
<el-descriptions-item label="监护人(教工)姓名">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="工号">{{viewData.loginName}}</el-descriptions-item>
<el-descriptions-item label="职称">{{viewData.professionalTitle}}</el-descriptions-item>
<el-descriptions-item label="手机号码">{{viewData.mobile}}</el-descriptions-item>
<el-descriptions-item label="所在单位">{{viewData.unitName}}</el-descriptions-item>
<el-descriptions-item label="监护人与学生关系">
@@ -41,14 +41,32 @@ layout("/layouts/platform.html"){
<el-option v-for="item in unitOptions" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="职称">
<el-select clearable filterable placeholder="请选择职称"
style="width: 100%;"
v-model="pageForm.professionalTitle">
<el-option :label="item.name" :value="item.code"
v-for="item in dict.type.TECHNICAL_TITLE_LEVEL"></el-option>
</el-select>
</search-item>
<search-item label="是否解决">
<el-select clearable placeholder="请选择是否解决"
style="width: 100%;"
v-model="pageForm.solved">
<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">
<table-tool label="申请列表">
<el-button @click="doExportExcel" size="mini" type="primary">导出汇总名单
<el-button @click="doBatchSetSolved" size="small" type="primary">一键设置已解决
</el-button>
<el-button @click="doExportZip" size="mini" type="primary">导出附件zip
<el-button @click="doExportExcel" icon="el-icon-download" size="small" type="primary">导出汇总名单
</el-button>
<el-button @click="doExportZip" icon="el-icon-download" size="small" type="primary">导出附件zip
</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%">
@@ -58,6 +76,7 @@ layout("/layouts/platform.html"){
<el-table-column prop="loginName" label="工号"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="unitName" label="所属单位"></el-table-column>
<el-table-column prop="professionalTitle" label="职称"></el-table-column>
<el-table-column prop="mobile" label="手机号码"></el-table-column>
<el-table-column prop="registrationType" label="登记类型">
<template v-slot="{row}">
@@ -66,9 +85,20 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column prop="applyTime" label="填报时间"></el-table-column>
<el-table-column prop="solved" label="是否解决">
<template v-slot="{row}">
<el-tag :type="isSolved(row) ? 'success' : 'info'">
{{isSolved(row) ? '已解决' : '未解决'}}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" header-align="center" label="操作"
width="300px">
<template scope="{row}">
<el-button @click="doUpdateSolved(row, !isSolved(row))" size="mini"
:type="isSolved(row) ? 'success' : 'info'">
{{isSolved(row) ? '已解决' : '未解决'}}
</el-button>
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="doDelete(row)" size="mini" type="danger"
v-if="$auth.hasRoleOr(['SYSADMIN'])">删除
@@ -91,7 +121,7 @@ layout("/layouts/platform.html"){
new Vue({
el: "#app",
store,
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL"],
dicts: ["ENROLLMENT_REGISTRATION_TYPE", "ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP", "ENROLLMENT_REGISTRATION_CHILDREN_PLAN_SCHOOL", "TECHNICAL_TITLE_LEVEL"],
mixins: [initTableMixins],
data() {
return {
@@ -134,6 +164,44 @@ layout("/layouts/platform.html"){
data: JSON.stringify(this.pageForm)
})
},
isSolved(row) {
return row.solved === true || row.solved === 1 || row.solved === "1"
},
// 切换单条记录解决状态,历史空值在页面上按未解决处理。
doUpdateSolved(row, solved) {
this.$confirm("确定要切换解决状态吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/enrollmentRegistration/summary/doUpdateSolved", {
id: row.id,
solved: solved
}).then((resp) => {
if (resp.code === 0) {
this.$set(row, "solved", solved)
this.$message.success("操作成功")
}
})
})
},
// 按当前筛选条件批量设置,后端会更新符合条件的全部记录。
doBatchSetSolved() {
this.$confirm("确定将当前筛选条件下的数据全部设置为已解决吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/enrollmentRegistration/summary/doBatchSetSolved", {
data: JSON.stringify(this.pageForm)
}).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg || "操作成功")
this.doSearch()
}
})
})
},
openView(row) {
this.$refs.guava.view(() => {
this.showApprovalForm = false
@@ -39,10 +39,10 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.personTypes" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="编制类别">
<dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>
</search-item>
<!-- <search-item label="编制类别">-->
<!-- <dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"-->
<!-- code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
@@ -106,7 +106,7 @@ layout("/layouts/platform.html"){
{ label: "出生年月", prop: "birthday" },
{ label: "在职状态", prop: "userState", sortable: true },
{ label: "教职工类别", prop: "personType", sortable: true },
{ label: '编制类别', prop: 'preparedBy', sortable: true },
// { label: '编制类别', prop: 'preparedBy', sortable: true },
{ label: "所属工会", prop: "unionName" },
{ label: "所属单位", prop: "unitName" },
],
@@ -163,7 +163,7 @@ layout("/layouts/platform.html"){
const pageForm = clone(this.pageForm)
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
// pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
this.$axios.post('/platform/fundMember/batchJoin/pageData', pageForm)
.then(res => {
this.tableData = res.data.list
@@ -26,12 +26,7 @@ layout("/layouts/platform.html"){
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="工号"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="isJoin" label="申请类型">
<template slot-scope="{row}">
<el-tag v-if="row.isJoin" size="small">加入</el-tag>
<el-tag v-else size="small" type="danger">退出</el-tag>
</template>
</el-table-column>
<el-table-column prop="aidFundMemberType" label="会员类别"></el-table-column>
<el-table-column prop="submitTime" label="申请时间"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
@@ -1,62 +1,61 @@
const fundMemberInfo = {
template: /*language=HTML*/ `
<div>
<div class="process-title">
申请信息
<el-link type="primary" @click="openChart">点击查看流程图</el-link>
</div>
<el-descriptions :column="2" border>
<el-descriptions-item label="姓名">{{viewData.userName}}</el-descriptions-item>
<el-descriptions-item label="工号">{{viewData.loginName}}</el-descriptions-item>
<el-descriptions-item label="性别">{{viewData.sex}}</el-descriptions-item>
<el-descriptions-item label="出生年月">{{viewData.birthday}}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{viewData.idCard}}</el-descriptions-item>
<el-descriptions-item label="参加工作时间">{{viewData.joinWorkTime}}</el-descriptions-item>
<el-descriptions-item label="退休时间">{{viewData.retireTime}}</el-descriptions-item>
<el-descriptions-item label="家庭住址">{{viewData.address}}</el-descriptions-item>
<el-descriptions-item label="手机电话">{{viewData.mobile}}</el-descriptions-item>
<el-descriptions-item label="住宅号码">{{viewData.homePhone}}</el-descriptions-item>
<el-descriptions-item label="照片">
<img :src="viewData.avatar" alt="" style="width: 120px;height: 150px" v-if="viewData.avatar">
</el-descriptions-item>
</el-descriptions>
<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="办理意见" v-if="!task.ext.isFirstTaskNode">{{
task.taskFormData.opinion }}
</el-descriptions-item>
</el-descriptions>
</div>
</template>
<slot></slot>
<snaker-chart ref="snakerChartRef"></snaker-chart>
</div>
`,
template: /*language=HTML*/ [
'<div>',
' <div class="process-title">',
' 申请信息',
' <el-link type="primary" @click="openChart" v-if="row && row.instanceId">点击查看流程图</el-link>',
' </div>',
' <el-descriptions :column="2" border>',
' <el-descriptions-item label="姓名">{{ viewData.userName || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="工号">{{ viewData.loginName || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="出生年月">{{ viewData.birthday || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="性别">{{ viewData.sex || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="籍贯">{{ viewData.nativePlace || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="家庭住址">{{ viewData.address || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="健康状况">{{ viewData.healthStatus || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="学历">{{ viewData.education || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="联系电话">{{ viewData.mobile || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="入职时间">{{ viewData.joinWorkTime || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="身份证号码" :span="2">{{ viewData.idCard || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="会员类别">{{ viewData.aidFundMemberType || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="退休时间">{{ viewData.retireTime || \'-\' }}</el-descriptions-item>',
' <el-descriptions-item label="家庭主要成员" :span="2">',
' <el-table :data="viewData.families || []" border size="small">',
' <el-table-column label="序号" width="80" align="center">',
' <template slot-scope="scope">{{ scope.row.sequence || scope.$index + 1 }}</template>',
' </el-table-column>',
' <el-table-column prop="name" label="姓名" min-width="160"></el-table-column>',
' <el-table-column prop="age" label="年龄" width="120"></el-table-column>',
' <el-table-column prop="relation" label="与本人关系" min-width="180"></el-table-column>',
' </el-table>',
' </el-descriptions-item>',
' <el-descriptions-item label="备注" :span="2">{{ viewData.remark || \'-\' }}</el-descriptions-item>',
' </el-descriptions>',
'',
' <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="办理意见" v-if="!task.ext.isFirstTaskNode">{{ task.taskFormData.opinion }}</el-descriptions-item>',
' </el-descriptions>',
' </div>',
' </template>',
' <slot></slot>',
' <snaker-chart ref="snakerChartRef"></snaker-chart>',
'</div>'
].join(''),
store,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data(){
@@ -72,21 +71,29 @@ const fundMemberInfo = {
onOpen(row) {
this.row = row
this.visible = true
this.viewData = Object.assign({}, row || {})
this.doneTasks = []
this.getInfo()
this.getDoneTasks()
},
// 获取申请信息
getInfo() {
if (!this.row || !this.row.id) {
return
}
this.$axios.post('/platform/fundMember/common/info', {id: this.row.id}).then((res) => {
if (res.code === 0) {
this.viewData = res.data
this.viewData = Object.assign({}, this.viewData, res.data || {})
}
})
},
// 获取已办任务审批记录
getDoneTasks() {
if (!this.row || !this.row.instanceId) {
return
}
this.$axios.post("/flow/common/doneTasks", {bizId: this.row.id}).then((res) => {
if (res.code === 0) {
this.doneTasks = res.data
@@ -96,6 +103,10 @@ const fundMemberInfo = {
// 查看流程图
openChart() {
if (!this.row || !this.row.instanceId) {
this.$message.warning("暂无流程信息")
return
}
this.$refs.snakerChartRef.onOpenFull(this.row.instanceProcessDefineId, this.row.instanceId)
}
}
@@ -17,12 +17,7 @@ layout("/layouts/platform.html"){
<el-table-column type="index" width="50px" label="序号" :index="indexMethod"></el-table-column>
<el-table-column prop="loginName" label="工号"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="isJoin" label="申请类型">
<template slot-scope="{row}">
<el-tag v-if="row.isJoin" size="small">加入</el-tag>
<el-tag v-else size="small" type="danger">退出</el-tag>
</template>
</el-table-column>
<el-table-column prop="aidFundMemberType" label="会员类别"></el-table-column>
<el-table-column prop="submitTime" label="申请时间"></el-table-column>
<el-table-column prop="taskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
@@ -34,7 +29,6 @@ layout("/layouts/platform.html"){
<el-table-column label="操作" fixed="right" width="300px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button @click="exportDocx(row.id)" size="mini" type="primary">导出</el-button>
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onEdit(row)"
size="mini" type="primary">
编辑
@@ -42,9 +36,10 @@ layout("/layouts/platform.html"){
<el-button v-if="row.canRevoke" @click="onRevoke(row)" size="mini" type="danger">撤回
</el-button>
<!-- v-if="row.taskKey === 'startTask' || !row.instanceId"-->
<el-button @click="onDelete(row.id)"
<el-button v-if="row.taskKey === 'startTask' || !row.instanceId" @click="onDelete(row.id)"
size="mini" type="danger">删除
</el-button>
<el-button @click="exportDocx(row.id)" size="mini" type="primary">导出</el-button>
</template>
</el-table-column>
</el-table>
@@ -39,14 +39,14 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.userStates" placeholder="请选择在职状态" @change="doSearch"
code="USER_STATE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="教职工类别">
<dict-select v-model="pageForm.personTypes" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="编制类别">
<dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>
<search-item label="会员类别">
<dict-select v-model="pageForm.aidFundMemberTypes" placeholder="请选择会员类别" @change="doSearch"
code="USER_AID_FUND_MEMBER_TYPE" multiple collapse-tags></dict-select>
</search-item>
<!-- <search-item label="编制类别">-->
<!-- <dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"-->
<!-- code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>-->
<!-- </search-item>-->
</search>
</el-card>
<el-card shadow="never">
@@ -78,6 +78,11 @@ layout("/layouts/platform.html"){
<el-tag v-if="row.isJoin" size="small">加入</el-tag>
<el-tag v-else size="small" type="danger">退出</el-tag>
</template>
<template v-else-if="column.prop === 'aidFundMemberType'" scope="{row}">
<dict-select v-model="row.aidFundMemberType" placeholder="请选择会员类别"
code="USER_AID_FUND_MEMBER_TYPE" style="width: 100%"
@change="onAidFundMemberTypeChange(row)"></dict-select>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="200px">
<template slot-scope="{row}">
@@ -113,8 +118,8 @@ layout("/layouts/platform.html"){
{ label: "性别", prop: "sex" },
{ label: "出生年月", prop: "birthday" },
{ label: "在职状态", prop: "userState", sortable: true },
{ label: "教职工类别", prop: "personType", sortable: true },
{ label: '编制类别', prop: 'preparedBy', sortable: true },
{ label: "会员类别", prop: "aidFundMemberType", sortable: true },
// { label: '编制类别', prop: 'preparedBy', sortable: true },
{ label: "所属工会", prop: "unionName" },
{ label: "所属单位", prop: "unitName" },
{ label: "加入时间", prop: "joinTime" },
@@ -151,6 +156,22 @@ layout("/layouts/platform.html"){
})
},
// 修改会员类别
onAidFundMemberTypeChange(row) {
this.$axios.post('/platform/fundMember/query/updateAidFundMemberType', {
loginName: row.loginName,
aidFundMemberType: row.aidFundMemberType
}).then((res) => {
if (res.code === 0) {
this.$message.success('修改成功')
} else {
this.pageData()
}
}).catch(() => {
this.pageData()
})
},
// 备份会员
backup() {
// 此处需要选择年份
@@ -200,8 +221,8 @@ layout("/layouts/platform.html"){
pageData() {
const pageForm = clone(this.pageForm)
pageForm.userStates = JSON.stringify(this.pageForm.userStates)
pageForm.personTypes = JSON.stringify(this.pageForm.personTypes)
pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
pageForm.aidFundMemberTypes = JSON.stringify(this.pageForm.aidFundMemberTypes)
// pageForm.preparedBys = JSON.stringify(this.pageForm.preparedBys)
this.$axios.post('/platform/fundMember/query/pageData', pageForm)
.then(res => {
this.tableData = res.data.list
@@ -37,12 +37,7 @@ layout("/layouts/platform.html"){
<el-table-column prop="loginName" label="工号"></el-table-column>
<el-table-column prop="userName" label="姓名"></el-table-column>
<el-table-column prop="unionName" label="所属工会"></el-table-column>
<el-table-column prop="isJoin" label="申请类型">
<template slot-scope="{row}">
<el-tag v-if="row.isJoin" size="small">加入</el-tag>
<el-tag v-else size="small" type="danger">退出</el-tag>
</template>
</el-table-column>
<el-table-column prop="aidFundMemberType" label="会员类别"></el-table-column>
<el-table-column prop="submitTime" label="申请时间"></el-table-column>
<el-table-column prop="curTaskName" label="当前节点"></el-table-column>
<el-table-column prop="instanceState" label="流程状态">
@@ -4,7 +4,8 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<el-card shadow="never">
<snaker-start slot="header" label="基金会员入会申请" define_key="FUND_MEMBER"></snaker-start>
<snaker-start slot="header" label="基金会员入会申请" define_key="JJHY"></snaker-start>
<el-alert v-if="isFundMember" title="您已是基金会员,无需重复申请。" type="warning" :closable="false" show-icon class="mb20"></el-alert>
<el-form :model="formData" ref="formRef" :rules="formRules" label-width="120px">
<el-row :gutter="20">
<el-col :span="12">
@@ -43,8 +44,8 @@ layout("/layouts/platform.html"){
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="身份证号码" prop="idCard">
<el-input v-model="formData.idCard" placeholder="请输入身份证号码"></el-input>
<el-form-item label="籍贯" prop="nativePlace">
<el-input v-model="formData.nativePlace" placeholder="请输入籍贯"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -56,16 +57,51 @@ layout("/layouts/platform.html"){
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="参加工作时间" prop="joinWorkTime">
<el-form-item label="健康状况" prop="healthStatus">
<el-input v-model="formData.healthStatus" maxlength="200" placeholder="请输入健康状况"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="学历" prop="education">
<dict-select v-model="formData.education" placeholder="请选择学历" code="USER_EDUCATION" style="width: 100%"></dict-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="联系电话" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入联系电话" maxlength="11"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="入职时间" prop="joinWorkTime">
<el-date-picker
v-model="formData.joinWorkTime"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择参加工作时间"
placeholder="选择入职时间"
style="width: 100%"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="身份证号码" prop="idCard">
<el-input v-model="formData.idCard" placeholder="请输入身份证号码"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="会员类别" prop="aidFundMemberType">
<dict-select v-model="formData.aidFundMemberType" placeholder="请选择会员类别"
code="USER_AID_FUND_MEMBER_TYPE" style="width: 100%"></dict-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="退休时间" prop="retireTime">
<el-date-picker
@@ -79,19 +115,54 @@ layout("/layouts/platform.html"){
</el-col>
</el-row>
<!--
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="住宅号码" prop="homePhone">
<el-input v-model="formData.homePhone" placeholder="请输入住宅电话" maxlength="20"></el-input>
</el-form-item>
</el-col>
</el-row>
-->
<el-form-item label="家庭主要成员" prop="families" required>
<el-table :data="formData.families" border size="small">
<el-table-column label="序号" width="80" align="center">
<template slot-scope="scope">
{{ scope.row.sequence }}
</template>
</el-table-column>
<el-table-column label="姓名" min-width="160">
<template slot-scope="scope">
<el-input v-model="scope.row.name" maxlength="50" placeholder="请输入姓名"></el-input>
</template>
</el-table-column>
<el-table-column label="年龄" width="160">
<template slot-scope="scope">
<el-input-number v-model="scope.row.age" :min="0" :max="150" :precision="0" controls-position="right" style="width: 100%"></el-input-number>
</template>
</el-table-column>
<el-table-column label="与本人关系" min-width="180">
<template slot-scope="scope">
<el-input v-model="scope.row.relation" maxlength="50" placeholder="请输入与本人关系"></el-input>
</template>
</el-table-column>
<el-table-column width="150" align="center">
<template slot="header">
<el-button type="primary" size="mini" @click="addFamily">添加成员</el-button>
</template>
<template slot-scope="scope">
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeFamily(scope.$index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" :rows="3" maxlength="500" show-word-limit placeholder="请输入备注"></el-input>
</el-form-item>
<!--
<el-form-item label="照 片">
<file-upload
style="--upload-width: 150px;--upload-height:176px"
@@ -102,6 +173,7 @@ layout("/layouts/platform.html"){
upload_result_type="url"
></file-upload>
</el-form-item>
-->
<!-- <el-form-item>-->
<!-- <el-checkbox v-model="isAgree">-->
@@ -112,8 +184,8 @@ layout("/layouts/platform.html"){
</el-form>
<el-row type="flex" justify="end" class="mt20">
<!-- <el-button type="primary" plain @click="onSave">保存</el-button>-->
<el-button type="primary" @click="onSubmit" v-if="!taskId">提交申请</el-button>
<el-button type="primary" @click="onFinishTask" v-else>提交申请</el-button>
<el-button type="primary" @click="onSubmit" v-if="!taskId && !isFundMember">提交申请</el-button>
<el-button type="primary" @click="onFinishTask" v-if="taskId && !isFundMember">提交申请</el-button>
</el-row>
</el-card>
</div>
@@ -126,7 +198,14 @@ layout("/layouts/platform.html"){
return {
bizId: GetQueryString("bizId"),
taskId: GetQueryString("taskId"),
formData: {},
isFundMember: false,
formData: {
families: [],
nativePlace: "",
education: "",
healthStatus: "",
remark: ""
},
formRules: {
userName: [{required: true, message: '请输入姓名', trigger: 'blur'}],
loginName: [{required: true, message: '请输入工资号', trigger: 'blur'}],
@@ -134,14 +213,18 @@ layout("/layouts/platform.html"){
sex: [{required: true, message: '请选择性别', trigger: 'blur'}],
idCard: [{required: true, message: '请输入身份证号码', trigger: 'blur'},
{
pattern: /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))([0-2][1-9]|3[0-1])\d{3}[Xx\d]$/,
pattern: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[Xx\d]$/,
message: '请输入正确的身份证号码',
trigger: 'blur'
}
],
address: [{required: true, message: '请输入家庭住址', trigger: 'blur'}],
joinWorkTime: [{required: true, message: '请选择参加工作时间', trigger: 'blur'}],
nativePlace: [{required: true, message: '请输入籍贯', trigger: 'blur'}],
healthStatus: [{required: true, message: '请输入健康状况', trigger: 'blur'}],
education: [{required: true, message: '请选择学历', trigger: 'change'}],
joinWorkTime: [{required: true, message: '请选择入职时间', trigger: 'blur'}],
retireTime: [{required: false, message: '请选择退休时间', trigger: 'blur'}],
aidFundMemberType: [{required: true, message: '请选择会员类别', trigger: 'change'}],
mobile: [{required: true, message: '请输入手机号码', trigger: 'blur'},
{
pattern: /^1[3456789]\d{9}$/,
@@ -162,6 +245,63 @@ layout("/layouts/platform.html"){
}
},
methods: {
// 确保家庭成员字段始终为可响应式数组,兼容旧申请数据。
ensureFamilies() {
if (!Array.isArray(this.formData.families)) {
this.$set(this.formData, "families", [])
}
},
// 按当前行顺序重置家庭成员序号,避免删除成员后出现断号。
resetFamilySequence() {
this.ensureFamilies()
this.formData.families.forEach((family, index) => {
this.$set(family, "sequence", index + 1)
})
},
// 添加一名家庭成员并自动设置序号。
addFamily() {
this.ensureFamilies()
this.formData.families.push({
sequence: this.formData.families.length + 1,
name: "",
age: null,
relation: ""
})
},
// 删除指定家庭成员后重排序号。
removeFamily(index) {
this.ensureFamilies()
this.formData.families.splice(index, 1)
this.resetFamilySequence()
},
// 提交前校验家庭主要成员的必填信息。
validateFamilies() {
this.resetFamilySequence()
if (this.formData.families.length === 0) {
this.$message.error("请至少添加一名家庭主要成员")
return false
}
for (const family of this.formData.families) {
if (!family.name || !String(family.name).trim()) {
this.$message.error("请填写第" + family.sequence + "位家庭成员的姓名")
return false
}
if (family.age === null || family.age === undefined || family.age === "") {
this.$message.error("请填写第" + family.sequence + "位家庭成员的年龄")
return false
}
if (!family.relation || !String(family.relation).trim()) {
this.$message.error("请填写第" + family.sequence + "位家庭成员与本人的关系")
return false
}
}
return true
},
// 保存
// onSave() {
// this.$confirm("您确定保存吗?", "提示", {
@@ -182,6 +322,7 @@ layout("/layouts/platform.html"){
onSubmit() {
this.$refs.formRef.validate(valid => {
if (!valid) return
if (!this.validateFamilies()) return
// if (!this.isAgree) {
// this.$message.error("请先阅读并同意《南昌大学教职工医疗互助“爱心”基金管理办法》")
// return
@@ -204,19 +345,22 @@ layout("/layouts/platform.html"){
},
onFinishTask() {
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/fundMember/write/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/fundMember/mine')
}
this.$refs.formRef.validate(valid => {
if (!valid || !this.validateFamilies()) return
this.$confirm("您确定要提交吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post('/platform/fundMember/write/submitAgain', {
data: JSON.stringify(this.formData),
taskId: GetQueryString("taskId")
}).then(res => {
if (res.code === 0) {
this.$message.success("提交成功")
commonUtil.pjaxPush('/platform/fundMember/mine')
}
})
})
})
},
@@ -228,10 +372,11 @@ layout("/layouts/platform.html"){
this.$axios.post("/platform/fundMember/write/info", {id: this.bizId}).then((res) => {
if (res.code === 0) {
this.formData = res.data
this.resetFamilySequence()
}
})
} else {
const {username, loginname, sex, birthday, mobile, union, userState, idCard} = this.$store.state.user
const {username, loginname, sex, birthday, mobile, union, userState, idCard, education} = this.$store.state.user
this.formData = {
userName: username,
loginName: loginname,
@@ -241,7 +386,12 @@ layout("/layouts/platform.html"){
unionId: union?.id,
unionName: union?.name,
userState: userState,
idCard: idCard
idCard: idCard,
nativePlace: "",
education: education || "",
healthStatus: "",
remark: "",
families: []
}
}
},
@@ -249,6 +399,11 @@ layout("/layouts/platform.html"){
},
created() {
this.init()
this.$axios.post('/platform/fundMember/write/memberStatus').then((res) => {
if (res.code === 0) {
this.$set(this, "isFundMember", Boolean(res.data))
}
})
if(!this.bizId){
this.$axios.post('/platform/fundMember/write/validateApply')
}
@@ -58,6 +58,17 @@ const basicForm = {
</div>
</el-form-item>
<el-form-item label="封面" prop="cover">
<file-upload
:upload_number="1"
:value.sync="formData.cover"
accept=".jpg,.jpeg,.png"
upload_mode="image"
upload_result_category="interval"
upload_result_type="url"
></file-upload>
</el-form-item>
<template v-if="formData.category==='QUIZ'">
<el-form-item label="出题模式" prop="mode">
<span slot="label">
@@ -171,17 +182,6 @@ const basicForm = {
</el-radio-group>
</el-form-item>
<!-- <el-form-item label="封面" prop="cover">-->
<!-- <file-upload-->
<!-- :upload_number="1"-->
<!-- :value.sync="formData.cover"-->
<!-- accept=".jpg,.jpeg,.png"-->
<!-- complete_result-->
<!-- upload_mode="image"-->
<!-- upload_result_category="interval"-->
<!-- ></file-upload>-->
<!-- </el-form-item>-->
</template>
</el-form>
</div>
@@ -204,7 +204,8 @@ const basicForm = {
return {
dialogVisible: false,
formData: {
category: ''
category: '',
cover: ''
},
formRules: {
category: [{ required: true, message: "请选择类型", trigger: "change" }],
@@ -228,7 +229,9 @@ const basicForm = {
}
})
} else {
this.formData = {}
this.formData = {
cover: ''
}
}
},
onSubmit() {
@@ -31,11 +31,27 @@ layout("/layouts/platform.html"){
</el-table-column>
<el-table-column label="开始时间" prop="startTime" sortable></el-table-column>
<el-table-column label="结束时间" prop="endTime" sortable></el-table-column>
<el-table-column label="操作" fixed="right" width="450px">
<el-table-column label="状态" width="100">
<template scope="{row}">
<el-tag v-if="row.enabled !== false" type="success">开启</el-tag>
<el-tag v-else type="info">关闭</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="520px">
<template scope="{row}">
<el-button size="mini" type="primary" @click="openQrCode(row)">二维码</el-button>
<el-button size="mini" type="primary" @click="openEdit(row)">编辑</el-button>
<el-button size="mini" type="primary" @click="openSubject(row.id)">题目设置</el-button>
<el-button
v-if="row.enabled === false"
size="mini"
type="success"
@click="updateEnabled(row, true)">开启</el-button>
<el-button
v-else
size="mini"
type="warning"
@click="updateEnabled(row, false)">关闭</el-button>
<el-button size="mini" type="danger" @click="onDelete(row.id)">删除</el-button>
</template>
</el-table-column>
@@ -94,6 +110,26 @@ layout("/layouts/platform.html"){
})
},
// 开启或关闭活动,关闭后移动端首页不展示,直达手机端问卷也不能答题
updateEnabled(row, enabled) {
const actionText = enabled ? "开启" : "关闭"
this.$confirm("您确认" + actionText + "该活动吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
$.post("/platform/qsv/activity/updateEnabled", {
id: row.id,
enabled
}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
}
})
})
},
// 删除
onDelete(id) {
this.$confirm("您确认删除吗, 是否继续?", "提示", {
@@ -8,6 +8,20 @@ const setting = {
<el-form-item label="详情" prop="description">
<text-editor v-model="formData.description"></text-editor>
</el-form-item>
<el-form-item label="补充填写" prop="fillRequired">
<el-switch
v-model="formData.fillRequired"
active-text="需要填写"
inactive-text="无需填写">
</el-switch>
</el-form-item>
<el-form-item label="填写提示" prop="fillPlaceholder" v-if="formData.fillRequired">
<el-input
maxlength="255"
placeholder="例如:请填写原因"
v-model="formData.fillPlaceholder">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
@@ -26,7 +40,11 @@ const setting = {
methods:{
onOpen(option,ext){
console.log(option)
this.formData = { ...option }
this.formData = {
...option,
fillRequired: !!option.fillRequired,
fillPlaceholder: option.fillPlaceholder || ""
}
this.ext = ext
this.visible = true
},
@@ -12,14 +12,21 @@ const subjectForm = {
<transition-group>
<div v-for="(subject, subjectIndex) in subjects" :key="subject.id" class="subject-item">
<div class="subject-header">
<div style="display: flex; align-items: center;">
<div class="subject-title-row">
<i class="el-icon-rank drag-handler"></i>
<span style="font-weight: bold; margin-right: 10px;">第 {{subjectIndex + 1}} 题</span>
<el-input
class="subject-title-input"
v-model="subject.title"
placeholder="请输入题目"
style="flex: 1">
placeholder="请输入题目">
</el-input>
<el-button
class="subject-visible-btn"
type="primary"
icon="el-icon-setting"
@click="openSubjectVisibleSetting(subjectIndex, subject)">
隐显逻辑
</el-button>
</div>
<div class="subject-meta">
@@ -214,6 +221,87 @@ const subjectForm = {
<setting ref="settingRef" @confirm="onSettingConfirm"></setting>
<txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import>
<bank ref="bankRef" @confirm="onBankConfirm"></bank>
<el-dialog
title="设置题目隐显逻辑"
:visible.sync="subjectVisibleSetting.visible"
append-to-body
width="520px">
<el-form :model="subjectVisibleSetting.formData" label-width="110px">
<el-form-item label="启用逻辑">
<el-switch
v-model="subjectVisibleSetting.formData.enabled"
active-text="启用"
inactive-text="关闭">
</el-switch>
</el-form-item>
<template v-if="subjectVisibleSetting.formData.enabled">
<el-form-item label="处理方式">
<el-radio-group v-model="subjectVisibleSetting.formData.action">
<el-radio label="show">选中后显示本题</el-radio>
<el-radio label="hide">选中后隐藏本题</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="条件关系">
<el-radio-group v-model="subjectVisibleSetting.formData.logic">
<el-radio label="AND">并且</el-radio>
<el-radio label="OR">或者</el-radio>
</el-radio-group>
</el-form-item>
<div
v-for="(condition, conditionIndex) in subjectVisibleSetting.formData.conditions"
:key="conditionIndex"
class="subject-visible-condition">
<el-form-item :label="'条件' + (conditionIndex + 1)">
<div style="display: flex; gap: 8px;">
<el-select
v-model="condition.subjectId"
placeholder="请选择触发题目"
style="flex: 1;"
@change="subjectVisibleRuleSubjectChange(condition)">
<el-option
v-for="item in subjectVisibleRuleSubjects"
:key="item.id"
:label="item.title || '未填写题目'"
:value="item.id">
</el-option>
</el-select>
<el-select
v-model="condition.optionId"
placeholder="请选择触发选项"
style="flex: 1;">
<el-option
v-for="item in getSubjectVisibleRuleOptions(condition.subjectId)"
:key="item.id"
:label="item.text || '未填写选项'"
:value="item.id">
</el-option>
</el-select>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeSubjectVisibleRuleCondition(conditionIndex)">
</el-button>
</div>
</el-form-item>
</div>
<el-form-item label="">
<el-button
type="primary"
icon="el-icon-plus"
size="small"
@click="addSubjectVisibleRuleCondition">
添加条件
</el-button>
</el-form-item>
</template>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="subjectVisibleSetting.visible = false">取 消</el-button>
<el-button type="primary" @click="onSubjectVisibleSettingConfirm">确 定</el-button>
</div>
</el-dialog>
</div>
`,
components: {
@@ -230,7 +318,32 @@ const subjectForm = {
subjects: [],
previewDialogVisible: false,
activity: {},
formRules: {}
formRules: {},
subjectVisibleSetting: {
visible: false,
subjectIndex: null,
formData: {
enabled: false,
action: "show",
logic: "AND",
conditions: [
{
subjectId: "",
optionId: ""
}
]
}
}
}
},
computed: {
subjectVisibleRuleSubjects() {
if (this.subjectVisibleSetting.subjectIndex === null) {
return []
}
return this.subjects.filter((item, index) => {
return index < this.subjectVisibleSetting.subjectIndex && item.type !== "text"
})
}
},
methods: {
@@ -351,13 +464,113 @@ const subjectForm = {
//选项设置确认
onSettingConfirm({option, ext}) {
this.subjects[ext.subjectIndex].options[ext.optionIndex] = option
this.$set(this.subjects[ext.subjectIndex].options, ext.optionIndex, option)
console.log(this.subjects[ext.subjectIndex].options[ext.optionIndex])
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "isCorrect", option.isCorrect)
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint)
},
//打开题目隐显逻辑设置,用于配置当前题目受前置选择题的哪个选项控制显示或隐藏
openSubjectVisibleSetting(subjectIndex, subject) {
const conditions = this.buildSubjectVisibleConditions(subject)
this.subjectVisibleSetting.subjectIndex = subjectIndex
this.subjectVisibleSetting.formData = {
enabled: !!subject.visibleRuleEnabled,
action: subject.visibleRuleAction || "show",
logic: subject.visibleRuleLogic || "AND",
conditions
}
this.subjectVisibleSetting.visible = true
},
//构建题目隐显逻辑条件,已有条件按实际数量回显;未配置时默认提供一条空条件
buildSubjectVisibleConditions(subject) {
let visibleRuleConditions = subject.visibleRuleConditions || []
if (typeof visibleRuleConditions === "string") {
try {
visibleRuleConditions = JSON.parse(visibleRuleConditions)
} catch (e) {
visibleRuleConditions = []
}
}
const conditions = visibleRuleConditions || []
const result = conditions.map((condition) => {
return {
subjectId: condition.subjectId || "",
optionId: condition.optionId || ""
}
})
if (result.length === 0) {
result.push({
subjectId: "",
optionId: ""
})
}
return result
},
//根据触发题目获取可选项,用于每条隐显条件选择触发选项
getSubjectVisibleRuleOptions(subjectId) {
const subject = this.subjects.find((item) => {
return item.id === subjectId
})
if (!subject || !subject.options) {
return []
}
return subject.options
},
//切换触发题目后清空当前条件的旧选项,避免保留其他题目的选项导致隐显条件错误
subjectVisibleRuleSubjectChange(condition) {
condition.optionId = ""
},
//添加一条隐显逻辑条件,多个条件通过条件关系字段统一按并且或或者计算
addSubjectVisibleRuleCondition() {
this.subjectVisibleSetting.formData.conditions.push({
subjectId: "",
optionId: ""
})
},
//删除一条隐显逻辑条件,至少保留一条条件用于继续配置
removeSubjectVisibleRuleCondition(conditionIndex) {
if (this.subjectVisibleSetting.formData.conditions.length === 1) {
this.$message.warning("至少保留一条条件")
return
}
this.subjectVisibleSetting.formData.conditions.splice(conditionIndex, 1)
},
//保存题目隐显逻辑到当前题目对象,后续保存题目时随 subjects 一起提交
onSubjectVisibleSettingConfirm() {
const subjectIndex = this.subjectVisibleSetting.subjectIndex
if (subjectIndex === null) {
return
}
const formData = this.subjectVisibleSetting.formData
if (formData.enabled) {
for (let i = 0; i < formData.conditions.length; i++) {
const condition = formData.conditions[i]
if (!condition.subjectId || !condition.optionId) {
this.$message.warning("请选择条件" + (i + 1) + "的触发题目和触发选项")
return
}
}
}
this.$set(this.subjects[subjectIndex], "visibleRuleEnabled", formData.enabled)
this.$set(this.subjects[subjectIndex], "visibleRuleAction", formData.enabled ? formData.action : "show")
this.$set(this.subjects[subjectIndex], "visibleRuleLogic", formData.enabled ? formData.logic : "AND")
this.$set(this.subjects[subjectIndex], "visibleRuleConditions", formData.enabled ? formData.conditions.map((condition) => {
return {
subjectId: condition.subjectId,
optionId: condition.optionId
}
}) : [])
this.subjectVisibleSetting.visible = false
},
//从文本导入
openTxtImport() {
this.$refs.txtImportRef.visible = true;
@@ -449,6 +662,21 @@ const subjectForm = {
margin-bottom: 15px;
}
/deep/ .subject-title-row {
display: flex;
align-items: center;
}
/deep/ .subject-title-input {
flex: 1;
}
/deep/ .subject-visible-btn {
height: 40px;
margin-left: 8px;
flex-shrink: 0;
}
/deep/ .subject-toolbar {
display: flex;
justify-content: space-between;
@@ -5,7 +5,7 @@ const answer = {
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportUserAnswerXlsx">导出xlsx</el-button>
</el-row>
<el-table :data="tableData">
<el-table :data="tableData" v-loading="tableLoading">
<el-table-column label="序号" type="index" width="70"></el-table-column>
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
<el-table-column label="操作" fixed="right" width="100px">
@@ -30,17 +30,24 @@ const answer = {
onOpen(activityId) {
this.activityId = activityId
this.dialogVisible = true
this.tableColumns = []
this.tableData = []
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.pageData()
},
pageData() {
this.pageForm.activityId = this.activityId
this.tableLoading = true
$.post("/platform/qsv/survey/userAnswer", this.pageForm).then((res) => {
if (res.code === 0) {
this.tableColumns = res.data.tableColumns
this.tableData = res.data.tableData.list
this.pageForm.totalCount = res.data.tableData.totalCount
}
}).always(() => {
this.tableLoading = false
})
},
@@ -53,7 +60,7 @@ const answer = {
$.post("/platform/qsv/survey/deleteUserAnswer", { id }).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.list()
this.pageData()
}
})
})
@@ -2,6 +2,42 @@
layout("/layouts/platform.html"){
#-->
<style>
.survey-report-dialog {
margin-top: 40px !important;
height: calc(100vh - 80px);
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.survey-report-dialog .el-dialog__header {
flex: 0 0 auto;
}
.survey-report-dialog .el-dialog__body {
flex: 1;
min-height: 0;
overflow: hidden;
padding-top: 10px;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.survey-report-toolbar {
flex: 0 0 auto;
}
.survey-report-body {
flex: 1;
min-height: 0;
overflow-y: auto;
padding-right: 8px;
box-sizing: border-box;
}
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
@@ -1,41 +1,44 @@
const report = {
/*language=HTML*/
template: `
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%">
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
</el-row>
<div v-for="(subject,subjectIndex) in subjects" class="subject">
<div>
<div class="title">
第{{subjectIndex+1}}题: {{subject.title}}
<span class="type" v-if="subject.type==='text'">[填空题]</span>
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
<span class="type" v-else-if="subject.type==='text'">[多选题]</span>
</div>
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%" custom-class="survey-report-dialog">
<div class="survey-report-toolbar">
<el-row type="flex" justify="end" class="mb10">
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
</el-row>
</div>
<div class="survey-report-body">
<div v-for="(subject,subjectIndex) in subjects" class="subject">
<div>
<div class="title">
第{{subjectIndex+1}}题: {{subject.title}}
<span class="type" v-if="subject.type==='text'">[填空题]</span>
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
<span class="type" v-else-if="subject.type==='checkbox'">[多选题]</span>
</div>
<div v-if="subject.type==='text'">
{{subject.texts.join('、')}}
</div>
<div v-if="subject.type==='text'">
<el-button type="text" @click="openTextDetail(subject)">查看填写内容</el-button>
</div>
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
<el-table :data="subject.options" size="small">
<el-table-column label="选项" prop="text"></el-table-column>
<el-table-column label="小计" prop="selectCount" width="100"></el-table-column>
<el-table-column label="比例" width="500">
<template slot-scope="scope">
<el-progress
:percentage="Math.round(scope.row.selectCount / subject.selectTotal * 100)"></el-progress>
</template>
</el-table-column>
<el-table-column label="详情" width="100px">
<template slot-scope="{row}">
<el-button type="text" @click="openDetail(subject.id,row.id)">详情</el-button>
</template>
</el-table-column>
</el-table>
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
<el-table :data="subject.options" size="small">
<el-table-column label="选项" prop="text"></el-table-column>
<el-table-column label="小计" prop="selectCount" width="100"></el-table-column>
<el-table-column label="比例" width="500">
<template slot-scope="scope">
<el-progress
:percentage="Math.round(scope.row.selectCount / subject.selectTotal * 100)"></el-progress>
</template>
</el-table-column>
<el-table-column label="详情" width="100px">
<template slot-scope="{row}">
<el-button type="text" @click="openDetail(subject.id,row.id)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
@@ -45,9 +48,22 @@ const report = {
<el-table-column label="工号" prop="loginName"></el-table-column>
<el-table-column label="所属工会" prop="unionName"></el-table-column>
<el-table-column label="所属单位" prop="unitName"></el-table-column>
<el-table-column label="补充理由" prop="fillContent" show-overflow-tooltip></el-table-column>
<el-table-column label="选择时间" prop="attemptDate"></el-table-column>
</el-table>
</el-dialog>
<el-dialog :title="textSubject.title || '填写内容'" :visible.sync="textVisible" width="50%" append-to-body>
<el-table :data="textAnswers" size="small">
<el-table-column label="序号" type="index" width="70"></el-table-column>
<el-table-column label="姓名" prop="userName" width="100"></el-table-column>
<el-table-column label="工号" prop="loginName" width="120"></el-table-column>
<el-table-column label="所属工会" prop="unionName" width="140"></el-table-column>
<el-table-column label="所属单位" prop="unitName" width="180" show-overflow-tooltip></el-table-column>
<el-table-column label="填写内容" prop="text" show-overflow-tooltip></el-table-column>
<el-table-column label="提交时间" prop="submitTime" width="160"></el-table-column>
</el-table>
</el-dialog>
</el-dialog>
`,
@@ -59,7 +75,10 @@ const report = {
report: null,
subjects: [],
optionVisible: false,
optionUsers: []
optionUsers: [],
textVisible: false,
textSubject: {},
textAnswers: []
}
},
methods: {
@@ -73,8 +92,6 @@ const report = {
})
},
openDetail(subjectId, optionId) {
console.log(subjectId)
console.log(optionId)
$.post("/platform/qsv/survey/selectOptionUsers", {
activityId: this.activityId,
subjectId,
@@ -87,6 +104,13 @@ const report = {
}
})
},
openTextDetail(subject) {
this.textSubject = subject
this.textAnswers = subject.textAnswers || (subject.texts || []).map((text) => {
return { text }
})
this.textVisible = true
},
exportReportXlsx(){
this.$downLoad("/platform/qsv/survey/exportReportXlsx", { activityId: this.activityId })
}
@@ -77,7 +77,7 @@ layout("/layouts/platform.html"){
</template>
</el-table-column>
<el-table-column prop="taskName" label="当前节点" width="120"></el-table-column>
<el-table-column label="操作" fixed="right" width="200">
<el-table-column label="操作" fixed="right" width="250">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button size="mini" type="primary" v-if="canEdit(row)" @click="onEdit(row)">修改</el-button>
@@ -196,9 +196,10 @@ layout("/layouts/platform.html"){
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="90">
<el-table-column label="操作" fixed="right" width="150">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="onOpen(row)">查看</el-button>
<el-button v-if="canDelete(row)" size="mini" type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -257,6 +258,24 @@ layout("/layouts/platform.html"){
this.$refs.infoRef.onOpen(row)
})
},
canDelete(row) {
return this.$auth.hasRole('SYSADMIN') && row.state === '已办结' && Number(row.instanceState) === 20
},
onDelete(row) {
this.$confirm("您确定要删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.$axios.post("/platform/appeal/query/delete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$message.success(res.msg)
this.pageData()
this.loadStatistics()
}
})
})
},
doSearch() {
this.pageNumber = 1
this.pageData()
@@ -56,10 +56,11 @@ layout("/layouts/platform.html"){
<el-tag :type="row.isReply ? 'success' : 'warning'" size="small">{{ row.isReply ? '已回复' : '待回复' }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="160px">
<el-table-column label="操作" fixed="right" width="240px">
<template slot-scope="{row}">
<el-button @click="openView(row)" size="mini" type="primary">查看</el-button>
<el-button v-if="!row.isReply" @click="openReply(row)" size="mini" type="success">回复</el-button>
<el-button @click="handleDelete(row)" size="mini" type="danger">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -187,6 +188,23 @@ layout("/layouts/platform.html"){
})
})
},
handleDelete(row) {
this.$confirm('确认删除该信件吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$axios.post('/platform/chairmanMailbox/query/delete', {
id: row.id
}).then((res) => {
if (res.code === 0) {
this.$message.success('删除成功')
this.loadStats()
this.pageData()
}
})
})
},
loadStats() {
this.$axios.post('/platform/chairmanMailbox/query/getStats').then((res) => {
if (res.code === 0) {
@@ -103,7 +103,7 @@ layout("/layouts/platform.html"){
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
@@ -31,10 +31,10 @@ const COMMON_QUERY = {
<dict-select v-model="pageForm.personTypes" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="编制类别">
<!-- <search-item label="编制类别">
<dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>
</search-item>
</search-item> -->
</template>
</search>
`,
@@ -86,7 +86,7 @@ layout("/layouts/platform.html"){
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
@@ -121,7 +121,7 @@ layout("/layouts/platform.html"){
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
@@ -105,7 +105,7 @@ layout("/layouts/platform.html"){
{ prop: "userName", label: "姓名", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "sign", label: "签字" },
@@ -95,7 +95,7 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: 'preparedBy', label: '编制类别', sortable: true },
<!-- { prop: 'preparedBy', label: '编制类别', sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "changeTypes", label: "变更类型", sortable: true, width: 200 },
@@ -26,10 +26,10 @@ const COMMON_QUERY = {
<dict-select v-model="pageForm.personTypes" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="编制类别">
<!-- <search-item label="编制类别">
<dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>
</search-item>
</search-item> -->
</search>
`,
store,
@@ -34,10 +34,10 @@ layout("/layouts/platform.html"){
<dict-select v-model="pageForm.personType" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE"></dict-select>
</search-item>
<search-item label="编制类别">
<!-- <search-item label="编制类别">
<dict-select v-model="pageForm.preparedBy" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE"></dict-select>
</search-item>
</search-item> -->
<search-item label="更新日期">
<el-date-picker :picker-options="pickerOptions" @change="changeDateRangeChange"
align="right" end-placeholder="结束日期" format="yyyy-MM-dd"
@@ -259,7 +259,7 @@ layout("/layouts/platform.html"){
{ prop: "political", label: "政治面貌", width: 120, sortable: true},
{ prop: "userState", label: "在职状态", width: 120, sortable: true },
{ prop: "personType", label: "教职工类别", width: 120, sortable: true },
{ prop: "preparedBy", label: "编制类别", width: 120, sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", width: 120, sortable: true }, -->
{ prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 },
{ prop: "unionName", label: "所属工会", width: 120, sortable: true },
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
@@ -69,7 +69,7 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "changeTypes", label: "变更类型", sortable: true, width: 200 },
@@ -41,10 +41,10 @@ const COMMON_QUERY = {
<dict-select v-model="pageForm.personTypes" placeholder="请选择教职工类别" @change="doSearch"
code="USER_PERSON_TYPE" multiple collapse-tags></dict-select>
</search-item>
<search-item label="编制类别">
<!-- <search-item label="编制类别">
<dict-select v-model="pageForm.preparedBys" placeholder="请选择编制类别" @change="doSearch"
code="USER_PREPARED_BY_TYPE" multiple collapse-tags></dict-select>
</search-item>
</search-item> -->
</search>
`,
props: {
@@ -208,7 +208,7 @@ layout("/layouts/platform.html"){
{ prop: "sex", label: "性别", sortable: true },
{ prop: "userState", label: "在职状态", sortable: true },
{ prop: "personType", label: "教职工类别", sortable: true },
{ prop: "preparedBy", label: "编制类别", sortable: true },
<!-- { prop: "preparedBy", label: "编制类别", sortable: true }, -->
{ prop: "unionName", label: "所属工会", sortable: true },
{ prop: "unitName", label: "所属单位", sortable: true },
],
@@ -159,7 +159,7 @@ layout("/layouts/platform.html"){
{ prop: "political", label: "政治面貌", width: 120, sortable: true},
{ prop: "userState", label: "在职状态", width: 120, sortable: true },
{ prop: "personType", label: "教职工类别", width: 120, sortable: true },
{ prop: "preparedBy", label: "编制类别", width: 120, sortable: true },
{ prop: "preparedBy", label: "编制类别", width: 120, sortable: true, checked: 0 },
{ prop: "postDoctoralJoinDate", label: "进站时间", sortable: true, checked: 0 },
{ prop: "unionName", label: "所属工会", width: 120, sortable: true },
{ prop: "unitName", label: "所属单位", width: 120, sortable: true },
@@ -87,7 +87,7 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
</el-col>
</el-row>
<el-row type="flex" align="middle" class="query-row query-row-tag">
<!-- <el-row type="flex" align="middle" class="query-row query-row-tag">
<el-col class="query-row-title">编制类别:</el-col>
<el-col class="query-row-content query-row-content-tag">
<el-tag
@@ -110,7 +110,7 @@ const MEMBER_STATISTICS_COMPREHENSIVE_QUERY_FORM = {
type="success">全部
</el-link>
</el-col>
</el-row>
</el-row> -->
<el-row type="flex" align="middle" class="query-row">
<el-col class="query-row-content">
@@ -0,0 +1,184 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker
placeholder="选择年度"
style="width: 100%"
type="year"
v-model="pageForm.year"
:clearable="false"
value-format="yyyy">
</el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">姓名工号:</div>
<div class="search-item-option">
<el-input v-model="pageForm.searchKeyword" clearable maxlength="20"></el-input>
</div>
</div>
<div class="search-item"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])">
<div class="search-item-label">所属工会:</div>
<div class="search-item-option">
<el-select placeholder="所属工会" v-model="pageForm.unionId" style="width: 100%;"
clearable
@change="flushUnits" @clear="flushUnits"
filterable>
<el-option v-for="item in unions" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select placeholder="所属单位" v-model="pageForm.unitId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in units" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">变更类型:</div>
<div class="search-item-option">
<el-select v-model="pageForm.changeType" style="width: 100%" clearable>
<el-option v-for="item in changeTypes" :label="item.desc" :value="item.code"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="退休人员" :app="this"></table-tool>
<el-table :data="tableData" style="width: 100%" stripe border
:header-cell-style="{background:'#FAFAFA'}" row-key="id" @sort-change="pageOrder"
v-loading="tableLoading">
<el-table-column align="center" header-align="center" type="index" :index="indexMethod" label="序号"
width="80px"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
:key="column.prop"
show-overflow-tooltip
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
>
<template slot-scope="{row}">
<span v-if="column.prop==='unitname'">{{isDisPlayCode ? '(' + row.unitcode + ')' : ''}}{{row.unitname}}</span>
<span v-else-if="column.prop==='unionname'">{{isDisPlayCode ? '(' + row.unioncode + ')' : ''}}{{row.unionname}}</span>
<span v-else-if="column.prop==='changeType'">{{getChangeTypeName(row.changeType)}}</span>
<span v-else>{{row[column.prop]}}</span>
</template>
</el-table-column>
<!--<el-table-column align="center" header-align="center" label="操作" width="200px">
<template slot-scope="{row}">
<el-button size="mini" @click="openView(row.id)">查看</el-button>
</template>
</el-table-column>-->
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
unions: [],
isDisPlayCode: false,
units: [],
tableColumns: [
{prop: 'loginname', label: '工号'},
{prop: 'username', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'birthday', label: '出生年月', sortable: true},
{prop: 'mobile', label: '联系电话'},
{prop: 'idCard', label: '身份证号', width: 170},
{prop: 'position', label: '职务', sortable: true, checked: 0},
{prop: 'professionalTitle', label: '职称', sortable: true, checked: 0},
{prop: 'personType', label: '人员类型', sortable: true},
{prop: 'userState', label: '在职状态', sortable: true},
{prop: 'unionname', label: '所属工会', sortable: true},
{prop: 'unitname', label: '所属单位', sortable: true},
{prop: 'campusName', label: '所属校区', sortable: true, checked: 0},
{prop: 'nation', label: '民族', checked: 0},
{prop: 'political', label: '政治面貌', checked: 0},
{prop: 'changeType', label: '变更类型'}
],
changeTypes: [],
pageForm: {
year: (new Date().getFullYear()).toString()
}
}
},
methods: {
async flushUnits() {
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])) {
this.$set(this, "units", await this.$businessTool.listUnit(this.pageForm.unionId))
} else {
this.$set(this, "units", await this.$businessTool.listUnit(this.$store.state.user.union.id))
}
},
getChangeTypeName(changeType) {
const item = this.changeTypes.find(v => v.code === changeType)
return item ? item.desc : ''
},
openChange(row) {
this.$confirm('您确定要将' + row.username + '设为死亡吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async res => {
const resp = await $.post(loc() + '/changeToDie', {userId: row.id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
})
}
},
async created() {
this.pageData()
this.$set(this, "changeTypes", [
{code: 1, desc: '在职转离退休'},
{code: 2, desc: '离退休转去世'}
])
this.$set(this, "unions", await this.$businessTool.listUnion())
this.flushUnits()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,514 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-transfer {
text-align: center;
}
.el-transfer-panel {
text-align: left;
width: 35%;
height: 400px;
}
.el-transfer-panel__body {
height: calc(100% - 40px);
}
.el-transfer-panel__list {
height: 100%;
}
.v-tree-layout-left {
overflow: unset !important;
}
.v-tree-layout-left .v-tree {
width: 100%;
height: calc(100vh - 170px);
overflow-y: auto;
}
.v-tree:hover::-webkit-scrollbar {
width: 3px;
background-color: transparent;
}
.v-tree-layout-left .custom-tree-node {
width: 90%;
position: relative;
display: flex;
align-items: center;
}
.v-tree-layout-left .v-tree .v-node {
width: 100%;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
::-webkit-scrollbar {
/*width: 3px;*/
/*background-color: transparent;*/
display: none;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 10px;
}
.el-transfer-panel__list.is-filterable {
height: 300px;
padding-top: 0;
}
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never" style="height: calc(100vh - 70px)">
<tree-layout>
<template #tree>
<div style="padding:0 20px 20px;">
<el-input
@input="(val)=>{$refs.tree.filter(val)}"
placeholder="输入关键字进行查找" clearable
v-model="filterText">
</el-input>
</div>
<el-tree ref="tree" :data="treeData" v-loading="treeLoading" node-key="id"
:props="{label:'groupName'}"
:expand-on-click-node="false"
:default-expanded-keys="['1']"
@node-click="handleNodeClick" accordion
highlight-current :filter-node-method="filterNode">
<div class="custom-tree-node" slot-scope="{ node, data }">
<div v-if="node.level==1" style="font-size: 16px;" class="v-node">
<i class="el-icon-office-building"></i>&nbsp;
{{ data.label }}
</div>
<div v-if="node.level==2" style="font-size: 15px" :title="data.name" class="v-node">
<i class="el-icon-school"></i>
&nbsp; {{ data.label }}
</div>
</div>
</el-tree>
</template>
<template>
<div style="padding: 0 10px">
<el-tabs v-model="tabActive" @tab-click="doSearch" type="card" style="box-shadow: none">
<el-tab-pane v-if="currentNode.level===1" label="小组信息" name="groupInfo"></el-tab-pane>
<el-tab-pane v-if="currentNode.level===2" label="组成单位"
name="componentUnit"></el-tab-pane>
<el-tab-pane v-if="currentNode.level===2" label="小组人员" name="userInfo"></el-tab-pane>
</el-tabs>
<el-card shadow="never">
<div style="display: flex; align-items: center; width: 100%">
<div class="btn-group tool-button" style="width: 220px">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</div>
<div class="btn-group tool-button">
<el-button type="primary" icon="el-icon-search"
@click="doSearch"></el-button>
</div>
<div style="margin-left: auto"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN'])">
<el-button v-if="tabActive==='groupInfo'" type="primary" icon="el-icon-plus"
@click="openAddGroup">新增小组
</el-button>
<el-button v-if="tabActive==='componentUnit'" type="primary" icon="el-icon-plus"
@click="openAddComponentUnit">新增组成单位
</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<div id="secondaryTableWrap" data-bottom="80">
<el-table :data="groupTableData" :height="tableHeight" v-if="tabActive==='groupInfo'">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="groupName" label="小组名称"></el-table-column>
<el-table-column prop="groupCode" label="小组代码"></el-table-column>
<el-table-column label="操作" width="200px">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="openEditGroup(row)">
编辑
</el-button>
<el-button size="mini" type="danger" @click="deleteGroup(row.id)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-table :data="componentUnitTableData" :height="tableHeight"
v-else-if="tabActive==='componentUnit'">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="name" label="单位名称"></el-table-column>
<el-table-column prop="unitcode" label="单位代码"></el-table-column>
</el-table>
<el-table :data="userTableData" :height="tableHeight" v-else-if="tabActive==='userInfo'">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="loginname" label="工号"></el-table-column>
<el-table-column prop="username" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="birthday" label="出生年月"></el-table-column>
<el-table-column prop="mobile" label="联系电话"></el-table-column>
<el-table-column prop="unitname" label="所属单位"
show-overflow-tooltip></el-table-column>
<el-table-column prop="unionname" label="所属工会"
show-overflow-tooltip></el-table-column>
<el-table-column prop="roleName" label="身份"></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-dropdown @command="dropdownCommand">
<el-button size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{action:setGroupLeader,value:row}"
v-if="row.roleCode==null">
设为组长
</el-dropdown-item>
<el-dropdown-item :command="{action:removeGroupLeader,value:row}"
v-if="row.roleCode!=null">
取消组长
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
</div>
<el-row class="el-pagination-container" style="margin-bottom: 0px">
<el-pagination
@size-change="(val)=>{pageForm.pageSize=val;pageData()}"
@current-change="(val)=>{pageForm.pageNumber=val;pageData()}"
:current-page="pageForm.pageNumber"
:page-sizes="[5,10, 20, 30, 50]"
:page-size="pageForm.pageSize"
layout="total, sizes, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-card>
</div>
</template>
</tree-layout>
</el-card>
</guava>
<el-dialog :visible.sync="groupDialogVisible" title="新增离退休小组" width="40%">
<el-form :model="groupFormData" label-width="80px" ref="form">
<el-form-item label="小组名称" prop="groupName"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="groupFormData.groupName" maxlength="20"></el-input>
</el-form-item>
<el-form-item label="小组代码" prop="groupCode"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number v-model="groupFormData.groupCode" style="width: 100%;"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="groupDialogVisible = false">取消</el-button>
<el-button type="primary" @click="doSetGroup">确定</el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="componentUnitDialogVisible" title="组成单位">
<div style="width: 100%;">
<el-transfer v-model="groupComponentUnit" :data="groupComponentUnitLeft"
filterable
ref="componentUnitTransfer"
:props="{
key: 'id',
label: 'name'
}"
:titles="['可选单位', '当前成员单位']"
></el-transfer>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="componentUnitDialogVisible = false">取消</el-button>
<el-button type="primary" @click="doSetComponentUnit">确定</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'tree-layout': httpVueLoader('/components/plugins/TreeLayout.vue'),
},
data() {
return {
treeLoading: false,
treeData: [],
filterText: null,
currentData: null,
currentNode: {level: 1},
tabActive: 'groupInfo',
tableHeight: null,
//小组table
groupTableData: [],
groupDialogVisible: false,
groupFormData: {
groupName: null,
groupCode: null,
id: null
},
//组成单位table
componentUnitTableData: [],
componentUnitDialogVisible: false,
groupComponentUnit: [],
groupComponentUnitLeft: [],
userTableData: []
}
},
methods: {
// 根据表格容器位置动态计算高度,避免依赖旧项目全局方法。
resizeTableHeight() {
this.$nextTick(() => {
const wrap = document.getElementById('secondaryTableWrap')
if (!wrap) {
return
}
const bottom = Number(wrap.getAttribute('data-bottom') || 80)
const height = window.innerHeight - wrap.getBoundingClientRect().top - bottom
this.$set(this, "tableHeight", height > 240 ? height : 240)
})
},
doSearch() {
this.$set(this.pageForm, "pageNumber", 1)
this.pageData()
},
pageData() {
if (this.tabActive === 'groupInfo') {
this.groupPageData()
} else if (this.tabActive === 'componentUnit') {
this.componentUnitPageData()
} else if (this.tabActive === 'userInfo') {
this.getGroupUser()
}
},
handleNodeClick(data, node) {
this.$set(this, "currentData", data)
this.$set(this, "currentNode", node)
if (node.level === 1) {
this.$set(this, "tabActive", 'groupInfo')
this.groupPageData()
} else if (node.level === 2) {
this.$set(this, "tabActive", 'componentUnit')
this.componentUnitPageData()
}
},
filterNode(value, data, node) {
if (!value) return true
return data.label.includes(value)
},
//左侧树数据
async getTree() {
const resp = await $.post(loc() + '/getTree')
if (resp.code === 0) {
this.$set(this, "treeData", resp.data)
if (this.$refs.tree && this.$refs.tree.root.childNodes) {
this.$set(this, "currentNode", this.$refs.tree.root.childNodes[0])
}
} else {
this.notifyWarning(resp.msg)
}
},
//打开新增小组模态框
openAddGroup() {
this.$set(this, "groupDialogVisible", true)
this.$nextTick(() => {
this.$set(this, "groupFormData", {
groupName: null,
groupCode: null,
id: null
})
this.$refs.form.resetFields()
})
},
openEditGroup(row) {
this.$set(this, "groupDialogVisible", true)
this.$set(this, "groupFormData", Object.assign({}, row))
},
//新增、编辑小组
async doSetGroup() {
const resp = await $.post(loc() + '/doSetGroup', this.groupFormData)
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.$set(this, "groupDialogVisible", false)
this.getTree()
this.groupPageData()
} else {
this.notifyWarning(resp.msg)
}
},
//小组分页数据
async groupPageData() {
const resp = await $.post(loc() + '/groupPageData', this.pageForm)
if (resp.code === 0) {
this.$set(this, "groupTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
}
},
//删除小组
deleteGroup(id) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async res => {
const resp = await $.post(loc() + '/deleteGroup', {id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.getTree()
this.groupPageData()
} else {
this.notifyWarning(resp.msg)
}
})
},
//组成单位分页数据
async componentUnitPageData() {
const resp = await $.post(loc() + '/componentUnitPageData', Object.assign({}, this.pageForm, {
groupId: this.currentData.id
}))
if (resp.code === 0) {
this.$set(this, "componentUnitTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
}
},
openAddComponentUnit() {
this.$set(this, "componentUnitDialogVisible", true)
const groupId = this.currentData.id
this.getNotSetUnit(groupId)
this.getGroupComponentUnit(groupId)
if (this.$refs.componentUnitTransfer) {
this.$refs.componentUnitTransfer.clearQuery('left')
this.$refs.componentUnitTransfer.clearQuery('right')
}
},
//小组组成单位
async getGroupComponentUnit(groupId) {
const resp = await $.post(loc() + '/groupComponentUnit', {groupId})
if (resp.code === 0) {
this.$set(this, "groupComponentUnit", resp.data)
}
},
async getNotSetUnit(groupId) {
const resp = await $.post(loc() + '/notSetUnit', {groupId})
if (resp.code === 0) {
this.$set(this, "groupComponentUnitLeft", resp.data)
}
},
async doSetComponentUnit() {
const params = {
groupId: this.currentData.id,
units: JSON.stringify(this.groupComponentUnit)
}
const resp = await $.post(loc() + '/doSetComponentUnit', params)
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.$set(this, "componentUnitDialogVisible", false)
this.componentUnitPageData()
} else {
this.notifyWarning(resp.msg)
}
},
async getGroupUser() {
const resp = await $.post(loc() + '/groupUser', Object.assign({}, this.pageForm, {groupId: this.currentData.id}))
if (resp.code === 0) {
this.$set(this, "userTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
} else {
this.notifyWarning(resp.msg)
}
},
setGroupLeader(user) {
this.$confirm('您确定要将' + user.username + '设为小组组长吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await $.post(loc() + '/setGroupLeader', {
userId: user.id,
groupId: this.currentData.id
})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.getGroupUser()
} else {
this.notifyWarning(resp.msg)
}
})
},
removeGroupLeader(user) {
this.$confirm('您确定要将' + user.username + '设为小组组员吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await $.post(loc() + '/removeGroupLeader', {
userId: user.id,
groupId: this.currentData.id
})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.getGroupUser()
} else {
this.notifyWarning(resp.msg)
}
})
}
},
async mounted() {
//动态改变table高度
await httpVueLoader('/components/plugins/Guava.vue', 'Guava')()
await httpVueLoader('/components/plugins/TreeLayout.vue', 'tree-layout')()
this.resizeTableHeight()
window.addEventListener('resize', this.resizeTableHeight)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeTableHeight)
},
created() {
this.getTree()
this.groupPageData()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,99 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">所属小组:</div>
<div class="search-item-option">
<el-select placeholder="所属小组" v-model="retiredGroupId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredGroupOption" :label="item.groupName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="getData" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<el-table :data="statisticsData"
header-align="center"
align="center"
show-summary
:summary-method="summaryMethod"
border
highlight-current-row>
<el-table-column label="序号" type="index" width="70px"></el-table-column>
<el-table-column label="小组名称" prop="groupName"></el-table-column>
<el-table-column label="小组代码" prop="groupCode" sortable></el-table-column>
<el-table-column label="组成单位" prop="componentUnit"></el-table-column>
<el-table-column label="人数" prop="retireCount" sortable></el-table-column>
</el-table>
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
data() {
return {
retiredGroupId: null,
statisticsData: [],
retiredGroupOption: []
}
},
methods: {
async getData() {
const resp = await $.post(loc() + '/data', {retiredGroupId: this.retiredGroupId})
if (resp.code === 0) {
this.$set(this, "statisticsData", resp.data)
} else {
this.notifyWarning(resp.msg)
}
},
summaryMethod(param) {
const {columns, data} = param
let sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计';
return;
}
const values = data.map(item => Number(item[column.property]));
if (column.property === 'retireCount') {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
}
})
return sums
},
async getRetiredGroup() {
const resp = await $.post(loc() + '/retiredGroup')
this.$set(this, "retiredGroupOption", resp.data)
},
},
created() {
this.getData()
this.getRetiredGroup()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,196 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">年度:</div>
<div class="search-item-option">
<el-date-picker v-model="pageForm.year" value-format="yyyy" format="yyyy" type="year" style="width: 100%;" :clearable="false"></el-date-picker>
</div>
</div>
<div class="search-item">
<div class="search-item-label">姓名工号:</div>
<div class="search-item-option">
<el-input clearable maxlength="20" v-model.trim="pageForm.searchKeyword"></el-input>
</div>
</div>
<div class="search-item"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])">
<div class="search-item-label">所属工会:</div>
<div class="search-item-option">
<el-select placeholder="所属工会" v-model="pageForm.unionId" style="width: 100%;"
clearable
@change="flushUnits" @clear="flushUnits"
filterable>
<el-option v-for="item in unions" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select placeholder="所属单位" v-model="pageForm.unitId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in units" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属小组:</div>
<div class="search-item-option">
<el-select placeholder="所属小组" v-model="pageForm.retiredGroupId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredGroupOption" :label="item.groupName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属支部:</div>
<div class="search-item-option">
<el-select placeholder="所属支部" v-model="pageForm.retiredPartyBranchId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredPartyBranchOption" :label="item.partyBranchName"
:value="item.id" :key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="退休人员" :app="this">
</table-tool>
<el-table :data="tableData" style="width: 100%" stripe border
:header-cell-style="{background:'#FAFAFA'}" row-key="id" @sort-change="pageOrder"
v-loading="tableLoading">
<el-table-column align="center" header-align="center" type="index" :index="indexMethod" label="序号"
width="80px"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
:key="column.prop"
show-overflow-tooltip
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
>
<template slot-scope="{row}">
<span v-if="column.prop==='unitname'">{{isDisPlayCode ? '(' + row.unitcode + ')' : ''}}{{row.unitname}}</span>
<span v-else-if="column.prop==='unionname'">{{isDisPlayCode ? '(' + row.unioncode + ')' : ''}}{{row.unionname}}</span>
<span v-else-if="column.prop==='memberJoinTime'">{{row.memberJoinTime ? moment(row.memberJoinTime).format('YYYY-MM-DD') : ''}}</span>
<span v-else>{{row[column.prop]}}</span>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="100px">
<template slot-scope="{row}">
<el-dropdown @command="dropdownCommand">
<el-button size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>
查看
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
data() {
return {
unions: [],
isDisPlayCode: false,
units: [],
tableColumns: [
{prop: 'loginname', label: '工号'},
{prop: 'username', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'birthday', label: '出生年月', sortable: true},
{prop: 'mobile', label: '联系电话'},
{prop: 'idCard', label: '身份证号', width: 170, checked: 0},
{prop: 'position', label: '职务', sortable: true, checked: 0},
{prop: 'professionalTitle', label: '职称', sortable: true, checked: 0},
{prop: 'personType', label: '人员类型', sortable: true, checked: 0},
{prop: 'userState', label: '在职状态', sortable: true, checked: 0},
{prop: 'political', label: '政治面貌'},
{prop: 'unionname', label: '所属工会', sortable: true},
{prop: 'unitname', label: '所属单位', sortable: true},
{prop: 'threeUnitName', label: '所在科室', sortable: true, checked: 0},
{prop: 'unionGroupName', label: '工会小组', sortable: true, checked: 0},
{prop: 'retiredGroupName', label: '退休小组', sortable: true},
{prop: 'retiredPartyBranchName', label: '退休党支部', sortable: true},
{prop: 'campusName', label: '所属校区', sortable: true, checked: 0},
{prop: 'nation', label: '民族', checked: 0},
],
retiredGroupOption: [],
retiredPartyBranchOption: [],
pageForm: {
year: new Date().getFullYear() + ''
}
}
},
methods: {
async flushUnits() {
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])) {
this.$set(this, "units", await this.$businessTool.listUnit(this.pageForm.unionId))
} else {
this.$set(this, "units", await this.$businessTool.listUnit(this.$store.state.user.union.id))
}
},
async getRetiredGroup() {
const resp = await $.post(loc() + '/retiredGroup')
this.$set(this, "retiredGroupOption", resp.data)
},
async getRetiredPartyBranch() {
const resp = await $.post(loc() + '/retiredPartyBranch')
this.$set(this, "retiredPartyBranchOption", resp.data)
}
},
async created() {
this.pageData()
this.$set(this, "unions", await this.$businessTool.listUnion())
this.flushUnits()
this.getRetiredGroup()
this.getRetiredPartyBranch()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,388 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">姓名工号:</div>
<div class="search-item-option">
<el-input clearable maxlength="20"
placeholder="请输入姓名工号进行查询"
v-model.trim="pageForm.searchKeyword"></el-input>
</div>
</div>
<div class="search-item"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])">
<div class="search-item-label">所属工会:</div>
<div class="search-item-option">
<el-select placeholder="请选择所属工会" v-model="pageForm.unionId" style="width: 100%;"
clearable
@change="flushUnits" @clear="flushUnits"
filterable>
<el-option v-for="item in unions" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select placeholder="请选择所属单位" v-model="pageForm.unitId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in units" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属小组:</div>
<div class="search-item-option">
<el-select placeholder="请选择所属小组" v-model="pageForm.retiredGroupId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredGroupOption" :label="item.groupName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属支部:</div>
<div class="search-item-option">
<el-select placeholder="请选择所属支部" v-model="pageForm.retiredPartyBranchId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredPartyBranchOption" :label="item.partyBranchName"
:value="item.id" :key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="退休人员" :app="this">
<template v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])">
<el-button size="small" type="primary" @click="openAdd">新增退休人员(系统中不存在)</el-button>
<el-button size="small" type="primary" @click="openSet">设置退休人员(系统中存在)</el-button>
<el-button size="small" type="primary" @click="backUp">备份为历史数据</el-button>
</template>
</table-tool>
<el-table :data="tableData" style="width: 100%" stripe border
:header-cell-style="{background:'#FAFAFA'}" row-key="id" @sort-change="pageOrder"
v-loading="tableLoading">
<el-table-column align="center" header-align="center" type="index" :index="indexMethod" label="序号"
width="80px"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
:key="column.prop"
show-overflow-tooltip
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
>
<template slot-scope="{row}">
<span v-if="column.prop==='unitname'">{{isDisPlayCode ? '(' + row.unitcode + ')' : ''}}{{row.unitname}}</span>
<span v-else-if="column.prop==='unionname'">{{isDisPlayCode ? '(' + row.unioncode + ')' : ''}}{{row.unionname}}</span>
<span v-else-if="column.prop==='memberJoinTime'">{{row.memberJoinTime ? moment(row.memberJoinTime).format('YYYY-MM-DD') : ''}}</span>
<span v-else>{{row[column.prop]}}</span>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="100px">
<template slot-scope="{row}">
<el-dropdown @command="dropdownCommand">
<el-button size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{action:openView,value:row}">
查看
</el-dropdown-item>
<el-dropdown-item :command="{action:openEdit,value:row}">
编辑
</el-dropdown-item>
<!-- <el-dropdown-item :command="{action:openChange,value:row}">-->
<!-- 变更-->
<!-- </el-dropdown-item>-->
<el-dropdown-item :command="{action:doDelete,value:row}">
删除
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- <el-button size="mini" @click="openView(row.id)">查看</el-button>
<el-button size="mini" type="primary" @click="openChange(row)">编辑</el-button>-->
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<user-info :id="userId"></user-info>
</template>
<template #edit>
<user-edit ref="userEdit" @finish="$refs.guava.index();pageData()"></user-edit>
</template>
<el-drawer title="设置退休人员(系统中存在)" :visible.sync="retireUserAddDialogVisible" size="70%">
<el-timeline>
<el-timeline-item timestamp="" placement="top">
<el-input placeholder="请输入内容" clearable v-model="nonRetiredUserPageForm.searchKeyword"
@keyup.enter.native="nonRetiredUserPageForm.pageNumber=1;nonRetiredUserPageData()"
style="width: 300px">
<el-select v-model="nonRetiredUserPageForm.searchName" slot="prepend" style="width: 80px;">
<el-option label="姓名" value="username"></el-option>
<el-option label="工号" value="loginname"></el-option>
</el-select>
</el-input>
<el-button type="primary" icon="el-icon-search"
@click="nonRetiredUserPageForm.pageNumber=1;nonRetiredUserPageData()"></el-button>
</el-timeline-item>
<el-timeline-item timestamp="" placement="top">
<el-table :data="nonRetiredUserTableData" style="width: 100%" row-key="id"
ref="nonRetiredUserTable">
<el-table-column type="selection" reserve-selection></el-table-column>
<el-table-column label="工号" prop="loginname" align="center"></el-table-column>
<el-table-column label="姓名" prop="username" align="center"></el-table-column>
<el-table-column label="性别" prop="sex" align="center"></el-table-column>
<el-table-column label="电话" prop="mobile" align="center"></el-table-column>
<el-table-column label="在职状态" prop="userState" align="center"></el-table-column>
<el-table-column label="人员类型" prop="personType" align="center"></el-table-column>
<el-table-column label="单位" prop="unitname" align="center"
show-overflow-tooltip></el-table-column>
<el-table-column label="工会" prop="unionname" align="center"
show-overflow-tooltip></el-table-column>
</el-table>
<el-row class="el-pagination-container">
<el-pagination
@size-change="(val)=>{nonRetiredUserPageForm.pageSize=val;nonRetiredUserPageData()}"
@current-change="(val)=>{nonRetiredUserPageForm.pageNumber=val;nonRetiredUserPageData()}"
:current-page="nonRetiredUserPageForm.pageNumber"
:page-size="nonRetiredUserPageForm.pageSize"
layout="total, prev, pager, next"
:total="nonRetiredUserPageForm.totalCount">
</el-pagination>
</el-row>
</el-timeline-item>
</el-timeline>
<span style="position: absolute;bottom: 20px;right: 20px">
<el-button @click="retireUserAddDialogVisible = false">取 消</el-button>
<el-button type="primary" @click="doBatchJoinRetire">确定</el-button>
</span>
</el-drawer>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'user-info': httpVueLoader('/components/module/retired/userInfo.vue'),
'user-edit': httpVueLoader('/components/module/retired/userEdit.vue'),
},
data() {
return {
retireUserAddDialogVisible: false,
isDisPlayCode: false,
unions: [],
units: [],
tableColumns: [
{prop: 'loginname', label: '工号'},
{prop: 'username', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'birthday', label: '出生年月', sortable: true},
{prop: 'mobile', label: '联系电话'},
{prop: 'idCard', label: '身份证号', width: 170, checked: 0},
{prop: 'professionalTitle', label: '职称', sortable: true, checked: 0},
{prop: 'personType', label: '人员类型', sortable: true, checked: 0},
{prop: 'userState', label: '在职状态', sortable: true, checked: 0},
{prop: 'political', label: '政治面貌'},
// {prop: 'unionname', label: '所属工会', sortable: true},
{prop: 'unitname', label: '所属单位', sortable: true},
{prop: 'retiredGroupName', label: '退休小组', sortable: true},
{prop: 'retiredPartyBranchName', label: '退休党支部', sortable: true},
],
nonRetiredUserPageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0
},
nonRetiredUserTableData: [],
deadDialogVisible: false,
deathFormData: {},
retiredGroupOption: [],
retiredPartyBranchOption: [],
userId: null
}
},
methods: {
backUp() {
this.$confirm('确定把当前数据备份吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await $.post(loc() + '/backUp')
if (resp.code === 0) {
this.notifySuccess(resp.msg)
} else {
this.notifyWarning(resp.msg)
}
})
},
openAdd() {
this.$set(this, "userId", null)
this.$refs.guava.edit()
this.callUserEdit(userEdit => userEdit.reset())
},
openSet() {
this.$set(this, "retireUserAddDialogVisible", true)
this.$set(this.nonRetiredUserPageForm, "pageNumber", 1)
this.nonRetiredUserPageData()
if (this.$refs.nonRetiredUserTable) {
this.$refs.nonRetiredUserTable.clearSelection()
}
},
openEdit(row) {
this.$refs.guava.edit()
this.callUserEdit(userEdit => userEdit.getInfo(row.id))
},
callUserEdit(callback, retry) {
const waitCount = retry || 0
this.$nextTick(() => {
if (this.$refs.userEdit) {
callback(this.$refs.userEdit)
} else if (waitCount < 10) {
setTimeout(() => {
this.callUserEdit(callback, waitCount + 1)
}, 100)
} else {
this.notifyWarning("编辑组件加载失败,请刷新页面后重试")
}
})
},
async nonRetiredUserPageData() {
const resp = await $.post(loc() + '/nonRetiredUserPageData', this.nonRetiredUserPageForm)
if (resp.code === 0) {
this.$set(this, "nonRetiredUserTableData", resp.data.list)
this.$set(this.nonRetiredUserPageForm, "totalCount", resp.data.totalCount)
} else {
this.notifyWarning(resp.msg)
}
},
async doBatchJoinRetire() {
const selection = this.$refs.nonRetiredUserTable.selection
if (!selection.length) {
this.notifyWarning("请先勾选需要设置为退休的人员")
return
}
const resp = await $.post(loc() + "/doBatchJoinRetire", {userIds: JSON.stringify(selection.map(v => v.id))})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.$set(this, "retireUserAddDialogVisible", false)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
},
async flushUnits() {
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])) {
this.$set(this, "units", await this.$businessTool.listUnit(this.pageForm.unionId))
} else {
this.$set(this, "units", await this.$businessTool.listUnit(this.$store.state.user.union.id))
}
},
openChange(row) {
this.$set(this, "deadDialogVisible", true)
this.$nextTick(() => {
this.$set(this, "deathFormData", Object.assign({}, row))
})
},
setUserDeathInfo() {
this.$refs['deathForm'].validate(async valid => {
if (valid) {
const {id: userId, deathDate} = this.deathFormData
const resp = await $.post(loc() + '/changeToDie', {userId, deathDate})
if (resp.code === 0) {
this.$set(this, "deadDialogVisible", false)
this.notifySuccess(resp.msg)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
}
})
},
async getRetiredGroup() {
const resp = await $.post(loc() + '/retiredGroup')
this.$set(this, "retiredGroupOption", resp.data)
},
async getRetiredPartyBranch() {
const resp = await $.post(loc() + '/retiredPartyBranch')
this.$set(this, "retiredPartyBranchOption", resp.data)
},
async openView(row) {
this.$set(this, "userId", row.id)
this.$refs.guava.view()
},
async doDelete(row) {
const confirm = await this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
if ('confirm' !== confirm) return
const resp = await $.post(loc() + "/doDelete", {id: row.id})
if (resp.code == 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
}
},
async created() {
this.pageData()
this.$set(this, "unions", await this.$businessTool.listUnion())
this.flushUnits()
this.getRetiredGroup()
this.getRetiredPartyBranch()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,595 @@
<!--#
layout("/layouts/platform.html"){
#-->
<style>
.el-transfer {
text-align: center;
}
.el-transfer-panel {
text-align: left;
width: 35%;
height: 400px;
}
.el-transfer-panel__body {
height: calc(100% - 40px);
}
.el-transfer-panel__list {
height: 100%;
}
.v-tree-layout-left {
overflow: unset !important;
}
.v-tree-layout-left .v-tree {
width: 100%;
height: calc(100vh - 170px);
overflow-y: auto;
}
.v-tree:hover::-webkit-scrollbar {
width: 3px;
background-color: transparent;
}
.v-tree-layout-left .custom-tree-node {
width: 90%;
position: relative;
display: flex;
align-items: center;
}
.v-tree-layout-left .v-tree .v-node {
width: 100%;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
::-webkit-scrollbar {
/*width: 3px;*/
/*background-color: transparent;*/
display: none;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 10px;
}
</style>
<div id="app" v-cloak>
<guava>
<el-card shadow="never" style="height: calc(100vh - 70px)">
<tree-layout>
<template #tree>
<div style="padding:0 20px 20px;">
<el-input
@input="(val)=>{$refs.tree.filter(val)}"
placeholder="输入关键字进行查找" clearable
v-model="filterText">
</el-input>
</div>
<el-tree ref="tree" :data="treeData" v-loading="treeLoading" node-key="id"
:props="{label:'partyBranchName'}"
:expand-on-click-node="false"
:default-expanded-keys="['1']"
@node-click="handleNodeClick" accordion
highlight-current :filter-node-method="filterNode">
<div class="custom-tree-node" slot-scope="{ node, data }">
<div v-if="node.level==1" style="font-size: 16px;" class="v-node">
<i class="el-icon-office-building"></i>&nbsp;
{{ data.label }}
</div>
<div v-if="node.level==2" style="font-size: 15px" :title="data.name" class="v-node">
<i class="el-icon-school"></i>
&nbsp; {{ data.label }}
</div>
</div>
</el-tree>
</template>
<template>
<div style="padding: 0 10px">
<el-tabs v-model="tabActive" @tab-click="doSearch" type="card" style="box-shadow: none">
<el-tab-pane v-if="currentNode.level===1" label="党支部信息" name="groupInfo"></el-tab-pane>
<el-tab-pane v-if="currentNode.level===2" label="党支部人员" name="userInfo"></el-tab-pane>
<el-tab-pane v-if="currentNode.level===2" label="党支部委员会"
name="committee"></el-tab-pane>
</el-tabs>
<el-card shadow="never">
<div style="display: flex; align-items: center; width: 100%">
<div class="btn-group tool-button" style="width: 220px">
<el-input placeholder="请输入内容" clearable v-model="pageForm.searchKeyword"
@keyup.enter.native="doSearch">
</el-input>
</div>
<div class="btn-group tool-button">
<el-button type="primary" icon="el-icon-search"
@click="doSearch"></el-button>
</div>
<div style="margin-left: auto">
<el-button v-if="tabActive==='groupInfo'" type="primary" icon="el-icon-plus"
@click="openAddPartyBranch">新增党支部
</el-button>
<el-button v-if="tabActive==='userInfo'" type="primary" icon="el-icon-plus"
@click="openAddUser">新增党支部人员
</el-button>
<el-button v-if="tabActive==='committee'" type="primary" icon="el-icon-plus"
@click="openAddCommittee">新增支部委员会人员
</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<div id="secondaryTableWrap" data-bottom="80">
<el-table :data="partyBranchTableData" :height="tableHeight" v-if="tabActive==='groupInfo'"
key="partyBranchTable">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="partyBranchName" label="党支部名称"></el-table-column>
<el-table-column prop="partyBranchCode" label="党支部代码"></el-table-column>
<el-table-column label="操作" width="200px">
<template slot-scope="{row}">
<el-button size="mini" type="primary" @click="openEditPartyBranch(row)">
编辑
</el-button>
<el-button size="mini" type="danger" @click="deletePartyBranch(row.id)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-table :data="userTableData" :height="tableHeight" v-else-if="tabActive==='userInfo'"
key="userTable">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="loginname" label="工号"></el-table-column>
<el-table-column prop="username" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="birthday" label="出生年月"></el-table-column>
<el-table-column prop="mobile" label="联系电话"></el-table-column>
<el-table-column prop="unitname" label="所属单位"
show-overflow-tooltip></el-table-column>
<el-table-column prop="unionname" label="所属工会"
show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-button size="mini" type="danger" @click="deleteUser(row.id)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<el-table :data="committeeTableData" :height="tableHeight" v-else-if="tabActive==='committee'"
key="committeeTable">
<el-table-column type="index" label="序号" width="70px"></el-table-column>
<el-table-column prop="loginname" label="工号"></el-table-column>
<el-table-column prop="username" label="姓名"></el-table-column>
<el-table-column prop="sex" label="性别"></el-table-column>
<el-table-column prop="birthday" label="出生年月"></el-table-column>
<el-table-column prop="mobile" label="联系电话"></el-table-column>
<el-table-column prop="roleName" label="身份"></el-table-column>
<el-table-column label="操作" width="100px">
<template slot-scope="{row}">
<el-button size="mini" type="danger" @click="deleteCommittee(row.id)">删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-row class="el-pagination-container" style="margin-bottom: 0px">
<el-pagination
@size-change="(val)=>{pageForm.pageSize=val;pageData()}"
@current-change="(val)=>{pageForm.pageNumber=val;pageData()}"
:current-page="pageForm.pageNumber"
:page-sizes="[5,10, 20, 30, 50]"
:page-size="pageForm.pageSize"
layout="total, sizes, prev, pager, next"
:total="pageForm.totalCount">
</el-pagination>
</el-row>
</el-card>
</div>
</template>
</tree-layout>
</el-card>
</guava>
<el-dialog :visible.sync="partyBranchDialogVisible" title="新增离退休党支部" width="40%">
<el-form :model="partyBranchFormData" label-width="100px" ref="form">
<el-form-item label="党支部名称" prop="partyBranchName"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input v-model="partyBranchFormData.partyBranchName" maxlength="20"></el-input>
</el-form-item>
<el-form-item label="党支部代码" prop="partyBranchCode"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-input-number v-model="partyBranchFormData.partyBranchCode" style="width: 100%"></el-input-number>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="partyBranchDialogVisible = false">取消</el-button>
<el-button type="primary" @click="doSetPartyBranch">确定</el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="userDialogVisible" title="新增党支部人员" width="40%">
<el-form :model="partyBranchUserFormData" label-width="80px" ref="partyBranchUserForm">
<el-form-item label="人员" prop="userIds"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="partyBranchUserFormData.userIds"
style="width: 100%"
multiple
filterable
remote
reserve-keyword
placeholder="请输入姓名或者工号查询"
:remote-method="queryNonSetUser">
<el-option
v-for="item in nonSetUserOptions"
:key="item.id"
:label="item.username"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="userDialogVisible = false">取消</el-button>
<el-button type="primary" @click="doAddBranchPartyUser">确定</el-button>
</span>
</el-dialog>
<el-dialog :visible.sync="committeeDialogVisible" title="新增党支部委员" width="40%">
<el-form :model="partyBranchCommitteeFormData" label-width="80px" ref="partyBranchCommitteeForm">
<el-form-item label="人员" prop="userId"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="partyBranchCommitteeFormData.userId"
style="width: 100%"
filterable
remote
placeholder="请输入姓名或者工号查询"
:remote-method="queryUserByPartyBranchId">
<el-option
v-for="item in committeeUserOptions"
:key="item.id"
:label="item.username"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="身份" prop="roleCode"
:rules="[{required:true,message:'必填',trigger:['change','blur']}]">
<el-select v-model="partyBranchCommitteeFormData.roleCode" style="width: 100%;">
<el-option v-for="item in retiredPartyBranchCommitteeRoleOptions"
:label="item.name"
:value="item.code"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="committeeDialogVisible = false">取消</el-button>
<el-button type="primary" @click="doAddCommitteeUser">确定</el-button>
</span>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'tree-layout': httpVueLoader('/components/plugins/TreeLayout.vue'),
},
data() {
return {
treeLoading: false,
treeData: [],
filterText: null,
currentData: null,
currentNode: {level: 1},
tabActive: 'groupInfo',
tableHeight: null,
//党支部table
partyBranchTableData: [],
partyBranchDialogVisible: false,
partyBranchFormData: {
partyBranchName: null,
partyBranchCode: null,
id: null
},
partyBranchUserFormData: {
userIds: []
},
userTableData: [],
userDialogVisible: false,
nonSetUserOptions: [],
//支部委员会信息
retiredPartyBranchCommitteeRoleOptions: [],
committeeDialogVisible: false,
committeeUserOptions: [],
partyBranchCommitteeFormData: {
userId: null,
roleCode: null
},
committeeTableData: []
}
},
methods: {
// 根据表格容器位置动态计算高度,避免依赖旧项目全局方法。
resizeTableHeight() {
this.$nextTick(() => {
const wrap = document.getElementById('secondaryTableWrap')
if (!wrap) {
return
}
const bottom = Number(wrap.getAttribute('data-bottom') || 80)
const height = window.innerHeight - wrap.getBoundingClientRect().top - bottom
this.$set(this, "tableHeight", height > 240 ? height : 240)
})
},
doSearch() {
this.$set(this.pageForm, "pageNumber", 1)
this.pageData()
},
pageData() {
if (this.tabActive === 'groupInfo') {
this.partyBranchPageData()
} else if (this.tabActive === 'userInfo') {
this.partyBranchUserPageData()
} else if (this.tabActive === 'committee') {
this.partyBranchCommitteePageData()
}
},
handleNodeClick(data, node) {
this.$set(this, "currentData", data)
this.$set(this, "currentNode", node)
if (node.level === 1) {
this.$set(this, "tabActive", 'groupInfo')
this.partyBranchPageData()
} else if (node.level === 2) {
this.$set(this, "tabActive", 'userInfo')
this.partyBranchUserPageData()
}
},
filterNode(value, data, node) {
if (!value) return true
return data.label.includes(value)
},
//左侧树数据
async getTree() {
const resp = await $.post(loc() + '/getTree')
if (resp.code === 0) {
this.$set(this, "treeData", resp.data)
if (this.$refs.tree && this.$refs.tree.root.childNodes) {
this.$set(this, "currentNode", this.$refs.tree.root.childNodes[0])
}
} else {
this.notifyWarning(resp.msg)
}
},
//打开新增党支部模态框
openAddPartyBranch() {
this.$set(this, "partyBranchDialogVisible", true)
this.$nextTick(() => {
this.$set(this, "partyBranchFormData", {
partyBranchName: null,
partyBranchCode: null,
id: null
})
this.$refs.form.resetFields()
})
},
openEditPartyBranch(row) {
this.$set(this, "partyBranchDialogVisible", true)
this.$set(this, "partyBranchFormData", Object.assign({}, row))
},
//新增、编辑党支部
async doSetPartyBranch() {
const resp = await $.post(loc() + '/doSetPartyBranch', this.partyBranchFormData)
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.$set(this, "partyBranchDialogVisible", false)
this.getTree()
this.partyBranchPageData()
} else {
this.notifyWarning(resp.msg)
}
},
//党支部分页数据
async partyBranchPageData() {
const resp = await $.post(loc() + '/partyBranchPageData', this.pageForm)
if (resp.code === 0) {
this.$set(this, "partyBranchTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
}
},
//删除党支部
deletePartyBranch(id) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async res => {
const resp = await $.post(loc() + '/deletePartyBranch', {id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.getTree()
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
})
},
async partyBranchUserPageData() {
const resp = await $.post(loc() + '/partyBranchUserPageData', Object.assign({}, this.pageForm, {
partyBranchId: this.currentData.id
}))
if (resp.code === 0) {
this.$set(this, "userTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
} else {
this.notifyWarning(resp.msg)
}
},
openAddUser() {
this.$set(this, "userDialogVisible", true)
this.$set(this.partyBranchUserFormData, "userIds", [])
this.queryNonSetUser(null)
},
async queryNonSetUser(val) {
if (val !== '') {
const resp = await $.post(loc() + '/queryNonSetUser', {val})
if (resp.code === 0) {
this.$set(this, "nonSetUserOptions", resp.data)
}
} else {
this.$set(this, "nonSetUserOptions", [])
}
},
async doAddBranchPartyUser() {
this.$refs['partyBranchUserForm'].validate(async valid => {
if (valid) {
const userIds = JSON.stringify(this.partyBranchUserFormData.userIds)
const partyBranchId = this.currentData.id
const resp = await $.post(loc() + '/doAddBranchPartyUser', {
partyBranchId,
userIds
})
if (resp.code === 0) {
this.$set(this, "userDialogVisible", false)
this.notifySuccess(resp.msg)
this.partyBranchUserPageData()
} else {
this.notifyWarning(resp.msg)
}
}
})
},
async deleteUser(userId) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async res => {
const resp = await $.post(loc() + '/deleteUser', {userId, partyBranchId: this.currentData.id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
})
},
//打开新增支部委员会
openAddCommittee() {
this.$set(this, "committeeDialogVisible", true)
this.$set(this, "partyBranchCommitteeFormData", {
userId: null,
roleCode: null
})
this.queryUserByPartyBranchId(null)
},
//查询党支部下的人员
async queryUserByPartyBranchId(val) {
if (val) {
const resp = await $.post(loc() + '/queryUserByPartyBranchId', {
val,
partyBranchId: this.currentData.id
})
if (resp.code === 0) {
this.$set(this, "committeeUserOptions", resp.data)
}
} else {
this.$set(this, "committeeUserOptions", [])
}
},
//添加党支部委员会人员
doAddCommitteeUser() {
this.$refs['partyBranchCommitteeForm'].validate(async valid => {
if (valid) {
const resp = await $.post(loc() + '/doAddCommitteeUser', Object.assign({partyBranchId: this.currentData.id}, this.partyBranchCommitteeFormData))
if (resp.code === 0) {
this.$set(this, "committeeDialogVisible", false)
this.partyBranchCommitteePageData()
this.notifySuccess(resp.msg)
} else {
this.notifyWarning(resp.msg)
}
}
})
},
async partyBranchCommitteePageData() {
const resp = await $.post(loc() + '/partyBranchCommitteePageData', Object.assign({}, this.pageForm, {
partyBranchId: this.currentData.id
}))
if (resp.code === 0) {
this.$set(this, "committeeTableData", resp.data.list)
this.$set(this.pageForm, "totalCount", resp.data.totalCount)
} else {
this.notifyWarning(resp.msg)
}
},
deleteCommittee(userId) {
this.$confirm('您确定要删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
const resp = await $.post(loc() + '/deleteCommittee', {userId, partyBranchId: this.currentData.id})
if (resp.code === 0) {
this.notifySuccess(resp.msg)
this.doSearch()
} else {
this.notifyWarning(resp.msg)
}
})
}
},
async mounted() {
//动态改变table高度
await httpVueLoader('/components/plugins/Guava.vue', 'Guava')()
await httpVueLoader('/components/plugins/TreeLayout.vue', 'tree-layout')()
this.resizeTableHeight()
window.addEventListener('resize', this.resizeTableHeight)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeTableHeight)
},
created() {
this.getTree()
this.partyBranchPageData()
this.$businessTool.getDictOptions('RETIRED_PARTY_BRANCH_COMMITTEE_ROLE').then(res => {
this.$set(this, "retiredPartyBranchCommitteeRoleOptions", res)
})
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,99 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava>
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">所属支部:</div>
<div class="search-item-option">
<el-select placeholder="所属支部" v-model="retiredPartyBranchId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredPartyBranchOption" :label="item.partyBranchName"
:value="item.id" :key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="getData" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<el-table :data="statisticsData"
header-align="center"
align="center"
show-summary
:summary-method="summaryMethod"
border
highlight-current-row>
<el-table-column label="序号" type="index" width="70px"></el-table-column>
<el-table-column label="党支部名称" prop="partyBranchName"></el-table-column>
<el-table-column label="党支部代码" prop="partyBranchCode" sortable
:summary-method="()=>{}"></el-table-column>
<el-table-column label="党员人数" prop="userCount" sortable></el-table-column>
</el-table>
</el-card>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
data() {
return {
retiredPartyBranchId: null,
retiredPartyBranchOption: [],
statisticsData: [],
}
},
methods: {
async getData() {
const resp = await $.post(loc() + '/data', {retiredPartyBranchId: this.retiredPartyBranchId})
if (resp.code === 0) {
this.$set(this, "statisticsData", resp.data)
} else {
this.notifyWarning(resp.msg)
}
},
summaryMethod(param) {
const {columns, data} = param
let sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '合计';
return;
}
const values = data.map(item => Number(item[column.property]));
if (column.property === 'userCount') {
sums[index] = values.reduce((prev, curr) => {
const value = Number(curr);
if (!isNaN(value)) {
return prev + curr;
} else {
return prev;
}
}, 0);
}
})
return sums
},
async getRetiredPartyBranch() {
const resp = await $.post(loc() + '/retiredPartyBranch')
this.$set(this, "retiredPartyBranchOption", resp.data)
}
},
created() {
this.getData()
this.getRetiredPartyBranch()
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,198 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<div class="search">
<div class="search-item">
<div class="search-item-label">姓名工号:</div>
<div class="search-item-option">
<el-input clearable maxlength="20" v-model.trim="pageForm.searchKeyword"
placeholder="请输入工号或者姓名查询"></el-input>
</div>
</div>
<div class="search-item"
v-if="$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])">
<div class="search-item-label">所属工会:</div>
<div class="search-item-option">
<el-select placeholder="所属工会" v-model="pageForm.unionId" style="width: 100%;"
clearable
@change="flushUnits" @clear="flushUnits"
filterable>
<el-option v-for="item in unions" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属单位:</div>
<div class="search-item-option">
<el-select placeholder="所属单位" v-model="pageForm.unitId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in units" :label="item.name" :value="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属小组:</div>
<div class="search-item-option">
<el-select placeholder="所属小组" v-model="pageForm.retiredGroupId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredGroupOption" :label="item.groupName" :value="item.id"
:key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-item">
<div class="search-item-label">所属支部:</div>
<div class="search-item-option">
<el-select placeholder="所属支部" v-model="pageForm.retiredPartyBranchId" style="width: 100%;"
clearable
filterable>
<el-option v-for="item in retiredPartyBranchOption" :label="item.partyBranchName"
:value="item.id" :key="item.id"></el-option>
</el-select>
</div>
</div>
<div class="search-query">
<el-button @click="doSearch" icon="el-icon-search" type="primary">搜索</el-button>
</div>
</div>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="退休人员" :app="this">
</table-tool>
<el-table :data="tableData" style="width: 100%" stripe border
:header-cell-style="{background:'#FAFAFA'}" row-key="id" @sort-change="pageOrder"
v-loading="tableLoading">
<el-table-column align="center" header-align="center" type="index" :index="indexMethod" label="序号"
width="80px"></el-table-column>
<el-table-column
align="center"
header-align="center"
v-for="column in tableColumns"
:key="column.prop"
show-overflow-tooltip
:label="column.label"
:prop="column.prop"
:sortable="column.sortable"
>
<template slot-scope="{row}">
<span v-if="column.prop==='unitname'">{{isDisPlayCode ? '(' + row.unitcode + ')' : ''}}{{row.unitname}}</span>
<span v-else-if="column.prop==='unionname'">{{isDisPlayCode ? '(' + row.unioncode + ')' : ''}}{{row.unionname}}</span>
<span v-else-if="column.prop==='memberJoinTime'">{{row.memberJoinTime ? moment(row.memberJoinTime).format('YYYY-MM-DD') : ''}}</span>
<span v-else>{{row[column.prop]}}</span>
</template>
</el-table-column>
<el-table-column align="center" header-align="center" label="操作" width="100px">
<template slot-scope="{row}">
<el-dropdown @command="dropdownCommand">
<el-button size="mini">
<i class="ti-settings"></i>
<span class="ti-angle-down"></span>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="{action:openView,value:row}">
查看
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<template #view>
<user-info :id="userId"></user-info>
</template>
</guava>
</div>
<script nonce="${cspNonce!}">
const vue = new Vue({
el: '#app',
mixins: [initTableMixins],
components: {
'user-info': httpVueLoader('/components/module/retired/userInfo.vue'),
},
data() {
return {
unions: [],
isDisPlayCode: false,
units: [],
tableColumns: [
{prop: 'loginname', label: '工号'},
{prop: 'username', label: '姓名'},
{prop: 'sex', label: '性别'},
{prop: 'birthday', label: '出生年月', sortable: true},
{prop: 'mobile', label: '联系电话'},
{prop: 'idCard', label: '身份证号', width: 170, checked: 0},
{prop: 'position', label: '职务', sortable: true, checked: 0},
{prop: 'professionalTitle', label: '职称', sortable: true, checked: 0},
{prop: 'personType', label: '人员类型', sortable: true, checked: 0},
{prop: 'userState', label: '在职状态', sortable: true, checked: 0},
{prop: 'political', label: '政治面貌'},
{prop: 'unionname', label: '所属工会', sortable: true},
{prop: 'unitname', label: '所属单位', sortable: true},
{prop: 'threeUnitName', label: '所在科室', sortable: true, checked: 0},
{prop: 'unionGroupName', label: '工会小组', sortable: true, checked: 0},
{prop: 'retiredGroupName', label: '退休小组', sortable: true},
{prop: 'retiredPartyBranchName', label: '退休党支部', sortable: true},
{prop: 'campusName', label: '所属校区', sortable: true, checked: 0},
{prop: 'nation', label: '民族', checked: 0},
],
retiredGroupOption: [],
retiredPartyBranchOption: [],
userId: null
}
},
methods: {
async flushUnits() {
this.$set(this.pageForm, "unitId", null)
if (this.$auth.hasRoleOr(['SYSADMIN', 'SCHOOL_UNION_ADMIN', 'SCHOOL_UNION_MEMBER_ADMIN'])) {
this.$set(this, "units", await this.$businessTool.listUnit(this.pageForm.unionId))
} else {
this.$set(this, "units", await this.$businessTool.listUnit(this.$store.state.user.union.id))
}
},
async getRetiredGroup() {
const resp = await $.post(loc() + '/retiredGroup')
this.$set(this, "retiredGroupOption", resp.data)
},
async getRetiredPartyBranch() {
const resp = await $.post(loc() + '/retiredPartyBranch')
this.$set(this, "retiredPartyBranchOption", resp.data)
},
async openView(row) {
this.$set(this, "userId", row.id)
this.$refs.guava.view()
}
},
async created() {
this.pageData()
this.$set(this, "unions", await this.$businessTool.listUnion())
this.flushUnits()
this.getRetiredGroup()
this.getRetiredPartyBranch()
}
})
</script>
<!--#
}
#-->
@@ -45,6 +45,7 @@ layout("/layouts/platform_h5.html"){
required></van-field>
<van-field label="工号" :rules="[{ required: true }]" v-model="formData.loginName" readonly
required></van-field>
<van-field label="职称" v-model="formData.professionalTitle" readonly></van-field>
<van-field label="手机号码" name="mobile" :rules="[{ required: true }]" v-model="formData.mobile"
required
placeholder="请输入手机号码"></van-field>
@@ -257,6 +258,16 @@ layout("/layouts/platform_h5.html"){
this.registrationTypeOption = res.data
}
},
async ensureUserLoaded() {
if (this.$store.state.user && this.$store.state.user.id) {
return
}
const resp = await $.get("/platform/sys/user/getLogonUser")
if (resp.code === 0) {
window.sessionStorage.setItem("user", JSON.stringify(resp.data))
this.$store.commit("setUser", resp.data)
}
},
init() {
setTimeout(() => {
this.childRelationshipOption = this.dict.type.ENROLLMENT_REGISTRATION_CHILD_RELATIONSHIP
@@ -266,6 +277,9 @@ layout("/layouts/platform_h5.html"){
if (this.bizId) {
this.findOne(this.bizId).then(async data => {
this.formData = data
if (!this.formData.professionalTitle) {
this.$set(this.formData, "professionalTitle", (this.$store.state.user && this.$store.state.user.professionalTitle) || "")
}
//登记类型回显
const registrationType = this.registrationTypeOption.find(v => v.registrationType === data.registrationType)
if (registrationType) {
@@ -288,16 +302,19 @@ layout("/layouts/platform_h5.html"){
})
} else {
const {id, username, loginname, mobile, union, unit} = this.$store.state.user
const user = this.$store.state.user || {}
const unit = user.unit || {}
const union = user.union || {}
this.formData = {
userId: id,
userName: username,
loginName: loginname,
unitName: unit.name,
unitId: unit.id,
unionName: union.name,
unionId: union.id,
mobile: mobile,
userId: user.id,
userName: user.username,
loginName: user.loginname,
professionalTitle: user.professionalTitle || "",
unitName: unit.name || "",
unitId: unit.id || "",
unionName: union.name || "",
unionId: union.id || "",
mobile: user.mobile,
childrenBirthdayDate: new Date(2000, 0, 1),
}
@@ -468,6 +485,7 @@ layout("/layouts/platform_h5.html"){
},
async created() {
await this.getEnrollmentRegistrationPlan()
await this.ensureUserLoaded()
this.init()
}
@@ -80,6 +80,33 @@ layout("/layouts/platform_h5.html"){
resize: none;
width: 100%;
}
.option-fill-box {
border: 1px solid #e3e3e3;
margin: 0 16px 8px 46px;
background-color: #fff;
padding: 0;
display: flex;
}
.option-fill-box input {
background-color: #fff;
border: none !important;
padding: 10px;
font-size: 14px;
line-height: 18px;
display: inline-block;
margin: 0;
-webkit-appearance: none;
resize: none;
width: 100%;
}
.required-star {
color: #ee0a24;
margin-left: 4px;
font-weight: bold;
}
</style>
<div id="app" v-cloak>
@@ -87,8 +114,8 @@ layout("/layouts/platform_h5.html"){
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
<h2 class="title">{{ activity.title }}</h2>
<div v-if="!isFinished">
<div v-for="(subject, index) in subjects" :key="index" class="subject">
<p>{{index+1}}、{{ subject.title }}</p>
<div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
<p>{{index+1}}、{{ subject.title }}<span class="required-star">*</span></p>
<div class="tag">
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
<van-tag v-if="subject.type === 'radio'" type="primary" size="large">单选</van-tag>
@@ -102,31 +129,43 @@ layout("/layouts/platform_h5.html"){
v-if="['radio','checkbox'].includes(subject.type)"
>
<van-cell-group>
<van-cell
v-for="(option,index) in subject.options"
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
<template v-for="(option,index) in subject.options">
<van-cell
clickable
:key="option.id"
:title="option.text"
@click="cellToggle(subject,option.id)"
>
<template #icon>
<van-checkbox :name="option.id" :ref="'option'+option.id" style="margin-right: 10px"></van-checkbox>
</template>
<img
slot="right-icon"
v-if="option.imgUrl"
:src="option.imgUrl"
alt=""
style="width: 40px; height: 40px"
@click.stop="previewOptionImg(option.imgUrl)"
/>
</van-cell>
<div
class="option-fill-box"
:key="option.id + '-fill'"
v-if="isOptionFillVisible(subject, option)">
<input
type="text"
v-model="subject.optionFillContents[option.id]"
:placeholder="option.fillPlaceholder || '请填写补充内容'"
:readonly="answerRecord.isFinish"
@click.stop />
</div>
</template>
</van-cell-group>
</van-checkbox-group>
<!--填空题-->
<div class="ui-input-box" v-if="subject.type==='text'">
<input type="text" v-model="subject.userFillContent" :readonly="answerRecord.isFinish" />
<input type="text" v-model="subject.userFillContent" :placeholder="'请输入' + subject.title" :readonly="answerRecord.isFinish" />
</div>
</div>
<div class="button-control" v-if="!answerRecord.isFinish">
@@ -158,6 +197,11 @@ layout("/layouts/platform_h5.html"){
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
}
return true
},
visibleSubjects() {
return this.subjects.filter((subject) => {
return this.isSubjectVisible(subject)
})
}
},
@@ -193,14 +237,106 @@ layout("/layouts/platform_h5.html"){
const answer = this.answerRecord.extJson[subject.id]
if (["radio", "checkbox"].includes(subject.type)) {
this.$refs["subject" + subject.id][0].toggleAll(false)
answer?.optionIds.forEach((optionId) => {
this.$nextTick(() => {
this.$refs["option" + optionId][0].toggle()
})
})
this.$set(subject, "userSelectOptionIds", answer?.optionIds || [])
this.$set(subject, "optionFillContents", answer?.optionFillContents || {})
} else if (subject.type === "text") {
subject.userFillContent = answer?.text
this.$set(subject, "userFillContent", answer?.text)
}
})
if (!this.answerRecord.isFinish) {
this.clearHiddenSubjectAnswers()
}
},
//判断题目是否显示,未配置隐显逻辑的题目默认显示;已配置的题目按条件关系计算后再执行显示或隐藏动作
isSubjectVisible(subject) {
if (!subject.visibleRuleEnabled) {
return true
}
const conditions = this.getVisibleRuleConditions(subject)
if (conditions.length === 0) {
return true
}
const results = conditions.map((condition) => {
const triggerSubject = this.subjects.find((item) => {
return item.id === condition.subjectId
})
return triggerSubject
&& triggerSubject.userSelectOptionIds
&& triggerSubject.userSelectOptionIds.includes(condition.optionId)
})
const matched = subject.visibleRuleLogic === "OR"
? results.some((item) => {
return item
})
: results.every((item) => {
return item
})
if (subject.visibleRuleAction === "hide") {
return !matched
}
return matched
},
//读取隐显逻辑条件,只使用后台保存的条件数组参与显示或隐藏判断
getVisibleRuleConditions(subject) {
let conditions = subject.visibleRuleConditions || []
if (typeof conditions === "string") {
try {
conditions = JSON.parse(conditions)
} catch (e) {
conditions = []
}
}
conditions = conditions.filter((condition) => {
return condition.subjectId && condition.optionId
})
if (conditions.length > 0) {
return conditions
}
return []
},
//清空当前隐藏题目的答案,避免隐藏题残留旧选项或填空内容参与后续提交
clearHiddenSubjectAnswers() {
this.subjects.forEach((subject) => {
if (this.isSubjectVisible(subject)) {
return
}
if (["radio", "checkbox"].includes(subject.type)) {
this.$set(subject, "userSelectOptionIds", [])
this.$set(subject, "optionFillContents", {})
} else if (subject.type === "text") {
this.$set(subject, "userFillContent", null)
}
})
},
//判断选项是否已被选择,用于控制选项补充填写框显示和提交校验
isOptionSelected(subject, optionId) {
return subject.userSelectOptionIds && subject.userSelectOptionIds.includes(optionId)
},
//选中需要补充填写的选项后显示输入框,例如选择“否”后填写原因
isOptionFillVisible(subject, option) {
return option.fillRequired && this.isOptionSelected(subject, option.id)
},
//清空未选中选项的补充填写内容,避免取消选择后残留旧内容
clearUnselectedOptionFillContents(subject) {
if (!subject.optionFillContents) {
this.$set(subject, "optionFillContents", {})
}
if (!subject.options) {
return
}
subject.options.forEach((option) => {
if (!this.isOptionSelected(subject, option.id)) {
this.$delete(subject.optionFillContents, option.id)
}
})
},
@@ -215,6 +351,10 @@ layout("/layouts/platform_h5.html"){
this.$refs["subject" + subject.id][0].toggleAll(false)
}
this.$refs["option" + optionId][0].toggle()
this.$nextTick(() => {
this.clearUnselectedOptionFillContents(subject)
this.clearHiddenSubjectAnswers()
})
},
//预览图片
@@ -231,13 +371,20 @@ layout("/layouts/platform_h5.html"){
}
//提示那些题没有作答
for (let i = 0; i < this.subjects.length; i++) {
const subject = this.subjects[i]
for (let i = 0; i < this.visibleSubjects.length; i++) {
const subject = this.visibleSubjects[i]
if (["radio", "checkbox"].includes(subject.type)) {
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
this.$toast.fail("第" + (i + 1) + "题未做答")
return
}
for (let j = 0; j < subject.options.length; j++) {
const option = subject.options[j]
if (this.isOptionFillVisible(subject, option) && !subject.optionFillContents[option.id]) {
this.$toast.fail("请填写第" + (i + 1) + "题的补充内容")
return
}
}
} else if ("text" === subject.type) {
if (!subject.userFillContent) {
this.$toast.fail("第" + (i + 1) + "题未作答")
@@ -255,11 +402,12 @@ layout("/layouts/platform_h5.html"){
answer: JSON.stringify({
activityId: this.id,
answerRecordId: this.answerRecordId,
subjects: this.subjects.map((subject) => {
subjects: this.visibleSubjects.map((subject) => {
return {
id: subject.id,
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
userFillContent: subject.type === "text" ? subject.userFillContent : null
userFillContent: subject.type === "text" ? subject.userFillContent : null,
optionFillContents: ["checkbox", "radio"].includes(subject.type) ? subject.optionFillContents : {}
}
})
})
@@ -0,0 +1,252 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="申诉受理" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
v-model="pageForm.searchKeyword"
:show-action="false"
input-align="left"
placeholder="请输入申诉标题搜索"
@search="doSearch"
></van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.appealTypeId" :options="typeOptions" @change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val === '1'; this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/appeal/accept/pageData" :page_form.sync="pageForm" @ready="onReady"
ref="tableListRef" title="title">
<template v-slot="{row}">
<table-column label="申诉人">{{row.userName}}</table-column>
<table-column label="申诉类型">{{row.appealTypeName}}</table-column>
<table-column label="被申诉单位">{{row.defendantUnitName}}</table-column>
<table-column label="申请日期">{{formatDate(row.applyDate)}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</table-column>
</template>
<template #actions="{row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" v-if="row.taskState === 10" @click="onDeal(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<appeal-info ref="appealInfoRef">
<div v-if="showApprovalForm" class="appeal-h5-audit-form">
<div class="process-title">受理申诉</div>
<van-form ref="formRef">
<van-field :value="formData.title" label="申诉标题" readonly></van-field>
<van-field
v-model="formData.decisionDate"
name="decisionDate"
label="决定日期"
placeholder="请选择决定日期"
:rules="[{ required: true, message: '请选择决定日期' }]"
required
readonly
is-link
@click="showDecisionDatePicker = true"
></van-field>
<van-popup v-model="showDecisionDatePicker" position="bottom">
<van-datetime-picker
v-model="decisionDateValue"
type="date"
title="选择决定日期"
@confirm="onDecisionDateConfirm"
@cancel="showDecisionDatePicker = false"
></van-datetime-picker>
</van-popup>
<van-field
v-model="formData.decisionContent"
name="decisionContent"
label="决定内容"
placeholder="请输入处理决定内容"
type="textarea"
rows="4"
maxlength="2000"
show-word-limit
:rules="[{ required: true, validator: validateText, message: '请输入处理决定内容' }]"
required
></van-field>
<van-field
v-model="formData.legalBasis"
name="legalBasis"
label="事实理由及依据"
placeholder="请输入事实理由及依据"
type="textarea"
rows="5"
maxlength="3000"
show-word-limit
:rules="[{ required: true, validator: validateText, message: '请输入事实理由及依据' }]"
required
></van-field>
<van-cell title="决定书附件" class="direction-column-cell">
<h5-file-upload :value.sync="formData.decisionFiles" :upload_number="5" upload_mode="file" upload_result_category="array" complete_result></h5-file-upload>
</van-cell>
</van-form>
<div class="h5-form-actions">
<van-button block @click="closeApprovalDialog">取消</van-button>
<van-button type="warning" block @click="doAccept(6)">退回修改</van-button>
<van-button type="danger" block @click="doAccept(2)">不予受理</van-button>
<van-button type="primary" block @click="doAccept(1)">受理并转执行</van-button>
</div>
</div>
</appeal-info>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
const vue = new Vue({
el: "#app",
store,
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: null,
appealTypeId: null,
year: null,
approvalText: "0",
approval: false
},
typeOptions: [{text: "全部类型", value: null}],
showApprovalForm: false,
showDecisionDatePicker: false,
decisionDateValue: new Date(),
formData: {},
currentTaskId: null
}
},
components: {
"appeal-info": appealInfo
},
methods: {
onReady() {
this.loadTypeOptions()
this.doSearch()
},
loadTypeOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) {
this.typeOptions = [{text: "全部类型", value: null}]
.concat((res.data || []).map((item) => ({text: item.name, value: item.id})))
}
})
},
onView(row) {
this.showApprovalForm = false
this.$refs.appealInfoRef.onOpen(row)
},
closeApprovalDialog() {
this.showApprovalForm = false
this.currentTaskId = null
this.$refs.appealInfoRef.onClose()
},
onDeal(row) {
this.currentTaskId = row.taskId
this.$axios.post("/platform/appeal/accept/queryTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.formData = res.data || row
if (!this.formData.decisionDate) {
this.$set(this.formData, "decisionDate", this.$moment().format("YYYY-MM-DD"))
}
this.decisionDateValue = this.formData.decisionDate ? new Date(this.formData.decisionDate) : new Date()
this.showApprovalForm = true
this.$refs.appealInfoRef.onOpen(this.formData)
}
})
},
onDecisionDateConfirm(value) {
this.$set(this.formData, "decisionDate", this.$moment(value).format("YYYY-MM-DD"))
this.showDecisionDatePicker = false
},
async doAccept(submitType) {
if (submitType !== 6) {
try {
await this.$refs.formRef.validate()
} catch (error) {
return
}
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/platform/appeal/accept/accept", {
data: JSON.stringify(this.formData),
taskId: this.currentTaskId,
submitType
}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.closeApprovalDialog()
this.doSearch()
}
})
}).catch(() => {
})
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
validateText(value, rule) {
return !!((value || "").trim())
},
formatDate(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : ""
}
}
})
</script>
<style>
.appeal-h5-audit-form {
padding-bottom: 12px;
}
.h5-form-actions {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
padding: 10px;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,113 @@
const appealInfo = {
template: /*language=HTML*/ `
<van-action-sheet v-model="visible" title="申诉详情">
<div class="detail-container appeal-detail">
<van-cell-group title="申诉基础信息">
<van-cell title="申诉标题">{{ text(viewData.title) }}</van-cell>
<van-cell title="申诉人">{{ text(viewData.userName) }}</van-cell>
<van-cell title="性别">{{ text(viewData.sex) }}</van-cell>
<van-cell title="出生年月">{{ dateText(viewData.birthday) }}</van-cell>
<van-cell title="政治面貌">{{ text(viewData.political) }}</van-cell>
<van-cell title="工号">{{ text(viewData.loginName) }}</van-cell>
<van-cell title="所在单位">{{ text(viewData.unitName) }}</van-cell>
<van-cell title="岗位">{{ text(viewData.positionName) }}</van-cell>
<van-cell title="联系电话">{{ text(viewData.mobile) }}</van-cell>
<van-cell title="申请日期">{{ dateText(viewData.applyDate) }}</van-cell>
<van-cell title="业务状态">{{ text(viewData.state || '草稿') }}</van-cell>
<van-cell class="direction-column-cell" title="住址">{{ text(viewData.address) }}</van-cell>
<van-cell title="申诉类型">{{ text(viewData.appealTypeName) }}</van-cell>
<van-cell title="被申诉单位">{{ text(viewData.defendantUnitName) }}</van-cell>
<van-cell class="direction-column-cell" title="被申诉单位地址">{{ text(viewData.defendantAddress) }}</van-cell>
<van-cell title="被申诉单位电话">{{ text(viewData.defendantContact) }}</van-cell>
<van-cell class="direction-column-cell" title="申诉事项">{{ text(viewData.appealMatter) }}</van-cell>
<van-cell class="direction-column-cell" title="申诉理由">{{ text(viewData.reason) }}</van-cell>
<van-cell class="direction-column-cell" title="申诉要求">{{ text(viewData.request) }}</van-cell>
<van-cell class="direction-column-cell" title="申诉材料附件">
<template slot="default">
<div v-if="fileList(viewData.files).length">
<div v-for="(file,index) in fileList(viewData.files)" :key="index">
<a :href="file.url || file.path || file" target="_blank">{{ file.name || file.fileName || ('附件' + (index + 1)) }}</a>
</div>
</div>
<span v-else>暂无</span>
</template>
</van-cell>
<van-cell title="申诉人签名">
<van-image v-if="viewData.signature" :src="viewData.signature" class="signature-image"></van-image>
<span v-else>暂无</span>
</van-cell>
</van-cell-group>
<van-cell-group title="受理与处理决定" v-if="viewData.acceptTime || viewData.decisionContent">
<van-cell title="受理人">{{ text(viewData.acceptUserName) }}</van-cell>
<van-cell title="受理时间">{{ text(viewData.acceptTime) }}</van-cell>
<van-cell title="决定日期">{{ dateText(viewData.decisionDate) }}</van-cell>
<van-cell class="direction-column-cell" title="决定内容">{{ text(viewData.decisionContent) }}</van-cell>
<van-cell class="direction-column-cell" title="事实理由及依据">{{ text(viewData.legalBasis) }}</van-cell>
</van-cell-group>
<van-cell-group title="执行情况" v-if="viewData.executeTime || viewData.executeContent">
<van-cell title="执行人">{{ text(viewData.executeUserName) }}</van-cell>
<van-cell title="执行时间">{{ text(viewData.executeTime) }}</van-cell>
<van-cell class="direction-column-cell" title="执行情况">{{ text(viewData.executeContent) }}</van-cell>
</van-cell-group>
<template v-for="task in doneTasks">
<van-cell-group :title="task.displayName" :key="task.id">
<van-cell title="办理用户">
{{ task.taskFormData && task.taskFormData.userName ? task.taskFormData.userName : task.ext.initiatorName }}
</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 title="办理意见" class="direction-column-cell" v-if="task.taskFormData && task.taskFormData.tf_opinion">
<div v-html="task.taskFormData.tf_opinion"></div>
</van-cell>
</van-cell-group>
</template>
</div>
<slot></slot>
</van-action-sheet>
`,
dicts: ["PROCESS_TASK_SUBMIT_TYPE"],
data() {
return {
visible: false,
viewData: {},
doneTasks: []
}
},
methods: {
onOpen(row) {
this.viewData = {...row}
this.visible = true
this.getDoneTasks()
},
getDoneTasks() {
if (!this.viewData.id) {
this.doneTasks = []
return
}
this.$axios.post("/flow/common/doneTasks", {bizId: this.viewData.id}).then((res) => {
if (res.code === 0) this.doneTasks = res.data || []
})
},
text(value) {
return value || "暂无"
},
dateText(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : "暂无"
},
fileList(value) {
if (!value) return []
if (Array.isArray(value)) return value
try {
const list = JSON.parse(value)
return Array.isArray(list) ? list : []
} catch (e) {
return []
}
}
}
}
@@ -0,0 +1,212 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar @click-left="historyBack" left-arrow left-text="返回" title="申诉执行" placeholder fixed></van-nav-bar>
<van-sticky offset-top="46px">
<van-search
v-model="pageForm.searchKeyword"
:show-action="false"
input-align="left"
placeholder="请输入申诉标题搜索"
@search="doSearch"
></van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.appealTypeId" :options="typeOptions" @change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
<van-tabs v-model="pageForm.approvalText"
@change="(val)=>{this.pageForm.approval = val === '1'; this.doSearch();}">
<van-tab title="已审核" name="1"></van-tab>
<van-tab title="未审核" name="0"></van-tab>
</van-tabs>
</van-sticky>
<table-list api="/platform/appeal/execute/pageData" :page_form.sync="pageForm" @ready="onReady"
ref="tableListRef" title="title">
<template v-slot="{row}">
<table-column label="申诉人">{{row.userName}}</table-column>
<table-column label="申诉类型">{{row.appealTypeName}}</table-column>
<table-column label="被申诉单位">{{row.defendantUnitName}}</table-column>
<table-column label="申请日期">{{formatDate(row.applyDate)}}</table-column>
<table-column label="当前节点">{{row.curTaskName}}</table-column>
</template>
<template #actions="{row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" v-if="row.taskState === 10" @click="onDeal(row)">
<i class="fa fa-edit"></i>
<span>审核</span>
</div>
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
<i class="fa fa-reply"></i>
<span>撤回</span>
</div>
</template>
</table-list>
<appeal-info ref="appealInfoRef">
<div v-if="showApprovalForm" class="appeal-h5-audit-form">
<div class="process-title">执行反馈</div>
<van-form ref="formRef">
<van-field :value="formData.title" label="申诉标题" readonly></van-field>
<van-field
v-model="formData.executeContent"
name="executeContent"
label="执行情况"
placeholder="请输入执行情况"
type="textarea"
rows="5"
maxlength="2000"
show-word-limit
:rules="[{ required: true, validator: validateText, message: '请输入执行情况' }]"
required
></van-field>
<van-cell title="执行附件" class="direction-column-cell">
<h5-file-upload :value.sync="formData.executeFiles" :upload_number="5" upload_mode="file" upload_result_category="array" complete_result></h5-file-upload>
</van-cell>
</van-form>
<div class="h5-form-actions">
<van-button block @click="closeApprovalDialog">取消</van-button>
<van-button type="primary" block @click="doExecute">提交</van-button>
</div>
</div>
</appeal-info>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
const vue = new Vue({
el: "#app",
store,
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: null,
appealTypeId: null,
year: null,
approvalText: "0",
approval: false
},
typeOptions: [{text: "全部类型", value: null}],
showApprovalForm: false,
formData: {},
currentTaskId: null
}
},
components: {
"appeal-info": appealInfo
},
methods: {
onReady() {
this.loadTypeOptions()
this.doSearch()
},
loadTypeOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) {
this.typeOptions = [{text: "全部类型", value: null}]
.concat((res.data || []).map((item) => ({text: item.name, value: item.id})))
}
})
},
onView(row) {
this.showApprovalForm = false
this.$refs.appealInfoRef.onOpen(row)
},
closeApprovalDialog() {
this.showApprovalForm = false
this.currentTaskId = null
this.$refs.appealInfoRef.onClose()
},
onDeal(row) {
this.currentTaskId = row.taskId
this.$axios.post("/platform/appeal/execute/queryTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.formData = res.data || row
this.showApprovalForm = true
this.$refs.appealInfoRef.onOpen(this.formData)
}
})
},
async doExecute() {
try {
await this.$refs.formRef.validate()
} catch (error) {
return
}
this.$dialog.confirm({
title: "提示",
message: "您确定要提交吗?"
}).then(() => {
this.$axios.post("/platform/appeal/execute/execute", {
data: JSON.stringify(this.formData),
taskId: this.currentTaskId
}).then((res) => {
if (res.code === 0) {
const finishedTaskId = this.currentTaskId
this.$toast.success(res.msg)
this.closeApprovalDialog()
this.removeTaskFromList(finishedTaskId)
setTimeout(() => this.doSearch(), 300)
}
})
}).catch(() => {
})
},
onRevoke(row) {
this.$dialog.confirm({
title: "提示",
message: "您确定要撤回吗?"
}).then(() => {
this.$axios.post("/flow/common/revokeTask", {taskId: row.taskId}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {
})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
removeTaskFromList(taskId) {
const tableList = this.$refs.tableListRef
if (!tableList || !taskId) return
tableList.tableData = (tableList.tableData || []).filter((row) => row.taskId !== taskId)
tableList.localPageForm.totalCount = Math.max((tableList.localPageForm.totalCount || 1) - 1, 0)
},
validateText(value, rule) {
return !!((value || "").trim())
},
formatDate(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : ""
}
}
})
</script>
<style>
.appeal-h5-audit-form {
padding-bottom: 12px;
}
.h5-form-actions {
display: flex;
column-gap: 10px;
padding: 10px;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,142 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="申诉管理" fixed placeholder left-text="返回" left-arrow @click-left="historyBack"></van-nav-bar>
<div class="appeal-entry-list">
<div class="entry-card" v-if="$auth.hasPermission('h5.appeal.write')" @click="goPage('/platform/appeal/write/h5')">
<div class="entry-icon write-icon">
<van-icon name="edit"></van-icon>
</div>
<div class="entry-info">
<div class="entry-title">提交申诉</div>
<div class="entry-desc">填写并提交个人申诉申请</div>
</div>
<van-icon name="arrow" class="entry-arrow"></van-icon>
</div>
<div class="entry-card" v-if="$auth.hasPermission('h5.appeal.mine')" @click="goPage('/platform/appeal/mine/h5')">
<div class="entry-icon mine-icon">
<van-icon name="records"></van-icon>
</div>
<div class="entry-info">
<div class="entry-title">我的申诉</div>
<div class="entry-desc">查看本人申诉记录和办理进度</div>
</div>
<van-icon name="arrow" class="entry-arrow"></van-icon>
</div>
<div class="entry-card" v-if="$auth.hasPermission('h5.appeal.accept')" @click="goPage('/platform/appeal/accept/h5')">
<div class="entry-icon accept-icon">
<van-icon name="todo-list-o"></van-icon>
</div>
<div class="entry-info">
<div class="entry-title">申诉受理</div>
<div class="entry-desc">处理申诉受理环节任务</div>
</div>
<van-icon name="arrow" class="entry-arrow"></van-icon>
</div>
<div class="entry-card" v-if="$auth.hasPermission('h5.appeal.execute')" @click="goPage('/platform/appeal/execute/h5')">
<div class="entry-icon execute-icon">
<van-icon name="passed"></van-icon>
</div>
<div class="entry-info">
<div class="entry-title">申诉执行</div>
<div class="entry-desc">反馈申诉处理决定执行情况</div>
</div>
<van-icon name="arrow" class="entry-arrow"></van-icon>
</div>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
methods: {
goPage(url) {
this.$pjaxReplace(url)
}
}
})
</script>
<style>
body {
background: #f7f8fa;
}
.appeal-entry-list {
padding: 12px;
}
.entry-card {
display: flex;
align-items: center;
min-height: 72px;
margin-bottom: 10px;
padding: 14px 12px;
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, .04);
}
.entry-icon {
display: flex;
align-items: center;
justify-content: center;
width: 42px;
height: 42px;
border-radius: 8px;
color: #fff;
font-size: 23px;
flex-shrink: 0;
}
.write-icon {
background: #1989fa;
}
.mine-icon {
background: #07c160;
}
.accept-icon {
background: #ff976a;
}
.execute-icon {
background: #7232dd;
}
.entry-info {
flex: 1;
min-width: 0;
margin-left: 12px;
}
.entry-title {
color: #323233;
font-size: 16px;
font-weight: 600;
line-height: 22px;
}
.entry-desc {
margin-top: 4px;
color: #969799;
font-size: 13px;
line-height: 18px;
}
.entry-arrow {
color: #c8c9cc;
font-size: 18px;
flex-shrink: 0;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,120 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.van-cell__value {
min-width: 62%;
}
</style>
<div id="app">
<van-nav-bar title="我的申诉" left-text="返回" right-text="提交" left-arrow @click-left="historyBack" @click-right="onWrite" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-dropdown-menu :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-menu>
</van-sticky>
<table-list api="/platform/appeal/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="title" @ready="doSearch">
<template v-slot="{index,row}">
<table-column label="申诉类型">{{row.appealTypeName}}</table-column>
<table-column label="被申诉单位">{{row.defendantUnitName}}</table-column>
<table-column label="申请日期">{{row.applyDate}}</table-column>
<table-column label="业务状态">{{row.state || '草稿'}}</table-column>
<table-column label="当前节点">{{row.taskName}}</table-column>
</template>
<template #actions="{index,row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" @click="onEdit(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onRevoke(row)" v-if="row.canRevoke">
<i class="fa fa-undo"></i>
<span>撤回</span>
</div>
<div class="action-btn delete" @click="onDelete(row)" v-if="row.taskKey === 'startTask' || !row.instanceId">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<appeal-info ref="infoRef"></appeal-info>
</div>
<script nonce="${cspNonce!}">
<!--#include("../common/info.js"){}#-->
new Vue({
el: "#app",
store,
components: {
"appeal-info": appealInfo
},
data() {
return {
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
year: new Date().getFullYear()
}
}
},
methods: {
onView(row) {
this.$refs.infoRef.onOpen(row)
},
onWrite() {
this.$pjaxReplace("/platform/appeal/write/h5")
},
onEdit(row) {
this.$pjaxReplace("/platform/appeal/write/h5?taskId=" + (row.startTaskId || "") + "&id=" + row.id)
},
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()
}
})
})
},
onDelete(row) {
this.$dialog.confirm({
title: "提示",
message: "确定要删除此申诉吗?"
}).then(() => {
this.$axios.post("/platform/appeal/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(() => {})
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
}
}
})
</script>
<!--#
}
#-->
@@ -0,0 +1,225 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<style scoped>
.appeal-actions {
display: flex;
gap: 10px;
padding: 14px 16px 24px;
background: #f7f8fa;
}
.appeal-actions .van-button {
flex: 1;
}
</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">
<van-cell-group title="申诉人基本信息" class="form-section">
<van-field label="申诉人" v-model="formData.userName" readonly required :rules="[{required:true}]"></van-field>
<van-field label="性别" v-model="formData.sex" placeholder="请输入性别" required :rules="[{required:true}]"></van-field>
<van-field label="出生年月" v-model="formData.birthday" type="date" placeholder="请选择出生年月" required :rules="[{required:true}]"></van-field>
<van-field label="政治面貌" v-model="formData.political" placeholder="请输入政治面貌" required :rules="[{required:true}]"></van-field>
<van-field label="工号" v-model="formData.loginName" readonly></van-field>
<van-field label="所在单位" v-model="formData.unitName" readonly></van-field>
<van-field label="岗位" v-model="formData.positionName" placeholder="请输入岗位" required :rules="[{required:true}]"></van-field>
<van-field label="联系电话" name="mobile" v-model="formData.mobile" placeholder="请输入手机或办公电话" required :rules="phoneRules"></van-field>
<van-field label="申请日期" v-model="formData.applyDate" type="date" placeholder="请选择申请日期" required :rules="[{required:true}]"></van-field>
<van-field class="direction-column-field" label="住址" v-model="formData.address" placeholder="请输入住址" required :rules="[{required:true}]" type="textarea" rows="2" autosize></van-field>
</van-cell-group>
<van-cell-group title="申诉事项" class="form-section">
<van-field
label="申诉类型"
v-model="formData.appealTypeName"
placeholder="请选择申诉类型"
required
readonly
is-link
:rules="[{required:true}]"
@click="showTypePopup = true"
></van-field>
<van-field label="申诉标题" v-model="formData.title" placeholder="请输入申诉标题" required :rules="[{required:true}]" maxlength="200"></van-field>
<van-field
label="被申诉单位"
v-model="formData.defendantUnitName"
placeholder="请选择被申诉单位"
required
readonly
is-link
:rules="[{required:true}]"
@click="showUnitPopup = true"
></van-field>
<van-field class="direction-column-field" label="被申诉单位地址" v-model="formData.defendantAddress" placeholder="请输入被申诉单位地址" required :rules="[{required:true}]" type="textarea" rows="2" autosize></van-field>
<van-field label="被申诉单位电话" name="defendantContact" v-model="formData.defendantContact" placeholder="请输入联系电话" required :rules="phoneRules"></van-field>
<van-field class="direction-column-field" label="申诉事项" v-model="formData.appealMatter" placeholder="请输入申诉事项" required :rules="[{required:true, validator: validateText}]" type="textarea" rows="4" maxlength="1000" show-word-limit autosize></van-field>
<van-field class="direction-column-field" label="申诉理由" v-model="formData.reason" placeholder="请输入申诉理由" required :rules="[{required:true, validator: validateText}]" type="textarea" rows="5" maxlength="2000" show-word-limit autosize></van-field>
<van-field class="direction-column-field" label="申诉要求" v-model="formData.request" placeholder="请输入申诉要求" required :rules="[{required:true, validator: validateText}]" type="textarea" rows="4" maxlength="1000" show-word-limit autosize></van-field>
</van-cell-group>
<van-cell-group title="申诉材料附件" class="form-section">
<van-field class="direction-column-field" label="" required :rules="[{validator: validateFiles, message:'请上传申诉材料附件'}]">
<template #input>
<h5-file-upload :value.sync="formData.files" :upload_number="5" upload_mode="file" upload_result_category="array" complete_result></h5-file-upload>
</template>
</van-field>
</van-cell-group>
<van-cell-group title="申诉人签名" class="form-section">
<van-field class="direction-column-field" label="" required :rules="[{validator: validateSignature, message:'请完成申诉人签名'}]">
<template #input>
<h5-signature v-model="formData.signature"></h5-signature>
</template>
</van-field>
</van-cell-group>
<div class="appeal-actions">
<van-button native-type="button" @click="onSave" round type="info" plain>保存</van-button>
<van-button native-type="button" @click="onSubmit" round type="info">{{ hasTaskId() ? '提交' : '提交申诉' }}</van-button>
</div>
</van-form>
<van-popup v-model="showTypePopup" position="bottom">
<van-picker show-toolbar :columns="typeOptions.map(i => i.name)" @confirm="onTypeConfirm" @cancel="showTypePopup = false"></van-picker>
</van-popup>
<van-popup v-model="showUnitPopup" position="bottom">
<van-picker show-toolbar :columns="unitOptions.map(i => i.name)" @confirm="onUnitConfirm" @cancel="showUnitPopup = false"></van-picker>
</van-popup>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
taskId: null,
formData: {
files: []
},
typeOptions: [],
unitOptions: [],
showTypePopup: false,
showUnitPopup: false,
phoneRules: [
{required: true, message: "请输入联系电话"},
{validator: this.validatePhone, message: "请输入正确的联系电话"}
]
}
},
methods: {
queryParam(name) {
return new URLSearchParams(window.location.search).get(name)
},
hasTaskId() {
return !!this.taskId && this.taskId !== "undefined" && this.taskId !== "null"
},
validatePhone(value) {
if (!value) return true
return /^((1[3-9]\d{9})|(0\d{2,3}-?\d{7,8})|(\d{6,12}))$/.test(String(value).trim())
},
validateText(value) {
return !!(value || "").trim()
},
validateFiles() {
return this.formData.files && this.formData.files.length > 0
},
validateSignature() {
return !!this.formData.signature
},
loadOptions() {
this.$axios.post("/platform/appeal/common/typeOptions").then((res) => {
if (res.code === 0) this.typeOptions = res.data || []
})
this.$axios.post("/platform/appeal/common/unitOptions").then((res) => {
if (res.code === 0) this.unitOptions = res.data || []
})
},
loadCurrentUser() {
this.$axios.post("/platform/appeal/write/currentUserInfo").then((res) => {
if (res.code === 0) {
this.formData = Object.assign({files: []}, res.data, this.formData)
this.normalizeDates()
}
})
},
loadInfo(id) {
this.$axios.post("/platform/appeal/write/info", {id}).then((res) => {
if (res.code === 0 && res.data) {
this.formData = Object.assign({files: []}, res.data)
this.normalizeDates()
}
})
},
normalizeDates() {
;["birthday", "applyDate"].forEach((key) => {
if (this.formData[key]) {
this.$set(this.formData, key, this.$moment(this.formData[key]).format("YYYY-MM-DD"))
}
})
},
onTypeConfirm(value, index) {
const item = this.typeOptions[index]
this.$set(this.formData, "appealTypeId", item ? item.id : "")
this.$set(this.formData, "appealTypeName", value || "")
this.showTypePopup = false
},
onUnitConfirm(value, index) {
const item = this.unitOptions[index]
this.$set(this.formData, "defendantUnitId", item ? item.id : "")
this.$set(this.formData, "defendantUnitName", value || "")
this.$set(this.formData, "defendantAddress", item ? item.address : this.formData.defendantAddress)
this.$set(this.formData, "defendantContact", item ? item.telephone : this.formData.defendantContact)
this.showUnitPopup = false
},
onSave() {
this.$dialog.confirm({
title: "提示",
message: "您确定保存吗?"
}).then(() => {
this.$axios.post("/platform/appeal/write/save", {data: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.formData = Object.assign({files: []}, res.data)
this.normalizeDates()
}
})
})
},
onSubmit() {
this.$refs.formRef.validate().then(() => {
const url = this.hasTaskId() ? "/platform/appeal/write/submitAgain" : "/platform/appeal/write/submit"
this.$dialog.confirm({
title: "提示",
message: "您确定提交该申诉吗?"
}).then(() => {
this.$axios.post(url, {data: JSON.stringify(this.formData), taskId: this.taskId}).then((res) => {
if (res.code === 0) {
this.$toast(res.msg)
this.$pjaxReplace("/platform/appeal/mine/h5")
}
})
})
})
}
},
created() {
this.taskId = this.queryParam("taskId")
const id = this.queryParam("id")
this.loadOptions()
if (id) {
this.loadInfo(id)
} else {
this.loadCurrentUser()
}
}
})
</script>
<!--#
}
#-->
@@ -431,7 +431,7 @@ layout("/layouts/platform_h5.html"){
.then((res) => {
this.typeOptions = JSON.parse(JSON.stringify(res.data))
res.data.forEach((v) => {
this.typeColumns.push({ value: v.id, text: v.name + "(" + v.code + ")" })
this.typeColumns.push({ value: v.id, text: v.name })
})
})
},
@@ -0,0 +1,417 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="离退休人员档案" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-search v-model="pageForm.searchKeyword" placeholder="请输入姓名或工号搜索" show-action input-align="left" @search="doSearch">
<template #action>
<div @click="doSearch">搜索</div>
</template>
</van-search>
<div class="retired-toolbar">
<van-button class="toolbar-button" icon="plus" size="small" type="primary" block @click="openAdd">新增退休人员</van-button>
<van-button class="toolbar-button" icon="setting-o" size="small" type="info" block @click="openSet">设置退休人员</van-button>
</div>
</van-sticky>
<table-list api="/platform/retired/list/pageData" :page_form.sync="pageForm" ref="tableListRef" title="username" @ready="onReady">
<template v-slot="{row}">
<table-column label="工号">{{row.loginname}}</table-column>
<table-column label="性别">{{row.sex}}</table-column>
<table-column label="联系电话">{{row.mobile}}</table-column>
<table-column label="出生日期">{{formatDate(row.birthday)}}</table-column>
<table-column label="在职状态">{{row.userState}}</table-column>
<table-column label="人员类型">{{row.personType}}</table-column>
<table-column label="所属单位">{{row.unitname}}</table-column>
<table-column label="退休小组">{{row.retiredGroupName || '暂无'}}</table-column>
</template>
<template #actions="{row}">
<div class="action-btn" @click="openView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" @click="openEdit(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="doDelete(row)">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<van-action-sheet v-model="infoVisible" title="人员档案详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="工号">{{emptyText(viewData.loginname)}}</van-cell>
<van-cell title="姓名">{{emptyText(viewData.username)}}</van-cell>
<van-cell title="性别">{{emptyText(viewData.sex)}}</van-cell>
<van-cell title="出生日期">{{formatDate(viewData.birthday) || '暂无'}}</van-cell>
<van-cell title="身份证号">{{emptyText(viewData.idCard)}}</van-cell>
<van-cell title="政治面貌">{{emptyText(viewData.political)}}</van-cell>
<van-cell title="籍贯">{{emptyText(viewData.nativePlace)}}</van-cell>
<van-cell title="联系电话">{{emptyText(viewData.mobile)}}</van-cell>
<van-cell title="参加工作时间">{{emptyText(viewData.arrivalAtSchoolDate)}}</van-cell>
<van-cell title="工龄">{{workAgeText(viewData.arrivalAtSchoolDate) || '暂无'}}</van-cell>
<van-cell title="退休时间">{{formatDate(viewData.retireDate) || '暂无'}}</van-cell>
<van-cell title="职务">{{emptyText(viewData.position)}}</van-cell>
<van-cell title="职称">{{emptyText(viewData.professionalTitle)}}</van-cell>
<van-cell title="在职状态">{{emptyText(viewData.userState)}}</van-cell>
<van-cell title="人员类型">{{emptyText(viewData.personType)}}</van-cell>
<van-cell title="所属工会">{{emptyText(viewData.unionName)}}</van-cell>
<van-cell title="所属单位">{{emptyText(viewData.unitName)}}</van-cell>
<van-cell title="退休小组">{{emptyText(viewData.retiredGroupName)}}</van-cell>
<van-cell title="退休党支部">{{emptyText(viewData.retiredPartyBranchName)}}</van-cell>
</van-cell-group>
</div>
</van-action-sheet>
<van-action-sheet v-model="formVisible" :title="formUserId ? '编辑退休人员' : '新增退休人员'">
<van-form ref="formRef" class="h5-form-sheet">
<van-field v-model="formData.loginname" name="loginname" label="工号" maxlength="120" placeholder="请输入工号" required :rules="[{required:true,message:'请输入工号'}]"></van-field>
<van-field v-model="formData.username" name="username" label="姓名" maxlength="100" placeholder="请输入姓名" required :rules="[{required:true,message:'请输入姓名'}]"></van-field>
<van-field v-model="formData.nativePlace" label="籍贯" maxlength="100" placeholder="请输入籍贯"></van-field>
<van-field v-model="formData.sex" name="sex" label="性别" placeholder="请选择性别" readonly is-link required :rules="[{required:true,message:'请选择性别'}]" @click="showSexPicker = true"></van-field>
<van-field v-model="formData.birthday" label="出生日期" type="date" placeholder="请选择出生日期"></van-field>
<van-field v-model="formData.idCard" name="idCard" label="身份证号" maxlength="30" placeholder="请输入身份证号" :rules="idCardRules"></van-field>
<van-field v-model="formData.political" label="政治面貌" maxlength="100" placeholder="请输入政治面貌"></van-field>
<van-field v-model="formData.arrivalAtSchoolDate" label="参加工作时间" maxlength="20" placeholder="请输入参加工作时间"></van-field>
<van-field :value="workAgeText(formData.arrivalAtSchoolDate)" label="工龄" readonly placeholder="系统自动计算"></van-field>
<van-field v-model="formData.unitName" label="单位" placeholder="请选择单位" readonly is-link @click="showUnitPicker = true"></van-field>
<van-field v-model="formData.unionName" label="工会" readonly placeholder="系统自动显示"></van-field>
<van-field v-model="formData.position" label="职务" maxlength="50" placeholder="请输入职务"></van-field>
<van-field v-model="formData.professionalTitle" label="职称" maxlength="50" placeholder="请输入职称"></van-field>
<van-field v-model="formData.retireDate" label="退休时间" type="date" placeholder="请选择退休时间"></van-field>
<van-field v-model="formData.mobile" label="电话" maxlength="32" placeholder="请输入电话"></van-field>
<van-field v-model="formData.userState" name="userState" label="在职状态" placeholder="请选择在职状态" readonly is-link required :rules="[{required:true,message:'请选择在职状态'}]" @click="showUserStatePicker = true"></van-field>
<van-field v-model="formData.personType" name="personType" label="人员类型" placeholder="请选择人员类型" readonly is-link required :rules="[{required:true,message:'请选择人员类型'}]" @click="showPersonTypePicker = true"></van-field>
</van-form>
<div class="h5-form-actions">
<van-button class="sheet-button" block @click="formVisible = false">取消</van-button>
<van-button class="sheet-button" icon="success" block type="primary" @click="submitForm">确定</van-button>
</div>
</van-action-sheet>
<van-action-sheet v-model="setVisible" title="设置退休人员">
<van-search v-model="nonRetiredUserPageForm.searchKeyword" placeholder="请输入姓名或工号搜索" show-action @search="searchNonRetiredUsers">
<template #action>
<div @click="searchNonRetiredUsers">搜索</div>
</template>
</van-search>
<van-checkbox-group v-model="selectedUserIds" class="retired-user-list">
<van-cell v-for="item in nonRetiredUserList" :key="item.id" :title="item.username + '(' + item.loginname + ')'" :label="nonRetiredUserLabel(item)" clickable @click="toggleUser(item.id)">
<template #right-icon>
<van-checkbox :name="item.id" ref="userCheckboxes" @click.stop></van-checkbox>
</template>
</van-cell>
</van-checkbox-group>
<van-empty v-if="!nonRetiredUserList.length" description="暂无人员"></van-empty>
<div class="retired-page-actions">
<van-button class="page-button" size="small" :disabled="nonRetiredUserPageForm.pageNumber <= 1" @click="changeNonRetiredPage(-1)">上一页</van-button>
<span>第{{nonRetiredUserPageForm.pageNumber}}页 / 共{{nonRetiredUserPageForm.totalCount}}人</span>
<van-button class="page-button" size="small" :disabled="nonRetiredUserPageForm.pageNumber * nonRetiredUserPageForm.pageSize >= nonRetiredUserPageForm.totalCount" @click="changeNonRetiredPage(1)">下一页</van-button>
</div>
<div class="h5-form-actions">
<van-button class="sheet-button" block @click="setVisible = false">取消</van-button>
<van-button class="sheet-button" icon="success" block type="primary" @click="doBatchJoinRetire">确定</van-button>
</div>
</van-action-sheet>
<van-popup v-model="showSexPicker" position="bottom">
<van-picker show-toolbar :columns="sexOptions" @confirm="(value)=>{formData.sex=value;showSexPicker=false}" @cancel="showSexPicker = false"></van-picker>
</van-popup>
<van-popup v-model="showUserStatePicker" position="bottom">
<van-picker show-toolbar :columns="userStateOptions" @confirm="(value)=>{formData.userState=value;showUserStatePicker=false}" @cancel="showUserStatePicker = false"></van-picker>
</van-popup>
<van-popup v-model="showPersonTypePicker" position="bottom">
<van-picker show-toolbar :columns="personTypeOptions" @confirm="(value)=>{formData.personType=value;showPersonTypePicker=false}" @cancel="showPersonTypePicker = false"></van-picker>
</van-popup>
<van-popup v-model="showUnitPicker" position="bottom">
<van-picker show-toolbar :columns="unitColumns" @confirm="onUnitConfirm" @cancel="showUnitPicker = false"></van-picker>
</van-popup>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0},
infoVisible: false,
formVisible: false,
setVisible: false,
showSexPicker: false,
showUserStatePicker: false,
showPersonTypePicker: false,
showUnitPicker: false,
viewData: {},
formData: {},
formUserId: "",
units: [],
sexOptions: ["男", "女"],
userStateOptions: ["退休", "离休", "离退休"],
personTypeOptions: ["离退休人员"],
idCardRules: [
{
validator: (value) => !value || /(^\d{15}$)|(^\d{17}[\dXx]$)/.test(value),
message: "请输入正确的身份证号码"
}
],
nonRetiredUserPageForm: {pageNumber: 1, pageSize: 10, totalCount: 0},
nonRetiredUserList: [],
selectedUserIds: []
}
},
computed: {
unitColumns() {
return this.units.map((item) => item.name)
}
},
methods: {
onReady() {
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
openView(row) {
this.$axios.post("/platform/retired/list/userInfo", {userId: row.id}).then((res) => {
if (res.code === 0) {
this.viewData = this.normalizeUserData(res.data || row)
this.infoVisible = true
}
})
},
openAdd() {
this.formUserId = ""
this.formData = this.defaultFormData()
this.formVisible = true
},
openEdit(row) {
this.$axios.post("/platform/retired/list/userInfo", {userId: row.id}).then((res) => {
if (res.code === 0) {
this.formUserId = row.id
this.formData = this.normalizeUserData(res.data || row)
this.formVisible = true
}
})
},
submitForm() {
this.$refs.formRef.validate().then(() => {
this.$axios.post("/platform/retired/list/doSubmit", {
user: JSON.stringify(this.formData),
userId: this.formUserId
}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.formVisible = false
this.doSearch()
}
})
})
},
doDelete(row) {
this.$dialog.confirm({title: "提示", message: "您确定要删除吗?"}).then(() => {
this.$axios.post("/platform/retired/list/doDelete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {})
},
openSet() {
this.setVisible = true
this.selectedUserIds = []
this.nonRetiredUserPageForm = {pageNumber: 1, pageSize: 10, totalCount: 0}
this.nonRetiredUserPageData()
},
searchNonRetiredUsers() {
this.nonRetiredUserPageForm.pageNumber = 1
this.nonRetiredUserPageData()
},
changeNonRetiredPage(step) {
this.nonRetiredUserPageForm.pageNumber = this.nonRetiredUserPageForm.pageNumber + step
this.nonRetiredUserPageData()
},
nonRetiredUserPageData() {
this.$axios.post("/platform/retired/list/nonRetiredUserPageData", this.nonRetiredUserPageForm).then((res) => {
if (res.code === 0) {
this.nonRetiredUserList = (res.data && res.data.list) || []
this.$set(this.nonRetiredUserPageForm, "totalCount", (res.data && res.data.totalCount) || 0)
}
})
},
toggleUser(id) {
const index = this.selectedUserIds.indexOf(id)
if (index >= 0) {
this.selectedUserIds.splice(index, 1)
} else {
this.selectedUserIds.push(id)
}
},
doBatchJoinRetire() {
if (!this.selectedUserIds.length) {
this.$toast("请先选择需要设置为退休的人员")
return
}
this.$axios.post("/platform/retired/list/doBatchJoinRetire", {userIds: JSON.stringify(this.selectedUserIds)}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.setVisible = false
this.doSearch()
}
})
},
onUnitConfirm(value) {
const unit = this.units.find((item) => item.name === value)
this.$set(this.formData, "unitName", unit ? unit.name : "")
this.$set(this.formData, "unitId", unit ? unit.id : "")
this.$set(this.formData, "unionName", unit ? (unit.unionName || unit.unionname || "") : "")
this.$set(this.formData, "unionId", unit ? (unit.unionId || unit.unionid || "") : "")
this.showUnitPicker = false
},
defaultFormData() {
return {
userState: "退休",
personType: "离退休人员",
families: []
}
},
normalizeUserData(user) {
const data = Object.assign(this.defaultFormData(), user)
const fieldMap = {
idcard: "idCard",
nativeplace: "nativePlace",
professionaltitle: "professionalTitle",
arrivalatschooldate: "arrivalAtSchoolDate",
userstate: "userState",
persontype: "personType",
retiredate: "retireDate",
unitid: "unitId",
unitname: "unitName",
unionid: "unionId",
unionname: "unionName",
retiredgroupname: "retiredGroupName",
retiredpartybranchname: "retiredPartyBranchName"
}
Object.keys(fieldMap).forEach((key) => {
if ((data[fieldMap[key]] === undefined || data[fieldMap[key]] === null) && user[key] !== undefined) {
this.$set(data, fieldMap[key], user[key])
}
})
data.birthday = this.formatDate(data.birthday)
data.retireDate = this.formatDate(data.retireDate)
if (typeof data.families === "string") {
try {
data.families = JSON.parse(data.families)
} catch (e) {
data.families = []
}
}
return data
},
formatDate(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : ""
},
emptyText(value) {
return value === undefined || value === null || value === "" ? "暂无" : value
},
nonRetiredUserLabel(item) {
return [item.sex, item.mobile, item.unitname].filter(Boolean).join(" / ")
},
workAgeText(value) {
const start = this.parseWorkDate(value)
if (!start) return ""
const today = new Date()
let years = today.getFullYear() - start.getFullYear()
if (today.getMonth() < start.getMonth() || (today.getMonth() === start.getMonth() && today.getDate() < start.getDate())) {
years = years - 1
}
return Math.max(years, 0) + "年"
},
parseWorkDate(value) {
if (!value) return null
const parts = String(value).split("-")
const year = Number(parts[0])
const month = parts.length > 1 ? Number(parts[1]) : 1
const day = parts.length > 2 ? Number(parts[2]) : 1
if (!year || !month || !day) return null
const date = new Date(year, month - 1, day)
return isNaN(date.getTime()) ? null : date
},
async loadUnits() {
this.units = await this.$businessTool.listUnit()
}
},
created() {
this.loadUnits()
}
})
</script>
<style>
.retired-toolbar {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
padding: 10px 12px 12px;
background: #fff;
border-top: 1px solid #f5f5f5;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
}
.retired-toolbar .toolbar-button {
height: 36px;
border-radius: 6px;
font-weight: 500;
}
.h5-form-sheet {
max-height: 70vh;
overflow-y: auto;
}
.h5-form-actions {
display: flex;
column-gap: 10px;
padding: 10px 12px 12px;
background: #fff;
border-top: 1px solid #f5f5f5;
}
.h5-form-actions .sheet-button {
height: 40px;
border-radius: 6px;
}
.retired-user-list {
max-height: 55vh;
overflow-y: auto;
}
.retired-page-actions {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 12px;
color: #666;
font-size: 13px;
background: #fff;
}
.retired-page-actions .page-button {
min-width: 72px;
border-radius: 6px;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,292 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="单身教职工管理" left-text="返回" right-text="新增" left-arrow @click-left="historyBack" @click-right="onAdd" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-search v-model="pageForm.searchKeyword" placeholder="请输入姓名或工号搜索" show-action input-align="left" @search="doSearch">
<template #action>
<div @click="doSearch">搜索</div>
</template>
</van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.unionId" :options="unionOptions" @change="unionChange"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.unitId" :options="unitOptions" @change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/singleTeacher/ledger/pageData" :page_form.sync="pageForm" json ref="tableListRef" title="username" @ready="onReady">
<template v-slot="{row}">
<table-column label="工号">{{row.loginname}}</table-column>
<table-column label="性别">{{row.sex}}</table-column>
<table-column label="手机号码">{{row.mobile}}</table-column>
<table-column label="出生日期">{{formatDate(row.birthday)}}</table-column>
<table-column label="学历">{{row.education}}</table-column>
<table-column label="婚姻状况">{{row.maritalStatus}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
</template>
<template #actions="{row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" @click="onEdit(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onDelete(row)">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<van-action-sheet v-model="infoVisible" title="单身教职工详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="姓名">{{viewData.username || '暂无'}}</van-cell>
<van-cell title="工号">{{viewData.loginname || '暂无'}}</van-cell>
<van-cell title="性别">{{viewData.sex || '暂无'}}</van-cell>
<van-cell title="手机号码">{{viewData.mobile || '暂无'}}</van-cell>
<van-cell title="出生日期">{{formatDate(viewData.birthday) || '暂无'}}</van-cell>
<van-cell title="学历">{{viewData.education || '暂无'}}</van-cell>
<van-cell title="婚姻状况">{{viewData.maritalStatus || '暂无'}}</van-cell>
<van-cell title="所属工会">{{viewData.unionName || '暂无'}}</van-cell>
<van-cell title="所属单位">{{viewData.unitName || '暂无'}}</van-cell>
<van-cell title="身高">{{viewData.height || '暂无'}}</van-cell>
<van-cell title="籍贯">{{viewData.nativePlace || '暂无'}}</van-cell>
<van-cell title="月收入">{{viewData.monthlyIncome || '暂无'}}</van-cell>
<van-cell title="住房情况">{{viewData.housingSituation || '暂无'}}</van-cell>
<van-cell title="兴趣爱好" class="direction-column-cell">{{viewData.hobby || '暂无'}}</van-cell>
<van-cell title="交友意向" class="direction-column-cell">{{viewData.intentionFriends || '暂无'}}</van-cell>
<van-cell title="个人介绍" class="direction-column-cell">{{viewData.introduction || '暂无'}}</van-cell>
<van-cell title="形象照片" class="direction-column-cell">
<van-image v-if="viewData.photo" :src="viewData.photo" width="120" height="120" fit="cover"></van-image>
<span v-else>暂无</span>
</van-cell>
</van-cell-group>
</div>
</van-action-sheet>
<van-action-sheet v-model="formVisible" :title="formData.id ? '编辑单身教职工' : '新增单身教职工'">
<van-form ref="formRef" class="h5-form-sheet">
<van-field v-if="!formData.id" v-model="userLabel" name="userId" label="选择用户" placeholder="请选择用户" required readonly is-link :rules="[{required:true,message:'请选择用户'}]" @click="openUserPicker"></van-field>
<van-field v-else :value="formData.username" label="用户信息" readonly></van-field>
<van-field v-model="formData.mobile" name="mobile" label="联系方式" placeholder="请输入手机号" required :rules="mobileRules"></van-field>
<van-field v-model="formData.birthday" name="birthday" label="出生日期" type="date" placeholder="请选择出生日期" required :rules="[{required:true,message:'请选择出生日期'}]"></van-field>
<van-field v-model="formData.height" name="height" label="身高(cm)" placeholder="请输入身高" :rules="heightRules"></van-field>
<van-field v-model="formData.nativePlace" label="籍贯" placeholder="请输入籍贯"></van-field>
<van-field v-model="formData.education" name="education" label="学历" placeholder="请选择学历" required readonly is-link :rules="[{required:true,message:'请选择学历'}]" @click="showEducationPicker = true"></van-field>
<van-field v-model="formData.maritalStatus" name="maritalStatus" label="婚姻状况" placeholder="请选择婚姻状况" required readonly is-link :rules="[{required:true,message:'请选择婚姻状况'}]" @click="showMaritalPicker = true"></van-field>
<van-field v-model="formData.monthlyIncome" label="月收入" placeholder="请选择月收入" readonly is-link @click="showIncomePicker = true"></van-field>
<van-field v-model="formData.housingSituation" label="住房情况" placeholder="请选择住房情况" readonly is-link @click="showHousingPicker = true"></van-field>
<van-field v-model="formData.hobby" label="兴趣爱好" placeholder="请输入兴趣爱好"></van-field>
<van-cell title="形象照片" class="direction-column-cell">
<h5-file-upload :value.sync="formData.photo" :upload_number="1" upload_mode="image" upload_result_category="interval" upload_result_type="url"></h5-file-upload>
</van-cell>
<van-field v-model="formData.intentionFriends" label="交友意向" type="textarea" rows="3" autosize placeholder="请描述交友意向"></van-field>
<van-field v-model="formData.introduction" name="introduction" label="个人介绍" type="textarea" rows="4" autosize placeholder="请简要介绍一下自己" required :rules="[{required:true,message:'请填写个人介绍'}]"></van-field>
</van-form>
<div class="h5-form-actions">
<van-button block @click="formVisible = false">取消</van-button>
<van-button block type="primary" @click="submitForm">确定</van-button>
</div>
</van-action-sheet>
<van-action-sheet v-model="userPickerVisible" title="选择用户">
<van-search v-model="userKeyword" placeholder="请输入姓名或工号搜索" show-action @search="searchUsers">
<template #action>
<div @click="searchUsers">搜索</div>
</template>
</van-search>
<van-cell v-for="item in userOptions" :key="item.id" :title="item.username + '(' + item.loginname + ')'" :label="item.mobile" is-link @click="selectUser(item)"></van-cell>
<van-empty v-if="!userOptions.length" description="暂无用户"></van-empty>
</van-action-sheet>
<van-popup v-model="showEducationPicker" position="bottom">
<van-picker show-toolbar :columns="dict.type.USER_EDUCATION.map(item => item.name || item.label)" @confirm="onEducationConfirm" @cancel="showEducationPicker = false"></van-picker>
</van-popup>
<van-popup v-model="showMaritalPicker" position="bottom">
<van-picker show-toolbar :columns="maritalOptions" @confirm="(value)=>{formData.maritalStatus=value;showMaritalPicker=false}" @cancel="showMaritalPicker = false"></van-picker>
</van-popup>
<van-popup v-model="showIncomePicker" position="bottom">
<van-picker show-toolbar :columns="incomeOptions" @confirm="(value)=>{formData.monthlyIncome=value;showIncomePicker=false}" @cancel="showIncomePicker = false"></van-picker>
</van-popup>
<van-popup v-model="showHousingPicker" position="bottom">
<van-picker show-toolbar :columns="housingOptions" @confirm="(value)=>{formData.housingSituation=value;showHousingPicker=false}" @cancel="showHousingPicker = false"></van-picker>
</van-popup>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
dicts: ["USER_EDUCATION"],
data() {
return {
pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0, age: [0, 100], unionId: "", unitId: ""},
unionOptions: [],
unitOptions: [],
infoVisible: false,
formVisible: false,
userPickerVisible: false,
showEducationPicker: false,
showMaritalPicker: false,
showIncomePicker: false,
showHousingPicker: false,
viewData: {},
formData: {},
userLabel: "",
userKeyword: "",
userOptions: [],
maritalOptions: ["未婚", "离婚", "丧偶"],
incomeOptions: ["5000以下", "5000-8000", "8000-10000", "10000-15000", "15000以上"],
housingOptions: ["已购房", "租房", "与父母同住", "单位宿舍", "其他"],
mobileRules: [
{required: true, message: "请输入联系方式"},
{pattern: /^1[3-9]\d{9}$/, message: "请输入正确的手机号码"}
],
heightRules: [
{
validator: (value) => !value || /^\d{2,3}$/.test(value),
message: "请输入正确的身高"
}
]
}
},
methods: {
async onReady() {
await this.initUnion()
await this.flushUnits()
this.doSearch()
},
async initUnion() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? null : this.$store.state.user.union.id
this.unionOptions = await this.$businessTool.listUnion(unionId)
this.unionOptions.forEach((v) => {
v.text = v.name
v.value = v.id
})
if (hasAdmin) this.unionOptions.unshift({text: "全部工会", value: null})
if (this.unionOptions.length) this.$set(this.pageForm, "unionId", this.unionOptions[0].value)
},
async flushUnits() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
this.unitOptions = await this.$businessTool.listUnit(unionId)
this.unitOptions.forEach((v) => {
v.text = v.name
v.value = v.id
})
if (hasAdmin && !this.pageForm.unionId) this.unitOptions.unshift({text: "全部单位", value: null})
if (this.unitOptions.length) this.$set(this.pageForm, "unitId", this.unitOptions[0].value)
},
async unionChange() {
this.$set(this.pageForm, "unitId", null)
await this.flushUnits()
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
onView(row) {
this.viewData = {...row}
this.infoVisible = true
},
onAdd() {
this.userLabel = ""
this.formData = {picFiles: []}
this.formVisible = true
},
onEdit(row) {
this.formData = {...row, birthday: this.formatDate(row.birthday), picFiles: this.parsePicFiles(row.picFiles)}
this.userLabel = row.username ? row.username + "(" + row.loginname + ")" : ""
this.formVisible = true
},
openUserPicker() {
this.userKeyword = ""
this.userOptions = []
this.userPickerVisible = true
},
searchUsers() {
if (!this.userKeyword) {
this.$toast("请输入姓名或工号")
return
}
this.$axios.post("/platform/singleTeacher/ledger/queryNotSingleTeacher", {key: this.userKeyword}).then((res) => {
if (res.code === 0) this.userOptions = res.data || []
})
},
selectUser(item) {
this.$set(this.formData, "userId", item.id)
this.$set(this.formData, "username", item.username)
this.$set(this.formData, "loginname", item.loginname)
this.$set(this.formData, "mobile", item.mobile || "")
this.$set(this.formData, "birthday", this.formatDate(item.birthday))
this.$set(this.formData, "education", item.education || "")
this.userLabel = item.username + "(" + item.loginname + ")"
this.userPickerVisible = false
},
onEducationConfirm(value) {
this.$set(this.formData, "education", value)
this.showEducationPicker = false
},
submitForm() {
this.$refs.formRef.validate().then(() => {
const url = this.formData.id ? "/platform/singleTeacher/ledger/update" : "/platform/singleTeacher/ledger/insert"
this.$axios.post(url, {singleTeacher: JSON.stringify(this.formData)}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.formVisible = false
this.doSearch()
}
})
})
},
onDelete(row) {
this.$dialog.confirm({title: "提示", message: "您确定要删除吗?"}).then(() => {
this.$axios.post("/platform/singleTeacher/ledger/delete", {id: row.id}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {})
},
formatDate(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : ""
},
parsePicFiles(value) {
if (!value) return []
if (Array.isArray(value)) return value
try {
const list = JSON.parse(value)
return Array.isArray(list) ? list : []
} catch (e) {
return []
}
}
},
})
</script>
<style>
.h5-form-sheet {
max-height: 70vh;
overflow-y: auto;
}
.h5-form-actions {
display: flex;
column-gap: 10px;
padding: 10px;
}
</style>
<!--#
}
#-->
@@ -0,0 +1,196 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="30教龄教职工管理" left-text="返回" left-arrow @click-left="historyBack" fixed placeholder></van-nav-bar>
<van-sticky offset-top="46px">
<van-search v-model="pageForm.searchKeyword" placeholder="请输入姓名或工号搜索" show-action input-align="left" @search="doSearch">
<template #action>
<div @click="doSearch">搜索</div>
</template>
</van-search>
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
<van-dropdown-item v-model="pageForm.unionId" :options="unionOptions" @change="unionChange"></van-dropdown-item>
<van-dropdown-item v-model="pageForm.unitId" :options="unitOptions" @change="doSearch"></van-dropdown-item>
</van-dropdown-menu>
</van-sticky>
<table-list api="/platform/thirtyTeach/manage/pageData" :page_form.sync="pageForm" ref="tableListRef" title="username" @ready="onReady">
<template v-slot="{row}">
<table-column label="工号">{{row.loginname}}</table-column>
<table-column label="性别">{{row.sex}}</table-column>
<table-column label="进校时长">{{row.teachNum}}年</table-column>
<table-column label="教职工类别">{{row.personType}}</table-column>
<table-column label="在职状态">{{row.userState}}</table-column>
<table-column label="所属工会">{{row.unionName}}</table-column>
<table-column label="所属单位">{{row.unitName}}</table-column>
<table-column label="办理年月">{{row.thirtyCertificateProcessingTime || '暂无'}}</table-column>
</template>
<template #actions="{row}">
<div class="action-btn" @click="onView(row)">
<i class="fa fa-eye"></i>
<span>查看</span>
</div>
<div class="action-btn" @click="onEditCertificate(row)">
<i class="fa fa-edit"></i>
<span>编辑</span>
</div>
<div class="action-btn delete" @click="onDelete(row)">
<i class="fa fa-trash"></i>
<span>删除</span>
</div>
</template>
</table-list>
<van-action-sheet v-model="infoVisible" title="30教龄教职工详情">
<div class="detail-container">
<van-cell-group title="基本信息">
<van-cell title="姓名">{{viewData.username || '暂无'}}</van-cell>
<van-cell title="工号">{{viewData.loginname || '暂无'}}</van-cell>
<van-cell title="性别">{{viewData.sex || '暂无'}}</van-cell>
<van-cell title="是否会员">{{viewData.member == 1 ? '是' : '否'}}</van-cell>
<van-cell title="联系电话">{{viewData.mobile || '暂无'}}</van-cell>
<van-cell title="出生日期">{{formatDate(viewData.birthday) || '暂无'}}</van-cell>
<van-cell title="进校时长">{{viewData.teachNum ? viewData.teachNum + '年' : '暂无'}}</van-cell>
<van-cell title="教职工类别">{{viewData.personType || '暂无'}}</van-cell>
<van-cell title="在职状态">{{viewData.userState || '暂无'}}</van-cell>
<van-cell title="所属工会">{{viewData.unionName || '暂无'}}</van-cell>
<van-cell title="所属单位">{{viewData.unitName || '暂无'}}</van-cell>
<van-cell title="荣誉证办理年月">{{viewData.thirtyCertificateProcessingTime || '暂无'}}</van-cell>
</van-cell-group>
</div>
</van-action-sheet>
<van-action-sheet v-model="editVisible" title="编辑荣誉证办理年月">
<van-form ref="formRef" class="h5-form-sheet">
<van-field :value="editData.username" label="姓名" readonly></van-field>
<van-field :value="editData.loginname" label="工号" readonly></van-field>
<van-field v-model="editData.thirtyCertificateProcessingTime" name="thirtyCertificateProcessingTime" label="办理年月" placeholder="请选择办理年月" readonly is-link required :rules="[{required:true,message:'请选择办理年月'}]" @click="showMonthPicker = true"></van-field>
</van-form>
<div class="h5-form-actions">
<van-button block @click="editVisible = false">取消</van-button>
<van-button block type="primary" @click="submitCertificate">确定</van-button>
</div>
</van-action-sheet>
<van-popup v-model="showMonthPicker" position="bottom">
<van-datetime-picker v-model="monthValue" type="year-month" title="选择办理年月" @confirm="onMonthConfirm" @cancel="showMonthPicker = false"></van-datetime-picker>
</van-popup>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
pageForm: {pageNumber: 1, pageSize: 10, totalCount: 0, unionId: "", unitId: ""},
unionOptions: [],
unitOptions: [],
infoVisible: false,
editVisible: false,
showMonthPicker: false,
viewData: {},
editData: {},
monthValue: new Date()
}
},
methods: {
async onReady() {
await this.initUnion()
await this.flushUnits()
this.doSearch()
},
async initUnion() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? null : this.$store.state.user.union.id
this.unionOptions = await this.$businessTool.listUnion(unionId)
this.unionOptions.forEach((v) => {
v.text = v.name
v.value = v.id
})
if (hasAdmin) this.unionOptions.unshift({text: "全部工会", value: null})
if (this.unionOptions.length) this.$set(this.pageForm, "unionId", this.unionOptions[0].value)
},
async flushUnits() {
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
this.unitOptions = await this.$businessTool.listUnit(unionId)
this.unitOptions.forEach((v) => {
v.text = v.name
v.value = v.id
})
if (hasAdmin && !this.pageForm.unionId) this.unitOptions.unshift({text: "全部单位", value: null})
if (this.unitOptions.length) this.$set(this.pageForm, "unitId", this.unitOptions[0].value)
},
async unionChange() {
this.$set(this.pageForm, "unitId", null)
await this.flushUnits()
this.doSearch()
},
doSearch() {
this.$nextTick(() => {
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.$refs.tableListRef.doSearch()
})
},
onView(row) {
this.viewData = {...row}
this.infoVisible = true
},
onEditCertificate(row) {
this.editData = {...row}
this.monthValue = row.thirtyCertificateProcessingTime ? new Date(row.thirtyCertificateProcessingTime + "-01") : new Date()
this.editVisible = true
},
onMonthConfirm(value) {
this.$set(this.editData, "thirtyCertificateProcessingTime", this.$moment(value).format("YYYY-MM"))
this.showMonthPicker = false
},
submitCertificate() {
this.$refs.formRef.validate().then(() => {
this.$axios.post("/platform/thirtyTeach/manage/doEditThirtyCertificateProcessingTime", {
id: this.editData.id,
thirtyCertificateProcessingTime: this.editData.thirtyCertificateProcessingTime
}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.editVisible = false
this.doSearch()
}
})
})
},
onDelete(row) {
this.$dialog.confirm({title: "提示", message: "您确定要删除吗?"}).then(() => {
this.$axios.post("/platform/thirtyTeach/manage/doBatchDelete", {userIds: JSON.stringify([row.id])}).then((res) => {
if (res.code === 0) {
this.$toast.success(res.msg)
this.doSearch()
}
})
}).catch(() => {})
},
formatDate(value) {
return value ? this.$moment(value).format("YYYY-MM-DD") : ""
}
},
})
</script>
<style>
.h5-form-sheet {
max-height: 70vh;
overflow-y: auto;
}
.h5-form-actions {
display: flex;
column-gap: 10px;
padding: 10px;
}
</style>
<!--#
}
#-->