feat(sip): 增加项目管理功能
- 在 ProjectInfo 模型中添加 partnerName 字段 - 在 ProjectInfoMapper 中添加 selectUserById 方法 - 在 ProjectInfoMapper.xml 中添加 selectUserById SQL 语句 - 在 ProjectInfoServiceImpl 中实现项目信息保存和其他信息变更记录功能 -优化项目信息更新逻辑,增加操作日志记录 - 重构操作日志记录方法,提高可读性和可维护性master
parent
3ef4149d83
commit
d5fedeb3f5
|
@ -66,8 +66,10 @@ public class ProjectInfo extends BaseEntity
|
|||
private String operateInstitution;
|
||||
|
||||
/** 代理商code */
|
||||
@Excel(name = "代理商code")
|
||||
|
||||
private String partnerCode;
|
||||
@Excel(name = "代理商")
|
||||
private String partnerName;
|
||||
|
||||
/** 联系方式 */
|
||||
@Excel(name = "联系方式")
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.ruoyi.sip.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.sip.domain.ProjectInfo;
|
||||
|
||||
/**
|
||||
|
@ -60,4 +62,6 @@ public interface ProjectInfoMapper
|
|||
public int deleteProjectInfoByIds(String[] ids);
|
||||
|
||||
String selectMaxProjectCode(ProjectInfo projectInfo);
|
||||
|
||||
List<SysUser> selectUserById(List<String> list);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package com.ruoyi.sip.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.DictUtils;
|
||||
import com.ruoyi.common.utils.ShiroUtils;
|
||||
import com.ruoyi.sip.domain.*;
|
||||
import com.ruoyi.sip.service.IProjectOperateLogService;
|
||||
|
@ -35,9 +37,15 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
|||
private IProjectWorkProgressService workProgressService;
|
||||
@Autowired
|
||||
private IProjectOperateLogService operateLogService;
|
||||
|
||||
private static final String PROJECT_CODE_PREFIX = "V";
|
||||
private static final Integer PROJECT_CODE_LENGTH = 5;
|
||||
|
||||
|
||||
public static final String INDUSTRY_TYPE_DICT_TYPE = "industry_type";
|
||||
public static final String PROJECT_STAGE_DICT_TYPE = "project_stage";
|
||||
public static final String OPERATE_INSTITUTION_DICT_TYPE = "operate_institution";
|
||||
|
||||
/**
|
||||
* 查询项目管理
|
||||
*
|
||||
|
@ -91,29 +99,40 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
|||
projectInfo.setCreateTime(DateUtils.getNowDate());
|
||||
projectInfo.setCreateBy(ShiroUtils.getUserId().toString());
|
||||
int i = projectInfoMapper.insertProjectInfo(projectInfo);
|
||||
saveOtherInfo(projectInfo);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void saveOtherInfo(ProjectInfo projectInfo1) {
|
||||
//插入产品信息
|
||||
List<ProjectProductInfo> hardwareProjectProductInfoList = projectInfo.getHardwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> softwareProjectProductInfoList = projectInfo.getSoftwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> addList=new ArrayList<>();
|
||||
addList.addAll(hardwareProjectProductInfoList);
|
||||
addList.addAll(softwareProjectProductInfoList);
|
||||
if (CollUtil.isNotEmpty(addList)){
|
||||
List<ProjectProductInfo> hardwareProjectProductInfoList = projectInfo1.getHardwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> softwareProjectProductInfoList = projectInfo1.getSoftwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> addList = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(hardwareProjectProductInfoList)) {
|
||||
addList.addAll(hardwareProjectProductInfoList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(softwareProjectProductInfoList)) {
|
||||
addList.addAll(softwareProjectProductInfoList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(addList)) {
|
||||
for (ProjectProductInfo projectProductInfo : addList) {
|
||||
projectProductInfo.setProjectId(projectInfo.getId());
|
||||
projectProductInfo.setProjectId(projectInfo1.getId());
|
||||
}
|
||||
productInfoService.saveBatch(addList);
|
||||
}
|
||||
//插入变更记录信息
|
||||
List<ProjectWorkProgress> projectWorkProgressList = projectInfo.getProjectWorkProgressList();
|
||||
List<ProjectWorkProgress> projectWorkProgressList = projectInfo1.getProjectWorkProgressList();
|
||||
if (CollUtil.isNotEmpty(projectWorkProgressList)) {
|
||||
for (ProjectWorkProgress workProgress : projectWorkProgressList) {
|
||||
workProgress.setProjectId(projectInfo.getId());
|
||||
workProgress.setProjectId(projectInfo1.getId());
|
||||
workProgress.setWorkUser(ShiroUtils.getUserId().toString());
|
||||
workProgress.setWorkTime(DateUtils.getNowDate());
|
||||
}
|
||||
workProgressService.insertIgnoreBatch(projectWorkProgressList);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 修改项目管理
|
||||
*
|
||||
|
@ -124,35 +143,60 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
|||
public int updateProjectInfo(ProjectInfo projectInfo) {
|
||||
// 获取更新前的项目信息
|
||||
ProjectInfo oldProjectInfo = projectInfoMapper.selectProjectInfoById(projectInfo.getId());
|
||||
|
||||
// 更新项目信息
|
||||
projectInfo.setUpdateTime(DateUtils.getNowDate());
|
||||
int result = projectInfoMapper.updateProjectInfo(projectInfo);
|
||||
|
||||
//变更其它信息
|
||||
saveOtherInfo(projectInfo);
|
||||
// 记录操作日志
|
||||
recordOperationLogs(projectInfo, oldProjectInfo);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void recordOperationLogs(ProjectInfo projectInfo, ProjectInfo oldProjectInfo) {
|
||||
StringBuilder logContent = new StringBuilder();
|
||||
int logIndex = 1;
|
||||
// 比较项目信息字段差异
|
||||
logIndex = compareField(logContent, logIndex, "项目名称", oldProjectInfo.getProjectName(), projectInfo.getProjectName());
|
||||
logIndex = compareField(logContent, logIndex, "客户名称", oldProjectInfo.getCustomerName(), projectInfo.getCustomerName());
|
||||
|
||||
logIndex = compareField(logContent, logIndex, "行业", DictUtils.getDictLabel(INDUSTRY_TYPE_DICT_TYPE, oldProjectInfo.getIndustryType())
|
||||
, DictUtils.getDictLabel(INDUSTRY_TYPE_DICT_TYPE, projectInfo.getIndustryType()));
|
||||
logIndex = compareField(logContent, logIndex, "属地", oldProjectInfo.getProvince(), projectInfo.getProvince());
|
||||
logIndex = compareField(logContent, logIndex, "项目阶段", DictUtils.getDictLabel(PROJECT_STAGE_DICT_TYPE, oldProjectInfo.getProjectStage())
|
||||
, DictUtils.getDictLabel(PROJECT_STAGE_DICT_TYPE, projectInfo.getProjectStage()));
|
||||
logIndex = compareField(logContent, logIndex, "项目把握度", oldProjectInfo.getProjectGraspDegree(), projectInfo.getProjectGraspDegree());
|
||||
if (oldProjectInfo.getHzSupportUser() != null || projectInfo.getHzSupportUser() != null) {
|
||||
List<SysUser> sysUsers = projectInfoMapper.selectUserById(Stream.of(oldProjectInfo.getHzSupportUser(), projectInfo.getHzSupportUser()).filter(Objects::nonNull).collect(Collectors.toList()));
|
||||
Map<String, String> userMap = sysUsers.stream().collect(Collectors.toMap(item -> item.getUserId().toString(), SysUser::getUserName));
|
||||
logIndex = compareField(logContent, logIndex, "汇智支撑人员", userMap.get(oldProjectInfo.getHzSupportUser()), userMap.get(projectInfo.getHzSupportUser()));
|
||||
}
|
||||
|
||||
logIndex = compareField(logContent, logIndex, "运作机构", DictUtils.getDictLabel(OPERATE_INSTITUTION_DICT_TYPE, oldProjectInfo.getOperateInstitution()),
|
||||
DictUtils.getDictLabel(OPERATE_INSTITUTION_DICT_TYPE, projectInfo.getOperateInstitution()));
|
||||
//替换代理商名称
|
||||
logIndex = compareField(logContent, logIndex, "代理商", oldProjectInfo.getPartnerName(), projectInfo.getPartnerName());
|
||||
logIndex = compareField(logContent, logIndex, "联系方式", oldProjectInfo.getContactWay(), projectInfo.getContactWay());
|
||||
logIndex = compareBigDecimalField(logContent, logIndex, "预计金额", oldProjectInfo.getEstimatedAmount(), projectInfo.getEstimatedAmount());
|
||||
logIndex = compareField(logContent, logIndex, "预计下单时间", oldProjectInfo.getEstimatedOrderTime(), projectInfo.getEstimatedOrderTime());
|
||||
logIndex = compareField(logContent, logIndex, "预计发货时间", oldProjectInfo.getEstimatedDeliverTime(), projectInfo.getEstimatedDeliverTime());
|
||||
logIndex = compareField(logContent, logIndex, "竞争对手", oldProjectInfo.getCompetitor(), projectInfo.getCompetitor());
|
||||
logIndex = compareField(logContent, logIndex, "关键技术问题", oldProjectInfo.getKeyProblem(), projectInfo.getKeyProblem());
|
||||
logIndex = compareField(logContent, logIndex, "项目简述", oldProjectInfo.getProjectDesc(), projectInfo.getProjectDesc());
|
||||
|
||||
// 配置信息变更
|
||||
List<ProjectProductInfo> oldHardwareList = oldProjectInfo.getHardwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> oldSoftwareList = oldProjectInfo.getSoftwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> newHardwareList = projectInfo.getHardwareProjectProductInfoList();
|
||||
List<ProjectProductInfo> newSoftwareList = projectInfo.getSoftwareProjectProductInfoList();
|
||||
|
||||
// 比较硬件产品信息
|
||||
logIndex = compareProductInfoList(logContent, logIndex, "硬件产品", oldHardwareList, newHardwareList);
|
||||
|
||||
|
||||
// 比较软件产品信息
|
||||
logIndex = compareProductInfoList(logContent, logIndex, "软件产品", oldSoftwareList, newSoftwareList);
|
||||
|
||||
// 比较字段差异
|
||||
compareField(logContent, logIndex++, "项目名称", oldProjectInfo.getProjectName(), projectInfo.getProjectName());
|
||||
compareField(logContent, logIndex++, "客户名称", oldProjectInfo.getCustomerName(), projectInfo.getCustomerName());
|
||||
compareField(logContent, logIndex++, "行业", oldProjectInfo.getIndustryType(), projectInfo.getIndustryType());
|
||||
compareField(logContent, logIndex++, "属地", oldProjectInfo.getProvince(), projectInfo.getProvince());
|
||||
compareField(logContent, logIndex++, "项目阶段", oldProjectInfo.getProjectStage(), projectInfo.getProjectStage());
|
||||
compareField(logContent, logIndex++, "项目把握度", oldProjectInfo.getProjectGraspDegree(), projectInfo.getProjectGraspDegree());
|
||||
compareField(logContent, logIndex++, "汇智支撑人员", oldProjectInfo.getHzSupportUser(), projectInfo.getHzSupportUser());
|
||||
compareField(logContent, logIndex++, "运作机构", oldProjectInfo.getOperateInstitution(), projectInfo.getOperateInstitution());
|
||||
compareField(logContent, logIndex++, "代理商", oldProjectInfo.getOperateInstitution(), projectInfo.getOperateInstitution());
|
||||
compareField(logContent, logIndex++, "竞争对手", oldProjectInfo.getCompetitor(), projectInfo.getCompetitor());
|
||||
// compareField(logContent, logIndex++, "项目类型", oldProjectInfo.getProjectType(), projectInfo.getProjectType());
|
||||
// compareField(logContent, logIndex++, "项目状态", oldProjectInfo.getProjectStatus(), projectInfo.getProjectStatus());
|
||||
// compareField(logContent, logIndex++, "项目经理", oldProjectInfo.getProjectManager(), projectInfo.getProjectManager());
|
||||
// compareField(logContent, logIndex++, "预期收益", oldProjectInfo.getExpectedRevenue(), projectInfo.getExpectedRevenue());
|
||||
// compareField(logContent, logIndex++, "实际收益", oldProjectInfo.getActualRevenue(), projectInfo.getActualRevenue());
|
||||
// compareField(logContent, logIndex++, "开始日期", oldProjectInfo.getStartDate(), projectInfo.getStartDate());
|
||||
// compareField(logContent, logIndex++, "结束日期", oldProjectInfo.getEndDate(), projectInfo.getEndDate());
|
||||
// compareField(logContent, logIndex++, "风险等级", oldProjectInfo.getRiskLevel(), projectInfo.getRiskLevel());
|
||||
// compareField(logContent, logIndex++, "备注", oldProjectInfo.getRemarks(), projectInfo.getRemarks());
|
||||
|
||||
// 插入操作日志
|
||||
if (logContent.length() > 0) {
|
||||
|
@ -163,21 +207,81 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
|||
operateLog.setOperateUser(ShiroUtils.getUserId().toString());
|
||||
operateLogService.insertProjectOperateLog(operateLog);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较字段并生成日志内容
|
||||
* 比较产品信息列表并生成日志内容
|
||||
*
|
||||
* @param logContent 日志内容构建器
|
||||
* @param index 日志索引
|
||||
* @param fieldName 字段名称
|
||||
* @param oldValue 旧值
|
||||
* @param newValue 新值
|
||||
* @param type 产品类型(硬件或软件)
|
||||
* @param oldList 旧的产品信息列表
|
||||
* @param newList 新的产品信息列表
|
||||
*/
|
||||
private void compareField(StringBuilder logContent, int index, String fieldName, Object oldValue, Object newValue) {
|
||||
if (!oldValue.equals(newValue)) {
|
||||
private int compareProductInfoList(StringBuilder logContent, int index, String type, List<ProjectProductInfo> oldList, List<ProjectProductInfo> newList) {
|
||||
// 将旧列表和新列表转换为以 id 为键的 Map,便于快速查找
|
||||
Map<Long, ProjectProductInfo> oldMap = CollUtil.isEmpty(oldList) ? new HashMap<>() : oldList.stream()
|
||||
.collect(Collectors.toMap(ProjectProductInfo::getId, product -> product));
|
||||
Map<Long, ProjectProductInfo> newMap = CollUtil.isEmpty(newList) ? new HashMap<>() : newList.stream()
|
||||
.collect(Collectors.toMap(ProjectProductInfo::getId, product -> product));
|
||||
|
||||
// 获取所有 id 的并集
|
||||
Set<Long> allIds = new HashSet<>(oldMap.keySet());
|
||||
allIds.addAll(newMap.keySet());
|
||||
|
||||
for (Long id : allIds) {
|
||||
ProjectProductInfo oldProduct = oldMap.get(id);
|
||||
ProjectProductInfo newProduct = newMap.get(id);
|
||||
|
||||
if (oldProduct == null && newProduct != null) {
|
||||
// 新增产品
|
||||
logContent.append(index).append(".").append(type).append("新增:").append(newProduct.getProductCode()).append("\n");
|
||||
index++;
|
||||
} else if (oldProduct != null && newProduct == null) {
|
||||
// 删除产品
|
||||
logContent.append(index).append(".").append(type).append("删除:").append(oldProduct.getProductCode()).append("\n");
|
||||
index++;
|
||||
} else if (oldProduct != null) {
|
||||
// 变更产品
|
||||
|
||||
if (!oldProduct.getProductCode().equals(newProduct.getProductCode())) {
|
||||
logContent.append(index).append(".").append(type).append("变更:").append(oldProduct.getProductCode()).append(" -> ").append(newProduct.getProductCode()).append("\n");
|
||||
index++;
|
||||
}
|
||||
if (!Objects.equals(oldProduct.getModel(), newProduct.getModel())) {
|
||||
logContent.append(index).append(".").append("型号").append("由‘").append(oldProduct.getModel()).append("’变更为‘").append(newProduct.getModel()).append("’\n");
|
||||
index++;
|
||||
}
|
||||
if (!Objects.equals(oldProduct.getQuantity(), newProduct.getQuantity())) {
|
||||
logContent.append(index).append(".").append("数量").append("由‘").append(oldProduct.getQuantity()).append("’变更为‘").append(newProduct.getQuantity()).append("’\n");
|
||||
index++;
|
||||
}
|
||||
if (!Objects.equals(oldProduct.getRemark(), newProduct.getRemark())) {
|
||||
logContent.append(index).append(".").append("备注").append("由‘").append(oldProduct.getRemark()).append("’变更为‘").append(newProduct.getRemark()).append("’\n");
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private int compareField(StringBuilder logContent, int index, String fieldName, Object oldValue, Object newValue) {
|
||||
if (!Objects.equals(oldValue, newValue)) {
|
||||
logContent.append(index).append(".")
|
||||
.append(fieldName)
|
||||
.append("由‘")
|
||||
.append(oldValue == null ? "" : oldValue)
|
||||
.append("’变更为‘")
|
||||
.append(newValue == null ? "" : oldValue)
|
||||
.append("’\n");
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
private int compareBigDecimalField(StringBuilder logContent, int index, String fieldName, BigDecimal oldValue, BigDecimal newValue) {
|
||||
if (oldValue != null && newValue != null && oldValue.compareTo(newValue) != 0) {
|
||||
logContent.append(index).append(".")
|
||||
.append(fieldName)
|
||||
.append("由‘")
|
||||
|
@ -185,7 +289,9 @@ public class ProjectInfoServiceImpl implements IProjectInfoService {
|
|||
.append("’变更为‘")
|
||||
.append(newValue)
|
||||
.append("’\n");
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,7 +34,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
</resultMap>
|
||||
|
||||
<sql id="selectProjectInfoVo">
|
||||
select id, project_code, project_name, customer_code, customer_name, industry_type, province, project_stage, project_grasp_degree, hz_support_user, operate_institution, partner_code, contact_way, estimated_amount, currency_type, estimated_order_time, estimated_deliver_time, competitor, country_product, server_configuration, key_problem, project_desc, create_by, create_time, update_by, update_time from project_info
|
||||
select id, project_code, project_name, customer_code, customer_name, industry_type, province, project_stage, project_grasp_degree, hz_support_user, operate_institution
|
||||
, partner_code, partner_name, contact_way, estimated_amount, currency_type, estimated_order_time, estimated_deliver_time, competitor, country_product, server_configuration
|
||||
, key_problem, project_desc, create_by, create_time, update_by, update_time from project_info
|
||||
</sql>
|
||||
|
||||
<select id="selectProjectInfoList" parameterType="ProjectInfo" resultMap="ProjectInfoResult">
|
||||
|
@ -51,6 +53,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="hzSupportUser != null and hzSupportUser != ''"> and hz_support_user = #{hzSupportUser}</if>
|
||||
<if test="operateInstitution != null and operateInstitution != ''"> and operate_institution = #{operateInstitution}</if>
|
||||
<if test="partnerCode != null and partnerCode != ''"> and partner_code = #{partnerCode}</if>
|
||||
<if test="partnerName != null and partnerName != ''"> and partner_name = #{partnerName}</if>
|
||||
<if test="contactWay != null and contactWay != ''"> and contact_way = #{contactWay}</if>
|
||||
<if test="estimatedAmount != null "> and estimated_amount = #{estimatedAmount}</if>
|
||||
<if test="currencyType != null and currencyType != ''"> and currency_type = #{currencyType}</if>
|
||||
|
@ -73,6 +76,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
where province=#{province}
|
||||
order by project_code desc limit 1
|
||||
</select>
|
||||
<select id="selectUserById" resultType="com.ruoyi.common.core.domain.entity.SysUser">
|
||||
select * from sys_user
|
||||
where id in <foreach collection="list" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<insert id="insertProjectInfo" parameterType="ProjectInfo" useGeneratedKeys="true" keyProperty="id">
|
||||
insert into project_info
|
||||
|
@ -88,6 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="hzSupportUser != null">hz_support_user,</if>
|
||||
<if test="operateInstitution != null">operate_institution,</if>
|
||||
<if test="partnerCode != null">partner_code,</if>
|
||||
<if test="partnerName != null">partner_name,</if>
|
||||
<if test="contactWay != null">contact_way,</if>
|
||||
<if test="estimatedAmount != null">estimated_amount,</if>
|
||||
<if test="currencyType != null">currency_type,</if>
|
||||
|
@ -115,6 +125,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="hzSupportUser != null">#{hzSupportUser},</if>
|
||||
<if test="operateInstitution != null">#{operateInstitution},</if>
|
||||
<if test="partnerCode != null">#{partnerCode},</if>
|
||||
<if test="partnerName != null">#{partnerName},</if>
|
||||
<if test="contactWay != null">#{contactWay},</if>
|
||||
<if test="estimatedAmount != null">#{estimatedAmount},</if>
|
||||
<if test="currencyType != null">#{currencyType},</if>
|
||||
|
@ -145,7 +156,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||
<if test="projectGraspDegree != null">project_grasp_degree = #{projectGraspDegree},</if>
|
||||
<if test="hzSupportUser != null">hz_support_user = #{hzSupportUser},</if>
|
||||
<if test="operateInstitution != null">operate_institution = #{operateInstitution},</if>
|
||||
<if test="partnerCode != null">partner_code = #{partnerCode},</if>
|
||||
partner_code = #{partnerCode},
|
||||
<if test="partnerName != null">partner_name = #{partnerName},</if>
|
||||
<if test="contactWay != null">contact_way = #{contactWay},</if>
|
||||
<if test="estimatedAmount != null">estimated_amount = #{estimatedAmount},</if>
|
||||
<if test="currencyType != null">currency_type = #{currencyType},</if>
|
||||
|
|
Loading…
Reference in New Issue