|
@@ -46,10 +46,6 @@ import java.util.stream.Collectors;
|
|
@Transactional
|
|
@Transactional
|
|
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
|
|
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
|
|
|
|
|
|
- //用于控制线程锁
|
|
|
|
- public static HashMap<String, CorpwxJobResult> corpwxJobCenter = new HashMap();
|
|
|
|
- public static HashMap<String, Integer> corpddJobCenter = new HashMap();
|
|
|
|
-
|
|
|
|
@Value(value = "${upload.path}")
|
|
@Value(value = "${upload.path}")
|
|
private String path;
|
|
private String path;
|
|
@Resource
|
|
@Resource
|
|
@@ -80,14 +76,14 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
|
|
private WxCorpInfoService wxCorpInfoService;
|
|
private WxCorpInfoService wxCorpInfoService;
|
|
@Resource
|
|
@Resource
|
|
private WxCorpInfoMapper wxCorpInfoMapper;
|
|
private WxCorpInfoMapper wxCorpInfoMapper;
|
|
-// @Resource
|
|
|
|
-// private DingDingService dingDingService;
|
|
|
|
@Resource
|
|
@Resource
|
|
private SysFunctionService sysFunctionService;
|
|
private SysFunctionService sysFunctionService;
|
|
@Resource
|
|
@Resource
|
|
private DepartmentService departmentService;
|
|
private DepartmentService departmentService;
|
|
@Resource
|
|
@Resource
|
|
private DepartmentOtherManagerMapper departmentOtherManagerMapper;
|
|
private DepartmentOtherManagerMapper departmentOtherManagerMapper;
|
|
|
|
+ @Resource
|
|
|
|
+ private ExcelExportService excelExportService;
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public HttpRespMsg getExecutorPanel(Integer projectId) {
|
|
public HttpRespMsg getExecutorPanel(Integer projectId) {
|
|
@@ -224,211 +220,6 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- @Override
|
|
|
|
- public HttpRespMsg exportTask(Integer projectId, Integer taskType) {
|
|
|
|
- HttpRespMsg httpRespMsg = new HttpRespMsg();
|
|
|
|
- List<TimeTask> list= taskMapper.getTaskWithWorktime(projectId, taskType);
|
|
|
|
- Project project = projectMapper.selectById(projectId);
|
|
|
|
- User user = userMapper.selectById(request.getHeader("token"));
|
|
|
|
- Integer companyId = user.getCompanyId();
|
|
|
|
- WxCorpInfo wxCorpInfo = wxCorpInfoService.getOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
|
|
|
|
- CompanyDingding dingding = companyDingdingService.getOne(new QueryWrapper<CompanyDingding>().eq("company_id", companyId));
|
|
|
|
- List<User> userList = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId));
|
|
|
|
- try {
|
|
|
|
- DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
- //准备导出
|
|
|
|
- HSSFWorkbook workbook = new HSSFWorkbook();
|
|
|
|
- //HSSFSheet sheet = workbook.createSheet("任务数据");
|
|
|
|
- HSSFSheet sheet = workbook.createSheet(MessageUtils.message("excel.taskData"));
|
|
|
|
- //创建表头
|
|
|
|
- HSSFRow headRow = sheet.createRow(0);
|
|
|
|
- //设置列宽 setColumnWidth的第二个参数要乘以256 这个参数的单位是1/256个字符宽度
|
|
|
|
- sheet.setColumnWidth(0, 50 * 256);
|
|
|
|
- sheet.setColumnWidth(1, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(2, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(3, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(4, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(5, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(6, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(7, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(8, 20 * 256);
|
|
|
|
- sheet.setColumnWidth(9, 20 * 256);
|
|
|
|
- //设置为居中加粗
|
|
|
|
- HSSFCellStyle headStyle = workbook.createCellStyle();
|
|
|
|
- HSSFFont font = workbook.createFont();
|
|
|
|
- font.setBold(true);
|
|
|
|
- headStyle.setFont(font);
|
|
|
|
- HSSFFont redFont = workbook.createFont();
|
|
|
|
- redFont.setColor(HSSFFont.COLOR_RED);
|
|
|
|
- HSSFCellStyle redStyle = workbook.createCellStyle();
|
|
|
|
- redStyle.setFont(redFont);
|
|
|
|
- //表头
|
|
|
|
- HSSFCell headCell;
|
|
|
|
- headCell = headRow.createCell(0);
|
|
|
|
- //headCell.setCellValue("任务内容");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.taskContent"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(1);
|
|
|
|
- //headCell.setCellValue("项目");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("entry.project"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(2);
|
|
|
|
- //headCell.setCellValue("执行人");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.executor"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(3);
|
|
|
|
- //headCell.setCellValue("创建时间");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.creatTime"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(4);
|
|
|
|
- //headCell.setCellValue("截止时间");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.deadline"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(5);
|
|
|
|
- //headCell.setCellValue("完成时间");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.comTime"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(6);
|
|
|
|
- //headCell.setCellValue("是否完成");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.whetherCom"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(7);
|
|
|
|
- //headCell.setCellValue("是否逾期");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.overdueNot"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(8);
|
|
|
|
- //headCell.setCellValue("计划工时(h)");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.plannedWork"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- headCell = headRow.createCell(9);
|
|
|
|
- //headCell.setCellValue("实际工时(h)");
|
|
|
|
- headCell.setCellValue(MessageUtils.message("excel.actualWork"));
|
|
|
|
- headCell.setCellStyle(headStyle);
|
|
|
|
- int rowNum = 1;
|
|
|
|
- for (TimeTask task : list) {
|
|
|
|
- HSSFRow row = sheet.createRow(rowNum);
|
|
|
|
- row.createCell(0).setCellValue(task.getName());
|
|
|
|
- row.createCell(1).setCellValue(project.getProjectName());
|
|
|
|
- if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
|
|
|
|
- Optional<User> first = userList.stream().filter(ul -> ul.getId().equals(task.getExecutorId())).findFirst();
|
|
|
|
- if(first.isPresent()){
|
|
|
|
- row.createCell(2).setCellValue("$userName="+(first.get().getCorpwxUserid()==null?"":first.get().getCorpwxUserid())+"$");
|
|
|
|
- }else {
|
|
|
|
- row.createCell(2).setCellValue("");
|
|
|
|
- }
|
|
|
|
- }else {
|
|
|
|
- row.createCell(2).setCellValue(task.getExecutorName());
|
|
|
|
- }
|
|
|
|
- row.createCell(3).setCellValue(dateTimeFormatter.format(task.getCreateDate()));
|
|
|
|
- row.createCell(4).setCellValue(task.getEndDate() != null?dateTimeFormatter.format(task.getEndDate()):"");
|
|
|
|
- row.createCell(5).setCellValue(task.getFinishDate() !=null?dateTimeFormatter.format(task.getFinishDate()):"");
|
|
|
|
- row.createCell(6).setCellValue(task.getTaskStatus() == 1?"Y":"N");
|
|
|
|
- boolean isExpired = false;
|
|
|
|
- if (task.getTaskStatus() == 0 && task.getEndDate() !=null&& !task.getEndDate().isAfter(LocalDate.now())) {
|
|
|
|
- isExpired = true;
|
|
|
|
- }
|
|
|
|
- row.createCell(7).setCellValue(isExpired?"Y":"N");
|
|
|
|
- row.createCell(8).setCellValue(task.getPlanHours()==null?"": task.getPlanHours().toString());
|
|
|
|
- row.createCell(9).setCellValue(task.getWorkHours());
|
|
|
|
- rowNum++;
|
|
|
|
- }
|
|
|
|
- //生成Excel文件
|
|
|
|
- //String fileUrlSuffix = "【"+project.getProjectName()+"】任务数据" + System.currentTimeMillis() + ".xls";
|
|
|
|
- String fileUrlSuffix = "【"+project.getProjectName()+"】"+MessageUtils.message("excel.taskData") + System.currentTimeMillis() + ".xls";
|
|
|
|
- FileOutputStream fos = new FileOutputStream(path + fileUrlSuffix);
|
|
|
|
- workbook.write(fos);
|
|
|
|
- fos.flush();
|
|
|
|
- fos.close();
|
|
|
|
- if(wxCorpInfo!=null&&wxCorpInfo.getSaasSyncContact()==1){
|
|
|
|
- String mediaId = wxCorpInfoService.getTranslationMediaId(fileUrlSuffix);
|
|
|
|
- String jobId = wxCorpInfoService.syncTranslation(wxCorpInfo.getCorpid(),mediaId,fileUrlSuffix, null);
|
|
|
|
- /*if(jobId!=null&&!jobId.equals("")){
|
|
|
|
- File file=new File(path + fileUrlSuffix);
|
|
|
|
- if(file.exists()){
|
|
|
|
- file.delete();
|
|
|
|
- }
|
|
|
|
- }*/
|
|
|
|
- int i = 0;
|
|
|
|
- String syncTranslationResult = null;
|
|
|
|
- /**
|
|
|
|
- * 异步上传转译文件的任务完成时会触发回调,在WeiXinCorpController中的commonDevCallbackPost实现了对回调的处理,存储到corpwxJobResult表中
|
|
|
|
- * 此处轮询查询本地数据库,检测到有任务的回调数据时继续执行查询操作
|
|
|
|
- */
|
|
|
|
- while (i < 10) {
|
|
|
|
- Thread.sleep(300);
|
|
|
|
- CorpwxJobResult corpwxJobResult = corpwxJobCenter.get(jobId);
|
|
|
|
- if (corpwxJobResult != null) {
|
|
|
|
- if (corpwxJobResult.getErrCode() == 0) {
|
|
|
|
- syncTranslationResult = wxCorpInfoService.getSyncTranslationResult(jobId);
|
|
|
|
- corpwxJobCenter.remove(jobId);
|
|
|
|
- } else {
|
|
|
|
- httpRespMsg.setError(corpwxJobResult.getErrMsg());
|
|
|
|
- return httpRespMsg;
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- i++;
|
|
|
|
- }
|
|
|
|
- if (syncTranslationResult != null) {
|
|
|
|
- httpRespMsg.data = syncTranslationResult;
|
|
|
|
- } else {
|
|
|
|
- //httpRespMsg.setError("处理超时...");
|
|
|
|
- httpRespMsg.setError(MessageUtils.message("request.outTime"));
|
|
|
|
- }
|
|
|
|
- }else if(dingding!=null&&dingding.getSyncContact()==1){
|
|
|
|
-// String mediaId = dingDingService.getTranslationMediaId(fileUrlSuffix,dingding);
|
|
|
|
-// String jobId = dingDingService.syncTranslation(mediaId,fileUrlSuffix,user.getDingdingUnionid(),dingding);
|
|
|
|
-// /*if(jobId!=null&&!jobId.equals("")){
|
|
|
|
-// File file=new File(path + fileUrlSuffix);
|
|
|
|
-// if(file.exists()){
|
|
|
|
-// file.delete();
|
|
|
|
-// }
|
|
|
|
-// }*/
|
|
|
|
-// int i = 0;
|
|
|
|
-// String syncTranslationResult = null;
|
|
|
|
-// /**
|
|
|
|
-// * 异步上传转译文件的任务完成时会触发回调,在WeiXinCorpController中的commonDevCallbackPost实现了对回调的处理,存储到corpwxJobResult表中
|
|
|
|
-// * 此处轮询查询本地数据库,检测到有任务的回调数据时继续执行查询操作
|
|
|
|
-// */
|
|
|
|
-// while (i < 10) {
|
|
|
|
-// Thread.sleep(300);
|
|
|
|
-// Integer status = corpddJobCenter.get(jobId);
|
|
|
|
-// if (status != null) {
|
|
|
|
-// if (status==1) {
|
|
|
|
-// syncTranslationResult = dingDingService.getSyncTranslationResult(jobId,dingding);
|
|
|
|
-// corpddJobCenter.remove(jobId);
|
|
|
|
-// }
|
|
|
|
-// break;
|
|
|
|
-// }
|
|
|
|
-// i++;
|
|
|
|
-// }
|
|
|
|
-// if (syncTranslationResult != null) {
|
|
|
|
-// httpRespMsg.data = syncTranslationResult;
|
|
|
|
-// } else {
|
|
|
|
-// //httpRespMsg.setError("处理超时...");
|
|
|
|
-// httpRespMsg.setError(MessageUtils.message("request.outTime"));
|
|
|
|
-// }
|
|
|
|
- }else {
|
|
|
|
- httpRespMsg.data = "/upload/" + fileUrlSuffix;
|
|
|
|
- }
|
|
|
|
- } catch (NullPointerException e) {
|
|
|
|
- e.printStackTrace();
|
|
|
|
- //httpRespMsg.setError("验证失败或缺少数据");
|
|
|
|
- httpRespMsg.setError(MessageUtils.message("access.verErrorOrDataLack"));
|
|
|
|
- return httpRespMsg;
|
|
|
|
- } catch (IOException e) {
|
|
|
|
- e.printStackTrace();
|
|
|
|
- //httpRespMsg.setError("文件生成错误");
|
|
|
|
- httpRespMsg.setError(MessageUtils.message("file.generateError"));
|
|
|
|
- return httpRespMsg;
|
|
|
|
- }catch (Exception e){
|
|
|
|
- e.printStackTrace();
|
|
|
|
- httpRespMsg.setError(MessageUtils.message("access.verErrorOrDataLack"));
|
|
|
|
- return httpRespMsg;
|
|
|
|
- }
|
|
|
|
- return httpRespMsg;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
@Override
|
|
@Override
|
|
public HttpRespMsg importTask(Integer isMultiProject, Integer projectId, Integer groupId, MultipartFile multipartFile, HttpServletRequest request) throws Exception {
|
|
public HttpRespMsg importTask(Integer isMultiProject, Integer projectId, Integer groupId, MultipartFile multipartFile, HttpServletRequest request) throws Exception {
|
|
HttpRespMsg httpRespMsg = new HttpRespMsg();
|
|
HttpRespMsg httpRespMsg = new HttpRespMsg();
|
|
@@ -852,6 +643,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
|
|
boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "全部员工任务完成情况表");
|
|
boolean viewAll = sysFunctionService.hasPriviledge(user.getRoleId(), "全部员工任务完成情况表");
|
|
boolean viewDept = sysFunctionService.hasPriviledge(user.getRoleId(), "负责部门员工任务完成情况表");
|
|
boolean viewDept = sysFunctionService.hasPriviledge(user.getRoleId(), "负责部门员工任务完成情况表");
|
|
List<Map<String, Object>> resultMaps;
|
|
List<Map<String, Object>> resultMaps;
|
|
|
|
+ Integer total;
|
|
if(pageIndex!=null&&pageSize!=null){
|
|
if(pageIndex!=null&&pageSize!=null){
|
|
pageStart = (pageIndex - 1) * pageSize;
|
|
pageStart = (pageIndex - 1) * pageSize;
|
|
}
|
|
}
|
|
@@ -866,14 +658,84 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements Ta
|
|
targetDeptIds.addAll(branchDepartment);
|
|
targetDeptIds.addAll(branchDepartment);
|
|
}
|
|
}
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, userId, deptId,targetDeptIds, companyId);
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, userId, deptId,targetDeptIds, companyId);
|
|
|
|
+ total = taskMapper.userTaskCompleteDetailCount(startDate, endDate, userId, deptId, targetDeptIds, companyId);
|
|
}else {
|
|
}else {
|
|
//只能看自己的
|
|
//只能看自己的
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, user.getId(), deptId,null, companyId);
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, user.getId(), deptId,null, companyId);
|
|
|
|
+ total = taskMapper.userTaskCompleteDetailCount( startDate, endDate, user.getId(), deptId, null, companyId);
|
|
}
|
|
}
|
|
}else {
|
|
}else {
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, userId, deptId,null, companyId);
|
|
resultMaps = taskMapper.userTaskCompleteDetail(pageStart, pageSize, startDate, endDate, userId, deptId,null, companyId);
|
|
|
|
+ total = taskMapper.userTaskCompleteDetailCount(startDate, endDate, userId, deptId, null, companyId);
|
|
|
|
+ }
|
|
|
|
+ Map<String,Object> map=new HashMap<>();
|
|
|
|
+ map.put("records",resultMaps);
|
|
|
|
+ map.put("total",total);
|
|
|
|
+ msg.setData(map);
|
|
|
|
+ return msg;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public HttpRespMsg exportUserTaskCompleteDetail(String startDate, String endDate, String userId, Integer deptId) {
|
|
|
|
+ HttpRespMsg msg=new HttpRespMsg();
|
|
|
|
+ Integer companyId = userMapper.selectById(request.getHeader("token")).getCompanyId();
|
|
|
|
+ WxCorpInfo wxCorpInfo = wxCorpInfoMapper.selectOne(new LambdaQueryWrapper<WxCorpInfo>().eq(WxCorpInfo::getCompanyId, companyId));
|
|
|
|
+ CompanyDingding dingding = companyDingdingService.getOne(new LambdaQueryWrapper<CompanyDingding>().eq(CompanyDingding::getCompanyId, companyId));
|
|
|
|
+ HttpRespMsg respMsg = userTaskCompleteDetail(null, null, startDate, endDate, userId, deptId);
|
|
|
|
+ Map<String, Object> data = (Map<String, Object>) respMsg.getData();
|
|
|
|
+ List<Map<String, Object>> mapList = (List<Map<String, Object>>) data.get("records");
|
|
|
|
+ List<List<String>> dataList=new ArrayList<>();
|
|
|
|
+ List<String> titleList=new ArrayList<>();
|
|
|
|
+ titleList.add("员工");
|
|
|
|
+ titleList.add("部门");
|
|
|
|
+ titleList.add("任务总数量");
|
|
|
|
+ titleList.add("已完成数量");
|
|
|
|
+ titleList.add("未完成数量");
|
|
|
|
+ titleList.add("未完成率");
|
|
|
|
+ titleList.add("按时完成数量");
|
|
|
|
+ titleList.add("延迟完成数量");
|
|
|
|
+ titleList.add("按时完成率");
|
|
|
|
+ dataList.add(titleList);
|
|
|
|
+ for (Map<String, Object> map : mapList) {
|
|
|
|
+ List<String> item=new ArrayList<>();
|
|
|
|
+ if((wxCorpInfo!=null && wxCorpInfo.getSaasSyncContact()==1)||(dingding!=null&&dingding.getSyncContact()==1)){
|
|
|
|
+ item.add("$userName="+String.valueOf(map.get("userName"))+"$");
|
|
|
|
+ item.add("$departmentName="+String.valueOf(map.get("deptName"))+"$");
|
|
|
|
+ }else {
|
|
|
|
+ item.add(String.valueOf(map.get("userName")));
|
|
|
|
+ item.add(String.valueOf(map.get("deptName")));
|
|
|
|
+ }
|
|
|
|
+ item.add(String.valueOf(map.get("allNum")));
|
|
|
|
+ item.add(String.valueOf(map.get("completedNum")));
|
|
|
|
+ item.add(String.valueOf(map.get("noCompletedNum")));
|
|
|
|
+ item.add(String.valueOf(map.get("noCompletedPercent")));
|
|
|
|
+ item.add(String.valueOf(map.get("onTimeNum")));
|
|
|
|
+ item.add(String.valueOf(map.get("noOnTimeNum")));
|
|
|
|
+ item.add(String.valueOf(map.get("onTimePercent")));
|
|
|
|
+ dataList.add(item);
|
|
|
|
+ }
|
|
|
|
+ String fileName="员工任务完成情况表_"+System.currentTimeMillis();
|
|
|
|
+ try {
|
|
|
|
+ return excelExportService.exportGeneralExcelByTitleAndList(wxCorpInfo,dingding,fileName,dataList,path);
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ return msg;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public HttpRespMsg getTaskByUserId(String startDate, String endDate, String userId, Integer pageIndex, Integer pageSize) {
|
|
|
|
+ HttpRespMsg msg=new HttpRespMsg();
|
|
|
|
+ Integer pageStart=null;
|
|
|
|
+ if(pageIndex!=null&&pageSize!=null){
|
|
|
|
+ pageStart = (pageIndex - 1) * pageSize;
|
|
}
|
|
}
|
|
- msg.setData(resultMaps);
|
|
|
|
|
|
+ List<Map<String,Object>> mapList=taskMapper.getTaskByUserId(startDate,endDate,userId,pageStart,pageSize);
|
|
|
|
+ Integer total=taskMapper.getTaskByUserIdCount(startDate,endDate,userId);
|
|
|
|
+ Map<String,Object> map=new HashMap<>();
|
|
|
|
+ map.put("records",mapList);
|
|
|
|
+ map.put("total",total);
|
|
|
|
+ msg.setData(map);
|
|
return msg;
|
|
return msg;
|
|
}
|
|
}
|
|
|
|
|