Pārlūkot izejas kodu

增加立项备案提醒任务

tags/24080901
WendyYang pirms 10 mēnešiem
vecāks
revīzija
3af6df8175
14 mainītis faili ar 335 papildinājumiem un 25 dzēšanām
  1. +4
    -1
      hz-pm-api/src/main/java/com/hz/pm/api/common/helper/UserInfoHelper.java
  2. +39
    -17
      hz-pm-api/src/main/java/com/hz/pm/api/common/helper/impl/UserInfoHelperImpl.java
  3. +34
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/common/util/MDCThreadPoolTaskScheduler.java
  4. +13
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/common/util/ThreadPoolUtil.java
  5. +1
    -1
      hz-pm-api/src/main/java/com/hz/pm/api/external/todo/MHTodoClient.java
  6. +2
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/external/todo/dto/MhTodoExtraParamDTO.java
  7. +5
    -3
      hz-pm-api/src/main/java/com/hz/pm/api/external/todo/enumerization/MHTodoTypeEnum.java
  8. +5
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/projectlib/manage/DeclaredRecordManage.java
  9. +154
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/scheduler/task/DeclaredRecordReminderTask.java
  10. +39
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/scheduler/task/ReminderTask.java
  11. +21
    -0
      hz-pm-api/src/main/java/com/hz/pm/api/sys/service/IMhTodoRecordService.java
  12. +8
    -1
      hz-pm-api/src/main/resources/application-dev.yml
  13. +7
    -1
      hz-pm-api/src/main/resources/application-prod.yml
  14. +3
    -1
      hz-pm-api/src/test/java/com/hz/pm/api/todocenter/MhApiClientTest.java

+ 4
- 1
hz-pm-api/src/main/java/com/hz/pm/api/common/helper/UserInfoHelper.java Parādīt failu

@@ -2,6 +2,7 @@ package com.hz.pm.api.common.helper;

import cn.hutool.core.util.NumberUtil;
import com.hz.pm.api.user.model.entity.UserInfo;
import com.hz.pm.api.user.model.enumeration.RoleEnum;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.ningdatech.basic.util.CollUtils;

@@ -42,9 +43,11 @@ public interface UserInfoHelper {

List<UserFullInfoDTO> listUserFullInfoByUserIds(Collection<Long> userIds);

default List<UserFullInfoDTO> listUserFullInfoByUserIds(List<String> userIds){
default List<UserFullInfoDTO> listUserFullInfoByUserIds(List<String> userIds) {
List<Long> userIdsLong = CollUtils.convert(userIds, Long::parseLong);
return listUserFullInfoByUserIds(userIdsLong);
}

List<UserFullInfoDTO> listUserFullInfoByUnitIdsAndRole(Collection<Long> unitIds, RoleEnum role);

}

+ 39
- 17
hz-pm-api/src/main/java/com/hz/pm/api/common/helper/impl/UserInfoHelperImpl.java Parādīt failu

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hz.pm.api.common.helper.UserInfoHelper;
import com.hz.pm.api.common.model.constant.BizConst;
import com.hz.pm.api.common.util.BizUtils;
import com.hz.pm.api.common.util.StrUtils;
import com.hz.pm.api.sys.mapper.RoleMapper;
import com.hz.pm.api.sys.model.entity.Role;
@@ -15,6 +17,7 @@ import com.hz.pm.api.user.model.enumeration.RoleEnum;
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.hz.pm.api.user.service.IUserInfoService;
import com.ningdatech.basic.util.CollUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

@@ -100,23 +103,25 @@ public class UserInfoHelperImpl implements UserInfoHelper {
if (CollUtil.isEmpty(userInfos)) {
return Collections.emptyList();
}
return userInfos.stream().map(userInfo -> {
UserFullInfoDTO userFullInfo = new UserFullInfoDTO();
// 装配返回
userFullInfo.setMhUnitName(userInfo.getMhUnitName());
userFullInfo.setMhUnitId(userInfo.getMhUnitId());
userFullInfo.setUserId(userInfo.getId());
userFullInfo.setIdentifier(userInfo.getRealName());
userFullInfo.setRealName(userInfo.getRealName());
userFullInfo.setUsername(userInfo.getRealName());
userFullInfo.setMobile(userInfo.getMobile());
userFullInfo.setAccountId(userInfo.getAccountId());
String available = userInfo.getAvailable();
if (StrUtils.isNotBlank(available)) {
userFullInfo.setAvailable(UserAvailableEnum.valueOf(available));
}
return userFullInfo;
}).collect(Collectors.toList());
return userInfos.stream().map(this::convert).collect(Collectors.toList());
}

private UserFullInfoDTO convert(UserInfo userInfo){
UserFullInfoDTO userFullInfo = new UserFullInfoDTO();
// 装配返回
userFullInfo.setMhUnitName(userInfo.getMhUnitName());
userFullInfo.setMhUnitId(userInfo.getMhUnitId());
userFullInfo.setUserId(userInfo.getId());
userFullInfo.setIdentifier(userInfo.getRealName());
userFullInfo.setRealName(userInfo.getRealName());
userFullInfo.setUsername(userInfo.getRealName());
userFullInfo.setMobile(userInfo.getMobile());
userFullInfo.setAccountId(userInfo.getAccountId());
String available = userInfo.getAvailable();
if (StrUtils.isNotBlank(available)) {
userFullInfo.setAvailable(UserAvailableEnum.valueOf(available));
}
return userFullInfo;
}

@Override
@@ -145,4 +150,21 @@ public class UserInfoHelperImpl implements UserInfoHelper {
return getUserFullInfos(userInfos);
}

@Override
public List<UserFullInfoDTO> listUserFullInfoByUnitIdsAndRole(Collection<Long> unitIds, RoleEnum roleEnum) {
LambdaQueryWrapper<Role> rQuery = Wrappers.lambdaQuery(Role.class)
.eq(Role::getCode, roleEnum.name())
.last(BizConst.LIMIT_1);
Role role = roleMapper.selectOne(rQuery);
if (role == null) {
return Collections.emptyList();
}
LambdaQueryWrapper<UserInfo> query = Wrappers.lambdaQuery(UserInfo.class)
.in(UserInfo::getMhUnitId, unitIds)
.exists("select 1 from nd_user_role nur where nur.user_id = nd_user_info.id" +
" and nur.role_id = {0}", role.getId());
List<UserInfo> userInfos = userInfoService.list(query);
return CollUtils.convert(userInfos,this::convert);
}

}

+ 34
- 0
hz-pm-api/src/main/java/com/hz/pm/api/common/util/MDCThreadPoolTaskScheduler.java Parādīt failu

@@ -0,0 +1,34 @@
package com.hz.pm.api.common.util;

import org.springframework.lang.NonNull;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;

/**
* <p>
* MDCThreadPoolTaskExecutor
* </p>
*
* @author WendyYang
* @since 2023/10/27
**/
public class MDCThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {

@Override
public @NonNull Future<?> submit(@NonNull Runnable task) {
return super.submit(MDCThreadUtil.wrap(task));
}

@Override
public void execute(@NonNull Runnable task) {
super.execute(MDCThreadUtil.wrap(task));
}

@Override
public <T> @NonNull Future<T> submit(@NonNull Callable<T> task) {
return super.submit(MDCThreadUtil.wrap(task));
}

}

+ 13
- 0
hz-pm-api/src/main/java/com/hz/pm/api/common/util/ThreadPoolUtil.java Parādīt failu

@@ -1,6 +1,7 @@
package com.hz.pm.api.common.util;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.util.concurrent.ThreadPoolExecutor;

@@ -18,16 +19,28 @@ public class ThreadPoolUtil {
}

public static final ThreadPoolTaskExecutor REQUEST;
public static final ThreadPoolTaskScheduler SCHEDULER;

static {
REQUEST = new MDCThreadPoolTaskExecutor();
REQUEST.setCorePoolSize(5);
REQUEST.setMaxPoolSize(15);
REQUEST.setQueueCapacity(300);
REQUEST.setThreadPriority(Thread.NORM_PRIORITY);
REQUEST.setKeepAliveSeconds(120);
REQUEST.setThreadNamePrefix("requestAsyncExecutor-");
REQUEST.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
REQUEST.initialize();
}

static {
SCHEDULER = new MDCThreadPoolTaskScheduler();
SCHEDULER.setPoolSize(5);
SCHEDULER.setThreadPriority(Thread.NORM_PRIORITY - 1);
SCHEDULER.setWaitForTasksToCompleteOnShutdown(true);
SCHEDULER.setThreadNamePrefix("scheduler-");
SCHEDULER.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
SCHEDULER.initialize();
}

}

+ 1
- 1
hz-pm-api/src/main/java/com/hz/pm/api/external/todo/MHTodoClient.java Parādīt failu

@@ -77,7 +77,7 @@ public class MHTodoClient {
log.info("添加新创待办:{}", todoReq);
String responseResult = HttpUtil.post(url, JSON.toJSONString(todoReq));
MhTodoRetDTO retData = JSON.parseObject(responseResult, TYPE_REF);
if (retData.getCode() != 0 || StrUtil.isBlank(retData.getData())) {
if (retData.getCode() != 200 || StrUtil.isBlank(retData.getData())) {
log.warn("发送待办失败:{} {}", todoReq, retData);
throw BizException.wrap("发送待办失败");
}


+ 2
- 0
hz-pm-api/src/main/java/com/hz/pm/api/external/todo/dto/MhTodoExtraParamDTO.java Parādīt failu

@@ -21,6 +21,8 @@ public class MhTodoExtraParamDTO {

private String instanceId;

private String projectCode;

private Long projectId;

private String taskId;


+ 5
- 3
hz-pm-api/src/main/java/com/hz/pm/api/external/todo/enumerization/MHTodoTypeEnum.java Parādīt failu

@@ -16,10 +16,12 @@ import lombok.Getter;
public enum MHTodoTypeEnum {


FINAL_INSPECT_AUDIT("终验审批"),
XCFHX_INSPECT_AUDIT("信创符合性审查审批"),
DECLARED_RECORD_AUDIT("立项备案审批");
FINAL_INSPECT_AUDIT("终验审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}"),
XCFHX_INSPECT_AUDIT("信创符合性审查审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}"),
DECLARED_RECORD_APPLY("立项备案申请", "userId=${userId}&userName=${userName}&path=${path}"),
DECLARED_RECORD_AUDIT("立项备案审批", "instanceId=${instanceId}&projectId=${projectId}&nodeId=${nodeId}&taskId=${taskId}&bidId=${bizId}&userId=${userId}&userName=${userName}&path=${path}");

private final String val;
private final String referLinkParam;

}

+ 5
- 0
hz-pm-api/src/main/java/com/hz/pm/api/projectlib/manage/DeclaredRecordManage.java Parādīt failu

@@ -21,6 +21,8 @@ import com.hz.pm.api.datascope.model.DataScopeDTO;
import com.hz.pm.api.datascope.utils.DataScopeUtil;
import com.hz.pm.api.external.model.enumeration.MhUnitStripEnum;
import com.hz.pm.api.external.model.enumeration.MhUnitTypeEnum;
import com.hz.pm.api.external.todo.MHTodoClient;
import com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum;
import com.hz.pm.api.projectdeclared.manage.DefaultDeclaredProjectManage;
import com.hz.pm.api.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.hz.pm.api.projectdeclared.model.dto.ProjectConditionDTO;
@@ -101,6 +103,7 @@ public class DeclaredRecordManage {
private final ProjectLibManage projectLibManage;
private final IProjectStatusChangeService projectStatusChangeService;
private final IProjectGovSystemReplaceInfosService systemReplaceInfosService;
private final MHTodoClient mhTodoClient;

private LambdaQueryWrapper<MhProject> buildQuery(DeclaredProjectListReq req) {
LambdaQueryWrapper<MhProject> query = Wrappers.lambdaQuery(MhProject.class)
@@ -335,6 +338,8 @@ public class DeclaredRecordManage {
//发送给第一个审批人消息
noticeManage.sendFirstUser(newProj, model.getFormName(), instanceId,
WorkNoticeConst.PASS_MSG_TEMPLATE, MsgTypeEnum.PROJECT_REVIEW);
// 完成立项备案待办
mhTodoClient.completeTodo(MHTodoTypeEnum.DECLARED_RECORD_APPLY, newProj.getProjectCode());
}

@Transactional(rollbackFor = Exception.class)


+ 154
- 0
hz-pm-api/src/main/java/com/hz/pm/api/scheduler/task/DeclaredRecordReminderTask.java Parādīt failu

@@ -0,0 +1,154 @@
package com.hz.pm.api.scheduler.task;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hz.pm.api.common.helper.UserInfoHelper;
import com.hz.pm.api.common.util.ThreadPoolUtil;
import com.hz.pm.api.external.MhApiClient;
import com.hz.pm.api.external.model.dto.MhZwddWorkNoticeDTO;
import com.hz.pm.api.external.todo.MHTodoClient;
import com.hz.pm.api.external.todo.dto.MhTodoExtraParamDTO;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.enumeration.ProjectStatusEnum;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.sys.entity.MhTodoRecord;
import com.hz.pm.api.sys.service.IMhTodoRecordService;
import com.hz.pm.api.user.helper.MhUnitCache;
import com.hz.pm.api.user.model.dto.UnitDTO;
import com.hz.pm.api.user.model.enumeration.RoleEnum;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.ningdatech.basic.util.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum.DECLARED_RECORD_APPLY;

/**
* <p>
* DeclaredRecordReminderTask
* </p>
*
* @author WendyYang
* @since 10:40 2024/3/14
*/
@Slf4j
@Component
public class DeclaredRecordReminderTask extends ReminderTask {

private final IProjectService projectService;
private final IMhTodoRecordService todoRecordService;
private final MhApiClient mhApiClient;
private final MHTodoClient mhTodoClient;
private final MhUnitCache mhUnitCache;
private final UserInfoHelper userInfoHelper;


public DeclaredRecordReminderTask(Environment environment,
IProjectService projectService,
IMhTodoRecordService todoRecordService,
MhApiClient mhApiClient,
MHTodoClient mhTodoClient,
MhUnitCache mhUnitCache,
UserInfoHelper userInfoHelper) {
super(environment);
this.projectService = projectService;
this.todoRecordService = todoRecordService;
this.mhApiClient = mhApiClient;
this.mhTodoClient = mhTodoClient;
this.mhUnitCache = mhUnitCache;
this.userInfoHelper = userInfoHelper;
}

@Override
public String getTaskPropertyName() {
return "declared-record";
}

private static final String MSG_FMT = "【%s】需要发起立项备案申请,请及时处理。";

private void declaredRecordReminder() {
Wrapper<Project> query = Wrappers.lambdaQuery(Project.class)
.eq(Project::getNewest, Boolean.TRUE)
.eq(Project::getStatus, ProjectStatusEnum.DECLARED_APPROVED_TO_BE_RECORD);
List<Project> projects = projectService.list(query);
if (projects.isEmpty()) {
return;
}
List<String> projectCodes = CollUtils.fieldList(projects, Project::getProjectCode);
List<Long> buildOrgCodes = projects.stream()
.map(Project::getBuildOrgCode)
.filter(w -> StrUtil.isNotBlank(w) && NumberUtil.isNumber(w))
.map(NumberUtil::parseLong)
.collect(Collectors.toList());
if (buildOrgCodes.isEmpty()) {
return;
}
List<UnitDTO> units = mhUnitCache.listByIds(buildOrgCodes);
Map<String, UnitDTO> unitMap = CollUtils.listToMap(units, w -> String.valueOf(w.getId()));
List<MhTodoRecord> todoRecords = todoRecordService.list(DECLARED_RECORD_APPLY, projectCodes);
Map<String, MhTodoRecord> todoRecordMap = CollUtils.listToMap(todoRecords, MhTodoRecord::getBizId);
List<UserFullInfoDTO> userFullInfos = userInfoHelper.listUserFullInfoByUnitIdsAndRole(buildOrgCodes, RoleEnum.COMPANY_MANAGER);
if (userFullInfos.isEmpty()) {
return;
}
Map<String, List<UserFullInfoDTO>> userMap = CollUtils.group(userFullInfos, UserFullInfoDTO::getMhUnitIdStr);
for (Project project : projects) {
try {
String projectCode = project.getProjectCode();
String buildOrgCode = project.getBuildOrgCode();
UnitDTO unit = unitMap.get(buildOrgCode);
if (unit == null) {
continue;
}
List<UserFullInfoDTO> currUnitUsers = userMap.get(buildOrgCode);
if (currUnitUsers == null) {
continue;
}
String content = String.format(MSG_FMT, project.getProjectName());
for (UserFullInfoDTO user : currUnitUsers) {
if (todoRecordMap.containsKey(project.getProjectCode())) {
MhZwddWorkNoticeDTO notice = MhZwddWorkNoticeDTO.builder()
.title(DECLARED_RECORD_APPLY.getVal())
.content(content)
.targetUser(user.getMhUserId())
.build();
mhApiClient.sendZwddWorkNotice(notice);
} else {
MhTodoExtraParamDTO paramObj = MhTodoExtraParamDTO.builder()
.projectId(project.getId())
.projectCode(projectCode)
.path("/declareManage/projectFiling")
.userId(user.getUserId())
.userName(user.getRealName())
.build();
mhTodoClient.addTodo(paramObj, user, DECLARED_RECORD_APPLY, projectCode, content);
}
}
} catch (Exception e) {
log.error("通知失败", e);
}
}
}

@PostConstruct
public void initTask() {
// 初始化立项备案提醒任务
if (this.open()) {
String cron = this.cron();
ThreadPoolUtil.SCHEDULER.schedule(this::declaredRecordReminder, triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
}
}

}

+ 39
- 0
hz-pm-api/src/main/java/com/hz/pm/api/scheduler/task/ReminderTask.java Parādīt failu

@@ -0,0 +1,39 @@
package com.hz.pm.api.scheduler.task;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.core.env.Environment;

/**
* <p>
* ReminderTask
* </p>
*
* @author WendyYang
* @since 13:20 2024/3/14
*/
@RequiredArgsConstructor
public abstract class ReminderTask {

public static final String PREFIX = "reminder-task";
public static final String CRON = "cron";
public static final String OPEN = "open";

public final Environment environment;


public abstract String getTaskPropertyName();

public boolean open() {
String property = PREFIX + "." + getTaskPropertyName() + "." + OPEN;
Boolean value = environment.getProperty(property, Boolean.class);
return value != null && value;
}

public String cron() {
String property = PREFIX + "." + getTaskPropertyName() + "." + CRON;
return environment.getProperty(property, String.class);
}

}

+ 21
- 0
hz-pm-api/src/main/java/com/hz/pm/api/sys/service/IMhTodoRecordService.java Parādīt failu

@@ -1,8 +1,15 @@
package com.hz.pm.api.sys.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hz.pm.api.external.todo.enumerization.MHTodoTypeEnum;
import com.hz.pm.api.sys.entity.MhTodoRecord;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.Collection;
import java.util.List;

/**
* <p>
* 信产待办发送记录 服务类
@@ -13,4 +20,18 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface IMhTodoRecordService extends IService<MhTodoRecord> {

default MhTodoRecord getOne(MHTodoTypeEnum type, String bizId) {
Wrapper<MhTodoRecord> query = Wrappers.lambdaQuery(MhTodoRecord.class)
.eq(MhTodoRecord::getType, type.name())
.eq(MhTodoRecord::getBizId, bizId);
return getOne(query);
}

default List<MhTodoRecord> list(MHTodoTypeEnum type, Collection<String> bizIds) {
Wrapper<MhTodoRecord> query = Wrappers.lambdaQuery(MhTodoRecord.class)
.eq(MhTodoRecord::getType, type.name())
.in(MhTodoRecord::getBizId, bizIds);
return list(query);
}

}

+ 8
- 1
hz-pm-api/src/main/resources/application-dev.yml Parādīt failu

@@ -263,4 +263,11 @@ agent-login:
proxy:
secret-key: nqkwiqojg7g4eiypr3rb8s7nb4noa8b2
sms:
client-url: http://10.54.38.13:8081/mh-gateway/auth-single
client-url: http://10.54.38.13:8081/mh-gateway/auth-single


# 提醒任务
reminder-task:
declared-record:
open: false
cron: 0 30 8 * * ?

+ 7
- 1
hz-pm-api/src/main/resources/application-prod.yml Parādīt failu

@@ -268,4 +268,10 @@ auth-code:
secret-key: uqrvd2bani4fercnisua1cqxjwk1neym
agent-login:
proxy:
secret-key: tqkwiqojg5j4eiypr3rb8w7nb4noa8b2
secret-key: tqkwiqojg5j4eiypr3rb8w7nb4noa8b2

# 提醒任务
reminder-task:
declared-record:
open: false
cron: 0 30 8 * * ?

+ 3
- 1
hz-pm-api/src/test/java/com/hz/pm/api/todocenter/MhApiClientTest.java Parādīt failu

@@ -26,7 +26,9 @@ public class MhApiClientTest extends AppTests {

@Test
public void sendTodo() {
UserFullInfoDTO assignee = userInfoHelper.getUserFullInfo("347873");
UserFullInfoDTO assignee = new UserFullInfoDTO();
assignee.setUserId(347873L);
assignee.setMhUserId("62697f4ed80d823fa1f26c5a082d989e");
JSONObject paramObj = new JSONObject();
paramObj.set("projectId", 1213);
paramObj.set("instId", 1213);


Notiek ielāde…
Atcelt
Saglabāt