20240419更新

master
RENCHAO 3 years ago
parent 596717b85a
commit 4fb66d1e61

@ -44,11 +44,11 @@
<version>2.2.6</version> <version>2.2.6</version>
</dependency> </dependency>
<!--常用工具库--> <!--常用工具库-->
<dependency> <!-- <dependency>-->
<groupId>com.google.guava</groupId> <!-- <groupId>com.google.guava</groupId>-->
<artifactId>guava</artifactId> <!-- <artifactId>guava</artifactId>-->
<version>29.0-jre</version> <!-- <version>29.0-jre</version>-->
</dependency> <!-- </dependency>-->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency> <dependency>

@ -332,101 +332,9 @@ public class Test01 {
@Test @Test
public void test16() { public void test16() {
// System.out.println(isMatch("abcdef", "a*ef"));
// System.out.println(isMatch("aaaef", "a*ef"));
// System.out.println(isMatch("abcdefghi", ".*"));
// System.out.println(isMatch("aa", "a"));
System.out.println(isMatch("aa", "a*"));
// System.out.println(isMatch("aa", "a*b*"));
// System.out.println(isMatch("aab", "c*a*b"));
System.out.println(isMatch("aab", ".*"));
// System.out.println(isMatch("abcde", ".*de"));
// System.out.println(isMatch("mississippi", "mis*is*ip*."));
// System.out.println(isMatch("mississippi", "mis*is*p*."));
// System.out.println(isMatch("issippi", "is*p*."));
// System.out.println("abcd".substring(1));
} }
public boolean isMatch(String s, String p) {
int row = s.length();
int col = p.length();
boolean[][] dp = new boolean[row + 1][col + 1];
// 初始化首行
dp[0][0] = true;
for (int j = 2; j <= col; j += 2) {
if (dp[0][j - 2] && p.charAt(j - 1) == '*') {
dp[0][j] = true;
}
}
// 状态转移
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= col; j++) {
if (p.charAt(j - 1) == '*') {
if (dp[i][j - 2] || (dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.'))) {
dp[i][j] = true;
}
} else {
if (dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.')) {
dp[i][j] = true;
}
}
}
}
return dp[row][col];
}
public boolean isMatch4(String s, String p) {
if (s.isEmpty() && p.isEmpty()) {
return true;
}
if (s.isEmpty() || p.isEmpty()) {
return false;
}
if (p.length() > 1 && p.charAt(1) == '*') {
if (p.charAt(0) == '.') {
return true;
}
int i = 0;
while (i < s.length() && s.charAt(i) == p.charAt(0)) {
i++;
}
return isMatch4(s.substring(i), p.substring(2));
} else if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.') {
return isMatch4(s.substring(1), p.substring(1));
} else {
return false;
}
}
@Test
public void test21() {
System.out.println(isMatch22("aa", "a*"));
}
public boolean isMatch22(String s, String p) {
int m = s.length() + 1, n = p.length() + 1;
boolean[][] dp = new boolean[m][n];
dp[0][0] = true;
for (int j = 2; j < n; j += 2)
dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = p.charAt(j - 1) == '*' ?
dp[i][j - 2] || dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') :
dp[i - 1][j - 1] && (p.charAt(j - 1) == '.' || s.charAt(i - 1) == p.charAt(j - 1));
}
}
return dp[m - 1][n - 1];
}
} }

@ -1,9 +1,18 @@
package com.renchao; package com.renchao;
import org.junit.Test;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -49,4 +58,96 @@ public class ZipDemo {
in.close(); in.close();
} }
} }
@Test
public void test01() throws IOException {
// ArrayList<File> list = new ArrayList<>();
// collect(new File("C:\\Users\\RENCHAO\\Desktop\\temp-sss\\aa\\20240314094355A076"), list);
long l = System.currentTimeMillis();
File file = new File("C:\\Users\\RENCHAO\\Desktop\\aa.pdf");
try (/*FileInputStream in = new FileInputStream(file);*/
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("C:\\Users\\RENCHAO\\Desktop\\temp-sss\\aa\\output.zip"))) {
ZipEntry entry = new ZipEntry("aa.pdf");
entry.setMethod(ZipEntry.STORED);
// Set the size of the file
entry.setSize(file.length());
// Set the CRC-32 checksum of the file
entry.setCrc(calcChecksum(file));
out.setLevel(Deflater.NO_COMPRESSION);
out.putNextEntry(entry);
System.out.println("创建entry:" + (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
// byte[] buffer = new byte[2048];
// int len;
// while ((len = in.read(buffer)) > 0) {
// out.write(buffer, 0, len);
// }
try (FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(8192); // 8KB缓冲区
int bytesRead;
while ((bytesRead = fileChannel.read(buffer)) != -1) {
buffer.flip(); // 切换到读模式
out.write(buffer.array(), 0, bytesRead);
buffer.clear(); // 清空缓冲区
}
}
//ZipOutputStream.write可以使用NIO操作吗,以提高效率
System.out.println("压缩完成:" + (System.currentTimeMillis() - l));
}
}
public void collect(File file, List<File> list) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
collect(f, list);
}
}
} else {
list.add(file);
}
}
// Calculate CRC-32 checksum of a file
private static long calcChecksum(File file) throws IOException {
try (FileInputStream fis = new FileInputStream(file);
CheckedInputStream cis = new CheckedInputStream(fis, new CRC32())) {
byte[] buffer = new byte[2048];
while (cis.read(buffer) >= 0) {
// Reading the file to calculate CRC-32 checksum
}
return cis.getChecksum().getValue();
}
}
private static long calcChecksum2(File file) throws IOException {
try (FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
CRC32 crc32 = new CRC32();
while (fileChannel.read(buffer) != -1) {
buffer.flip();
crc32.update(buffer);
buffer.clear();
}
return crc32.getValue();
}
}
} }

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

@ -21,8 +21,8 @@ public class IpUtils {
// 未知地址 // 未知地址
public static final String UNKNOWN = "XX XX"; public static final String UNKNOWN = "XX XX";
private static final Logger LOGGER = LoggerFactory.getLogger(IpUtils.class); private static final Logger LOGGER = LoggerFactory.getLogger(IpUtils.class);
private static final RestTemplate restTemplate = new RestTemplate(); private static RestTemplate restTemplate = new RestTemplate();
private static final ObjectMapper objectMapper = new ObjectMapper(); private static ObjectMapper objectMapper = new ObjectMapper();
public static String getRealAddressByIP(String ip, boolean isAddressEnabled) { public static String getRealAddressByIP(String ip, boolean isAddressEnabled) {
// 内网不查询 // 内网不查询

@ -127,6 +127,11 @@ public class PortalUserDTO implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
/** /**
* Get用户id * Get用户id
*/ */
@ -456,4 +461,12 @@ public class PortalUserDTO implements Serializable {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
} }

@ -12,7 +12,6 @@ import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static com.jiuyv.sptccc.agile.common.utils.IpUtils.UNKNOWN; import static com.jiuyv.sptccc.agile.common.utils.IpUtils.UNKNOWN;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -40,17 +39,13 @@ class IpUtilsTest {
@BeforeEach @BeforeEach
void setUp() throws ReflectiveOperationException { void setUp() throws ReflectiveOperationException {
Field modifier = Field.class.getDeclaredField("modifiers");
modifier.setAccessible(true);
Field restTemplateField = IpUtils.class.getDeclaredField("restTemplate"); Field restTemplateField = IpUtils.class.getDeclaredField("restTemplate");
restTemplateField.setAccessible(true); restTemplateField.setAccessible(true);
modifier.setInt(restTemplateField, restTemplateField.getModifiers() & ~Modifier.FINAL);
restTemplateField.set(null, restTemplate); restTemplateField.set(null, restTemplate);
Field objectMapperField = IpUtils.class.getDeclaredField("objectMapper"); Field objectMapperField = IpUtils.class.getDeclaredField("objectMapper");
objectMapperField.setAccessible(true); objectMapperField.setAccessible(true);
modifier.setInt(objectMapperField, objectMapperField.getModifiers() & ~Modifier.FINAL);
objectMapperField.set(null, objectMapper); objectMapperField.set(null, objectMapper);
} }

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-gateway</artifactId> <artifactId>agile-portal-gateway</artifactId>

@ -147,7 +147,7 @@ public class SysLoginService {
captcha = StringUtil.randomNumber(6); captcha = StringUtil.randomNumber(6);
localCache.setValueOfCacheName(CacheNames.CACHE_1MIN, phone, captcha); localCache.setValueOfCacheName(CacheNames.CACHE_1MIN, phone, captcha);
localCache.setValueOfCacheName(CacheNames.CACHE_5MIN, phone, captcha); localCache.setValueOfCacheName(CacheNames.CACHE_5MIN, phone, captcha);
LOGGER.info("手机{}验证码:{}", phone, captcha); LOGGER.info("手机{}验证码:{}", StringUtil.strHide(phone), captcha);
if (consoleProperties.isCaptchaTest()) { if (consoleProperties.isCaptchaTest()) {
return captcha; return captcha;
@ -302,7 +302,11 @@ public class SysLoginService {
if (!passwordEncoder.matches(oldPassword, user.getPassword())) { if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
throw new ServiceException("原密码错误"); throw new ServiceException("原密码错误");
} }
String encodePassword = passwordEncoder.encode(secretService.decodePassword(userPasswordDTO.getPassword())); String password = secretService.decodePassword(userPasswordDTO.getPassword());
if (password.equals(oldPassword)) {
throw new ServiceException("新密码不能与原密码相同");
}
String encodePassword = passwordEncoder.encode(password);
userPasswordDTO.setPassword(encodePassword); userPasswordDTO.setPassword(encodePassword);
userPasswordDTO.setUserId(user.getUserId()); userPasswordDTO.setUserId(user.getUserId());
R<Void> r = userService.resetUserPwd(userPasswordDTO); R<Void> r = userService.resetUserPwd(userPasswordDTO);

@ -59,7 +59,8 @@ public class UserDetailsServiceImpl implements UserDetailsService {
// 第一次登录,只有基本权限,修改密码后获取所有权限 // 第一次登录,只有基本权限,修改密码后获取所有权限
List<GrantedAuthority> authorities = new ArrayList<>(); List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_BASE)); authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_BASE));
if (userDTO.getFirstFlag() != null) { Integer pwdUpdateTime = userDTO.getPwdRemainderDate();
if (userDTO.getFirstFlag() != null && (pwdUpdateTime == null || pwdUpdateTime >= 0)) {
authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_ALL)); authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_ALL));
} }
return new LoginUser(user.getUserId(), user.getDeptId(), user, authorities); return new LoginUser(user.getUserId(), user.getDeptId(), user, authorities);

@ -120,6 +120,7 @@ public class ContentController extends BaseController {
Response feignResponse = portalContentFeign.sdkDownload(); Response feignResponse = portalContentFeign.sdkDownload();
response.addHeader("Content-Length", getResponseHeader(feignResponse,"content-length")); response.addHeader("Content-Length", getResponseHeader(feignResponse,"content-length"));
response.addHeader("Content-Disposition", "attachment;filename=sdk.rar"); response.addHeader("Content-Disposition", "attachment;filename=sdk.rar");
response.addHeader("Content-Type", "text/html; charset=utf-8");
IOUtils.copy(feignResponse.body().asInputStream(), response.getOutputStream()); IOUtils.copy(feignResponse.body().asInputStream(), response.getOutputStream());
} }
@ -134,6 +135,7 @@ public class ContentController extends BaseController {
response.addHeader("Content-Length", getResponseHeader(feignResponse,"content-length")); response.addHeader("Content-Length", getResponseHeader(feignResponse,"content-length"));
String fileName = URLEncoder.encode("(用户版)实验室使用说明.pdf", "UTF-8"); String fileName = URLEncoder.encode("(用户版)实验室使用说明.pdf", "UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName); response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Content-Type", "text/html; charset=utf-8");
IOUtils.copy(feignResponse.body().asInputStream(), response.getOutputStream()); IOUtils.copy(feignResponse.body().asInputStream(), response.getOutputStream());
} }

@ -175,6 +175,10 @@ public class TblPortalUser implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
/** /**
* 请求参数 * 请求参数
@ -623,6 +627,14 @@ public class TblPortalUser implements Serializable {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
public Map<String, Object> getParams() { public Map<String, Object> getParams() {
if (params == null) { if (params == null) {
params = new HashMap<>(); params = new HashMap<>();

@ -91,6 +91,11 @@ public class UserInfoDTO implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
public Long getUserId() { public Long getUserId() {
return userId; return userId;
} }
@ -226,4 +231,12 @@ public class UserInfoDTO implements Serializable {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
} }

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>久事大数据开放平台</title><script defer="defer" src="static/js/chunk-vendors.7aad466f.js"></script><script defer="defer" src="static/js/app.11080c4c.js"></script><link href="static/css/chunk-vendors.d47dac03.css" rel="stylesheet"><link href="static/css/app.f5ad523a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 久事大数据开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>久事大数据开放平台</title><script defer="defer" src="static/js/chunk-vendors.7aad466f.js"></script><script defer="defer" src="static/js/app.ad9f929b.js"></script><link href="static/css/chunk-vendors.d47dac03.css" rel="stylesheet"><link href="static/css/app.f5ad523a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 久事大数据开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

@ -1 +0,0 @@
.personal-info .el-form-item__label{text-align:left!important;font-size:16px!important}.personal-info .el-form-item__content{font-size:16px!important}.personal-info .el-form-item{margin-bottom:0}.personal-info[data-v-5e8b44ac]{padding-top:20px;font-size:16px}.personal-info .el-icon-success[data-v-5e8b44ac]{margin-right:6px;color:#6cbd7f}.personal-info .change-pwd-link[data-v-5e8b44ac]{margin-left:15px;color:#3165db}

@ -1 +0,0 @@
.lab-apply .top-filter[data-v-de1afecc]{margin-top:24px}.lab-apply .tale-list[data-v-de1afecc] .el-table th.el-table__cell{color:#333;background:#fafafa;padding:5px 0;font-size:16px}.lab-apply .tale-list[data-v-de1afecc] .el-table .cell.el-tooltip{font-size:16px}.lab-apply .tale-list .review-status[data-v-de1afecc]{display:flex;align-items:center}.lab-apply .tale-list .review-status .icon-circle[data-v-de1afecc]{width:6px;height:6px;border-radius:3px;margin-right:8px;background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.grey[data-v-de1afecc]{background:#d9d9d9}.lab-apply .tale-list .review-status .icon-circle.orange[data-v-de1afecc]{background:#ffd859}.lab-apply .tale-list .review-status .icon-circle.green[data-v-de1afecc]{background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.red[data-v-de1afecc]{background:#ff4d4f}.lab-apply[data-v-de1afecc] .el-pagination{text-align:right}

@ -1 +0,0 @@
.find-password[data-v-2725d968]{width:100%;min-height:500px;background:#fff}.find-password[data-v-2725d968] .el-step__title{text-align:center}.find-password .title[data-v-2725d968]{padding:40px 20px;text-align:center;font-size:26px;line-height:40px;font-weight:400}.find-password .el-form[data-v-2725d968]{width:382px;margin:60px auto 20px auto}.find-password .procees-contaner[data-v-2725d968]{width:700px;padding:60px 200px;margin:0 auto 50px auto;background:#fff}.divClass[data-v-2725d968]{width:100%;height:10px;margin:5px 0}.divClass span[data-v-2725d968]{float:left;background:#ccc;height:10px;width:31%;margin:0 1%}.divClass .weak[data-v-2725d968]{background-color:#f56c6c}.divClass .medium[data-v-2725d968]{background-color:#e6a23c}.divClass .strong[data-v-2725d968]{background-color:#67c23a}

@ -1 +0,0 @@
.inner-container[data-v-351a2db2]{margin:20px auto;background:#fff}.routerList[data-v-351a2db2]{background:#ecf5ff;height:100vh;border-radius:10px 10px 0 0}.routerList h2[data-v-351a2db2]{text-align:center;font-size:24px;background:#e6171e;color:#fff;line-height:45px;border-radius:10px 10px 0 0}.routerList ul[data-v-351a2db2]{line-height:45px;padding:20px 0}.routerList ul li[data-v-351a2db2]{font-size:18px;font-weight:600;padding:0 20px}.routerList ul li.on[data-v-351a2db2]{background:#fff;border-left:5px solid #e6171e}.routerList ul li.on a[data-v-351a2db2]{color:#e6171e}.api-list-container[data-v-351a2db2]{background:#f9f9f9}.api-list-container .guide-pic[data-v-351a2db2]{background:url(../../static/img/data-service.82b45c45.jpg) no-repeat top;background-size:100%}.api-list-container .api-list ul[data-v-351a2db2]{width:100%;align-items:flex-start;flex-wrap:wrap;justify-content:space-between;padding-top:30px;overflow:hidden}.api-list-container .api-list ul li[data-v-351a2db2]{padding:15px;margin-bottom:50px;box-sizing:border-box;width:32%;height:296px;background:#fff;box-shadow:0 0 6px 0 rgba(217,225,238,.47);border-radius:2px;transition-property:box-shadow transform;transition-duration:.25s,1s;float:left;margin-left:1%;cursor:pointer;border:2px solid #409eff}.api-list-container .api-list ul li[data-v-351a2db2]:hover{transform:translateY(-10px);box-shadow:0 0 16px 0 rgba(217,225,238,.47);background:linear-gradient(180deg,#2980b9,#87ceeb);border:2px solid #adb5bd}.api-list-container .api-list ul li:hover .aip-intro[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-info .others b[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-info[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-name[data-v-351a2db2]{color:#fff}.api-list-container .api-list ul li .api-name[data-v-351a2db2]{font-size:18px;color:#181818;font-weight:700;line-height:18px;height:18px;margin-bottom:15px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.api-list-container .api-list ul li .aip-intro[data-v-351a2db2]{height:120px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;color:#666;line-height:24px;margin-bottom:20px;font-size:14px}.api-list-container .api-list ul li .api-info[data-v-351a2db2]{padding:20px 0;color:#ababab;font-size:14px;border-top:1px solid #d8d8d8}.api-list-container .api-list ul li .api-info .others[data-v-351a2db2]{display:flex;justify-content:space-between}.api-list-container .api-list ul li .api-info .others b[data-v-351a2db2]{font-weight:400;font-size:12px;color:#5274ca;line-height:1;padding:4px 5px;border-radius:2px;border:1px solid #5274ca}.api-list-container .api-list ul li .api-info .data-from[data-v-351a2db2]{padding-bottom:15px}.api-list-container .api-list .pagination-container[data-v-351a2db2]{background:transparent}.api-list-container .api-list[data-v-351a2db2] .el-pagination{text-align:center}

@ -1 +0,0 @@
.el-table--scrollable-x .el-table__body-wrapper{height:355px}.lab-apply .top-filter[data-v-b3b3944e]{margin-top:24px}.lab-apply .tale-list[data-v-b3b3944e] .el-table th.el-table__cell{color:#333;background:#fafafa;padding:5px 0;font-size:16px}.lab-apply .tale-list[data-v-b3b3944e] .el-table .cell.el-tooltip{font-size:16px}.lab-apply .tale-list .review-status[data-v-b3b3944e]{display:flex;align-items:center}.lab-apply .tale-list .review-status .icon-circle[data-v-b3b3944e]{width:6px;height:6px;border-radius:3px;margin-right:8px;background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.grey[data-v-b3b3944e]{background:#d9d9d9}.lab-apply .tale-list .review-status .icon-circle.orange[data-v-b3b3944e]{background:#ffd859}.lab-apply .tale-list .review-status .icon-circle.green[data-v-b3b3944e]{background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.red[data-v-b3b3944e]{background:#ff4d4f}.lab-apply[data-v-b3b3944e] .el-pagination,[data-v-b3b3944e] .el-pagination{text-align:right}[data-v-b3b3944e] .el-dialog__body{padding:10px}::-webkit-scrollbar{width:7px;height:7px}::-webkit-scrollbar-thumb{border-radius:7px;background-color:rgba(0,0,0,.25)}::-webkit-scrollbar-track{background-color:#f6f6f6}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{border:0}

@ -1 +0,0 @@
"use strict";(self["webpackChunkagile_portal_front"]=self["webpackChunkagile_portal_front"]||[]).push([[146],{53146:(t,e,s)=>{s.r(e),s.d(e,{default:()=>c});var a=function(){var t=this,e=t._self._c;return e("div",{staticClass:"personal-info"},[e("el-form",{ref:"form1",attrs:{model:t.form,"label-width":"140px",align:"left"}},[e("el-row",[e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{align:"left",label:"用户名"}},[e("span",[t._v(t._s(t.form.userName))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"手机号"}},[e("span",[t._v(t._s(t.form.phonenumber))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"状态"}},["0"==t.form.status?e("span",{staticStyle:{color:"#6CBD7F"}},[t._v("正常")]):e("span",{staticStyle:{color:"red"}},[t._v("停用")])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"企业名"}},[e("span",[t._v(t._s(t.form.enterpriseName))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"社会统一信用代码"}},[e("span",[t._v(t._s(t.form.socialCreditCode))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"行业类型"}},[e("span",[t._v(t._s(t.form.industryCategory))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"地址"}},[e("span",[t._v(t._s(t.form.enterpriseAddress))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"登录密码"}},[e("i",{staticClass:"icon el-icon-success"}),e("span",[t._v("已设置")]),e("router-link",{staticClass:"change-pwd-link",attrs:{to:"/resetpwd"}},[t._v("更改密码")])],1)],1)],1)],1)],1)},r=[],l=s(12223);const o={name:"UserInfo",data:function(){return{form:{}}},created:function(){this.getUserInfo()},methods:{getUserInfo:function(){var t=this;(0,l.C5)().then((function(e){t.form=e.data,"0"==t.form.firstFlag&&t.$router.push("/resetpwd")["catch"]((function(){}))}))}}},n=o;var f=s(1001),i=(0,f.Z)(n,a,r,!1,null,"5e8b44ac",null);const c=i.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
"use strict";(self["webpackChunkagile_portal_front"]=self["webpackChunkagile_portal_front"]||[]).push([[53],{77053:(t,a,s)=>{s.r(a),s.d(a,{default:()=>u});var i=function(){var t=this,a=t._self._c;return a("div",{staticClass:"api-list-container container"},[t._m(0),a("div",{staticClass:"inner-container"},[a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:4,xs:24}},[a("div",{staticClass:"routerList"},[a("h2",[t._v("数据服务")]),a("ul",[a("li",[a("router-link",{attrs:{to:"/service/introduce"}},[t._v("服务介绍")])],1),a("li",[a("router-link",{attrs:{to:"/service/guide"}},[t._v("服务指南")])],1),a("li",{staticClass:"on"},[a("router-link",{attrs:{to:"/service/api"}},[t._v("API列表")])],1)])])]),a("el-col",{attrs:{span:20,xs:24}},[a("div",{staticClass:"api-list",staticStyle:{overflow:"auto"}},[a("ul",{staticClass:"list"},t._l(t.apiList,(function(s){return a("li",{key:s.id},[a("div",{staticClass:"api-name"},[t._v(t._s(s.apiName))]),a("div",{staticClass:"aip-intro"},[t._v(" "+t._s(s.apiName)+" ")]),a("div",{staticClass:"api-info"},[a("div",{staticClass:"data-from"},[t._v("数据提供方:上海公共交通卡有限公司")]),a("div",{staticClass:"others"},[a("span",[t._v("更新时间:"+t._s(s.createTime))]),a("b",[t._v("有条件开放")])])])])})),0),a("pagination",{directives:[{name:"show",rawName:"v-show",value:t.total>0,expression:"total > 0"}],attrs:{total:t.total,page:t.queryParams.pageNum,limit:t.queryParams.pageSize},on:{"update:page":function(a){return t.$set(t.queryParams,"pageNum",a)},"update:limit":function(a){return t.$set(t.queryParams,"pageSize",a)},pagination:t.getList}})],1)])],1)],1)])},e=[function(){var t=this,a=t._self._c;return a("div",{staticClass:"top-banner guide-pic"},[a("div",{staticClass:"slogan"},[a("h3",{staticClass:"title"},[t._v("API列表 ")]),a("div",{staticClass:"summary"},[t._v("旨在优化数据对外服务方式,提高开发效率,为用户提供规范化数据服务")])])])}],r=s(47121);const n={name:"ApiList",data:function(){return{total:0,apiList:[],queryParams:{pageNum:1,pageSize:9}}},computed:{},mounted:function(){this.backToTop(),this.$parent.$parent.$parent.$refs.topnav.topbg=""},created:function(){this.getList()},methods:{backToTop:function(){window.scrollTo({top:0,behavior:"smooth"})},getList:function(){var t=this;(0,r.ZF)(this.queryParams).then((function(a){t.apiList=a.rows,t.total=a.total}))}}},o=n;var l=s(1001),c=(0,l.Z)(o,i,e,!1,null,"351a2db2",null);const u=c.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -283,6 +283,10 @@ class SysLoginServiceTest {
@Test @Test
void changePassword() { void changePassword() {
ResUserPasswordDTO userPasswordDTO = mock(ResUserPasswordDTO.class); ResUserPasswordDTO userPasswordDTO = mock(ResUserPasswordDTO.class);
when(userPasswordDTO.getPassword()).thenReturn("a");
when(userPasswordDTO.getOldPassword()).thenReturn("a");
when(secretService.decodePassword("a")).thenReturn("A");
when(secretService.decodePassword("b")).thenReturn("B");
LoginUser loginUser = mock(LoginUser.class); LoginUser loginUser = mock(LoginUser.class);
securityUtilsMockedStatic.when(SecurityUtils::getLoginUser).thenReturn(loginUser); securityUtilsMockedStatic.when(SecurityUtils::getLoginUser).thenReturn(loginUser);
TblPortalUser portalUser = mock(TblPortalUser.class); TblPortalUser portalUser = mock(TblPortalUser.class);
@ -304,6 +308,14 @@ class SysLoginServiceTest {
assertTrue(e instanceof ServiceException); assertTrue(e instanceof ServiceException);
} }
when(userPasswordDTO.getOldPassword()).thenReturn("b");
try {
sysLoginService.changePassword(userPasswordDTO);
fail();
} catch (Exception e) {
assertTrue(e instanceof ServiceException);
}
when(userService.resetUserPwd(userPasswordDTO)).thenReturn(R.ok()); when(userService.resetUserPwd(userPasswordDTO)).thenReturn(R.ok());
servletUtilsMockedStatic.when(ServletUtils::getSession).thenReturn(mock(HttpSession.class)); servletUtilsMockedStatic.when(ServletUtils::getSession).thenReturn(mock(HttpSession.class));
try { try {

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-service</artifactId> <artifactId>agile-portal-service</artifactId>

@ -25,7 +25,7 @@ public class ConsoleProperties {
/** /**
* 文档下载文件名 * 文档下载文件名
*/ */
private String wordFileName = "word.docx"; private String wordFileName = "LaboratoryOperationsManual.pdf";
/** /**
* sdk下载文件名 * sdk下载文件名
@ -43,6 +43,16 @@ public class ConsoleProperties {
*/ */
private long downloadMaxFile = 100L; private long downloadMaxFile = 100L;
/**
* 密码过期时间,默认1年
*/
private int passwordExpirationDates = 365;
/**
* 密码快过期时间提醒,默认提前15天
*/
private int passwordExpirationWarnDates = 15;
public boolean isAddressEnabled() { public boolean isAddressEnabled() {
return addressEnabled; return addressEnabled;
@ -91,4 +101,20 @@ public class ConsoleProperties {
public void setDownloadMaxFile(long downloadMaxFile) { public void setDownloadMaxFile(long downloadMaxFile) {
this.downloadMaxFile = downloadMaxFile; this.downloadMaxFile = downloadMaxFile;
} }
public int getPasswordExpirationDates() {
return passwordExpirationDates;
}
public void setPasswordExpirationDates(int passwordExpirationDates) {
this.passwordExpirationDates = passwordExpirationDates;
}
public int getPasswordExpirationWarnDates() {
return passwordExpirationWarnDates;
}
public void setPasswordExpirationWarnDates(int passwordExpirationWarnDates) {
this.passwordExpirationWarnDates = passwordExpirationWarnDates;
}
} }

@ -7,13 +7,15 @@ import com.jiuyv.sptccc.agile.common.core.domain.R;
import com.jiuyv.sptccc.agile.common.enums.BusinessType; import com.jiuyv.sptccc.agile.common.enums.BusinessType;
import com.jiuyv.sptccc.agile.dto.PortalUserDTO; import com.jiuyv.sptccc.agile.dto.PortalUserDTO;
import com.jiuyv.sptccc.agile.dto.ResUserPasswordDTO; import com.jiuyv.sptccc.agile.dto.ResUserPasswordDTO;
import com.jiuyv.sptccc.agile.framework.config.ConsoleProperties;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalUser;
import com.jiuyv.sptccc.agile.portal.service.IPortalUserService;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalUser; import java.util.Date;
import com.jiuyv.sptccc.agile.portal.service.IPortalUserService;
import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX; import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX;
@ -28,9 +30,11 @@ import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX;
public class PortalUserController implements PortalUserFeignApi { public class PortalUserController implements PortalUserFeignApi {
private final IPortalUserService userService; private final IPortalUserService userService;
private final ConsoleProperties consoleProperties;
public PortalUserController(IPortalUserService userService) { public PortalUserController(IPortalUserService userService, ConsoleProperties consoleProperties) {
this.userService = userService; this.userService = userService;
this.consoleProperties = consoleProperties;
} }
/** /**
@ -49,6 +53,13 @@ public class PortalUserController implements PortalUserFeignApi {
String[] split = avatar.split("/"); String[] split = avatar.split("/");
userDTO.setAvatar("content/images/" + split[split.length - 1]); userDTO.setAvatar("content/images/" + split[split.length - 1]);
} }
// 计算密码过期时间
Date pwdUpdateTime = user.getPwdUpdateTime();
long diff = consoleProperties.getPasswordExpirationDates()
- (System.currentTimeMillis() - pwdUpdateTime.getTime()) / 1000 / 60 / 60 / 24;
if (diff <= consoleProperties.getPasswordExpirationWarnDates()) {
userDTO.setPwdRemainderDate((int) diff);
}
return R.ok(userDTO); return R.ok(userDTO);
} }

@ -173,6 +173,11 @@ public class TblPortalUser extends BaseEntity {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码更新时间
*/
private Date pwdUpdateTime;
/** /**
* Get用户id * Get用户id
@ -615,4 +620,12 @@ public class TblPortalUser extends BaseEntity {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Date getPwdUpdateTime() {
return pwdUpdateTime;
}
public void setPwdUpdateTime(Date pwdUpdateTime) {
this.pwdUpdateTime = pwdUpdateTime;
}
} }

@ -38,7 +38,7 @@ import java.util.stream.Collectors;
@Service @Service
public class FileServiceImpl extends AbstractSftpFileService implements IFileService { public class FileServiceImpl extends AbstractSftpFileService implements IFileService {
private static final Logger LOGGER = LoggerFactory.getLogger(FileServiceImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(FileServiceImpl.class);
private static final List<String> ALLOW_IMAGE_EXT = Arrays.asList("bmp", "gif", "jpg", "jpeg", "png"); private static final List<String> ALLOW_IMAGE_EXT = Arrays.asList("bmp", "gif", "jpg", "jpeg", "png", "BMP", "GIF", "JPG", "JPEG", "PNG");
private static final List<String> ALLOW_PYTHON_EXT = Arrays.asList("zip", "tar", "gz", "bz2"); private static final List<String> ALLOW_PYTHON_EXT = Arrays.asList("zip", "tar", "gz", "bz2");
private static final List<String> ALLOW_DATA_EXT = Arrays.asList("zip", "tar", "gz", "csv", "txt", "xls", "xlsx"); private static final List<String> ALLOW_DATA_EXT = Arrays.asList("zip", "tar", "gz", "csv", "txt", "xls", "xlsx");

@ -23,7 +23,7 @@ import java.util.regex.Pattern;
@Service @Service
public class PortalContentServiceImpl implements IPortalContentService { public class PortalContentServiceImpl implements IPortalContentService {
private static final Logger LOGGER = LoggerFactory.getLogger(PortalContentServiceImpl.class); private static final Logger LOGGER = LoggerFactory.getLogger(PortalContentServiceImpl.class);
private static final Pattern IMG_P = Pattern.compile("/?images/console/[a-fA-F0-9]+\\.(jpg|jpeg|png|gif|bmp|tiff|tif|webp|svg|ico)"); private static final Pattern IMG_P = Pattern.compile("(?i)/?images/console/[a-f0-9]+\\.(jpg|jpeg|png|gif|bmp|tiff|tif|webp|svg|ico)");
private final PortalContentMapper portalContentMapper; private final PortalContentMapper portalContentMapper;
private final IFileService fileService; private final IFileService fileService;

@ -34,6 +34,7 @@
<result property="loginErrorCount" column="login_error_count"/> <result property="loginErrorCount" column="login_error_count"/>
<result property="lastLoginErrorTime" column="last_login_error_time"/> <result property="lastLoginErrorTime" column="last_login_error_time"/>
<result property="firstFlag" column="first_flag"/> <result property="firstFlag" column="first_flag"/>
<result property="pwdUpdateTime" column="pwd_update_time"/>
</resultMap> </resultMap>
<sql id="selectUserVo"> <sql id="selectUserVo">
@ -63,7 +64,8 @@
u.social_credit_code, u.social_credit_code,
u.enterprise_industry, u.enterprise_industry,
u.enterprise_address, u.enterprise_address,
u.first_flag u.first_flag,
u.pwd_update_time
from tbl_portal_user u from tbl_portal_user u
</sql> </sql>
@ -118,7 +120,9 @@
update tbl_portal_user update tbl_portal_user
set version_num = version_num + 1, set version_num = version_num + 1,
password= #{password}, password= #{password},
first_flag='1' first_flag='1',
update_time = now(),
pwd_update_time = now()
where user_id = #{userId} where user_id = #{userId}
</update> </update>
</mapper> </mapper>

@ -2,6 +2,7 @@ package com.jiuyv.sptccc.agile.portal.service.impl;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.jiuyv.sptccc.agile.common.exception.ServiceException; import com.jiuyv.sptccc.agile.common.exception.ServiceException;
import com.jiuyv.sptccc.agile.framework.config.ConsoleProperties;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalContent; import com.jiuyv.sptccc.agile.portal.domain.TblPortalContent;
import com.jiuyv.sptccc.agile.portal.mapper.PortalContentMapper; import com.jiuyv.sptccc.agile.portal.mapper.PortalContentMapper;
import com.jiuyv.sptccc.agile.portal.service.IFileService; import com.jiuyv.sptccc.agile.portal.service.IFileService;
@ -35,6 +36,9 @@ class PortalContentServiceImplTest {
@Mock @Mock
private IFileService fileService; private IFileService fileService;
@Mock
private ConsoleProperties consoleProperties;
@Test @Test
void getContentList() { void getContentList() {
String showType = "1"; String showType = "1";

@ -1 +1 @@
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>久事大数据开放平台</title><script defer="defer" src="static/js/chunk-vendors.7aad466f.js"></script><script defer="defer" src="static/js/app.11080c4c.js"></script><link href="static/css/chunk-vendors.d47dac03.css" rel="stylesheet"><link href="static/css/app.f5ad523a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 久事大数据开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html> <!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>久事大数据开放平台</title><script defer="defer" src="static/js/chunk-vendors.7aad466f.js"></script><script defer="defer" src="static/js/app.ad9f929b.js"></script><link href="static/css/chunk-vendors.d47dac03.css" rel="stylesheet"><link href="static/css/app.f5ad523a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but 久事大数据开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

@ -1 +0,0 @@
.personal-info .el-form-item__label{text-align:left!important;font-size:16px!important}.personal-info .el-form-item__content{font-size:16px!important}.personal-info .el-form-item{margin-bottom:0}.personal-info[data-v-5e8b44ac]{padding-top:20px;font-size:16px}.personal-info .el-icon-success[data-v-5e8b44ac]{margin-right:6px;color:#6cbd7f}.personal-info .change-pwd-link[data-v-5e8b44ac]{margin-left:15px;color:#3165db}

@ -1 +0,0 @@
.lab-apply .top-filter[data-v-de1afecc]{margin-top:24px}.lab-apply .tale-list[data-v-de1afecc] .el-table th.el-table__cell{color:#333;background:#fafafa;padding:5px 0;font-size:16px}.lab-apply .tale-list[data-v-de1afecc] .el-table .cell.el-tooltip{font-size:16px}.lab-apply .tale-list .review-status[data-v-de1afecc]{display:flex;align-items:center}.lab-apply .tale-list .review-status .icon-circle[data-v-de1afecc]{width:6px;height:6px;border-radius:3px;margin-right:8px;background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.grey[data-v-de1afecc]{background:#d9d9d9}.lab-apply .tale-list .review-status .icon-circle.orange[data-v-de1afecc]{background:#ffd859}.lab-apply .tale-list .review-status .icon-circle.green[data-v-de1afecc]{background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.red[data-v-de1afecc]{background:#ff4d4f}.lab-apply[data-v-de1afecc] .el-pagination{text-align:right}

@ -1 +0,0 @@
.find-password[data-v-2725d968]{width:100%;min-height:500px;background:#fff}.find-password[data-v-2725d968] .el-step__title{text-align:center}.find-password .title[data-v-2725d968]{padding:40px 20px;text-align:center;font-size:26px;line-height:40px;font-weight:400}.find-password .el-form[data-v-2725d968]{width:382px;margin:60px auto 20px auto}.find-password .procees-contaner[data-v-2725d968]{width:700px;padding:60px 200px;margin:0 auto 50px auto;background:#fff}.divClass[data-v-2725d968]{width:100%;height:10px;margin:5px 0}.divClass span[data-v-2725d968]{float:left;background:#ccc;height:10px;width:31%;margin:0 1%}.divClass .weak[data-v-2725d968]{background-color:#f56c6c}.divClass .medium[data-v-2725d968]{background-color:#e6a23c}.divClass .strong[data-v-2725d968]{background-color:#67c23a}

@ -1 +0,0 @@
.inner-container[data-v-351a2db2]{margin:20px auto;background:#fff}.routerList[data-v-351a2db2]{background:#ecf5ff;height:100vh;border-radius:10px 10px 0 0}.routerList h2[data-v-351a2db2]{text-align:center;font-size:24px;background:#e6171e;color:#fff;line-height:45px;border-radius:10px 10px 0 0}.routerList ul[data-v-351a2db2]{line-height:45px;padding:20px 0}.routerList ul li[data-v-351a2db2]{font-size:18px;font-weight:600;padding:0 20px}.routerList ul li.on[data-v-351a2db2]{background:#fff;border-left:5px solid #e6171e}.routerList ul li.on a[data-v-351a2db2]{color:#e6171e}.api-list-container[data-v-351a2db2]{background:#f9f9f9}.api-list-container .guide-pic[data-v-351a2db2]{background:url(../../static/img/data-service.82b45c45.jpg) no-repeat top;background-size:100%}.api-list-container .api-list ul[data-v-351a2db2]{width:100%;align-items:flex-start;flex-wrap:wrap;justify-content:space-between;padding-top:30px;overflow:hidden}.api-list-container .api-list ul li[data-v-351a2db2]{padding:15px;margin-bottom:50px;box-sizing:border-box;width:32%;height:296px;background:#fff;box-shadow:0 0 6px 0 rgba(217,225,238,.47);border-radius:2px;transition-property:box-shadow transform;transition-duration:.25s,1s;float:left;margin-left:1%;cursor:pointer;border:2px solid #409eff}.api-list-container .api-list ul li[data-v-351a2db2]:hover{transform:translateY(-10px);box-shadow:0 0 16px 0 rgba(217,225,238,.47);background:linear-gradient(180deg,#2980b9,#87ceeb);border:2px solid #adb5bd}.api-list-container .api-list ul li:hover .aip-intro[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-info .others b[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-info[data-v-351a2db2],.api-list-container .api-list ul li:hover .api-name[data-v-351a2db2]{color:#fff}.api-list-container .api-list ul li .api-name[data-v-351a2db2]{font-size:18px;color:#181818;font-weight:700;line-height:18px;height:18px;margin-bottom:15px;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.api-list-container .api-list ul li .aip-intro[data-v-351a2db2]{height:120px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;color:#666;line-height:24px;margin-bottom:20px;font-size:14px}.api-list-container .api-list ul li .api-info[data-v-351a2db2]{padding:20px 0;color:#ababab;font-size:14px;border-top:1px solid #d8d8d8}.api-list-container .api-list ul li .api-info .others[data-v-351a2db2]{display:flex;justify-content:space-between}.api-list-container .api-list ul li .api-info .others b[data-v-351a2db2]{font-weight:400;font-size:12px;color:#5274ca;line-height:1;padding:4px 5px;border-radius:2px;border:1px solid #5274ca}.api-list-container .api-list ul li .api-info .data-from[data-v-351a2db2]{padding-bottom:15px}.api-list-container .api-list .pagination-container[data-v-351a2db2]{background:transparent}.api-list-container .api-list[data-v-351a2db2] .el-pagination{text-align:center}

@ -1 +0,0 @@
.el-table--scrollable-x .el-table__body-wrapper{height:355px}.lab-apply .top-filter[data-v-b3b3944e]{margin-top:24px}.lab-apply .tale-list[data-v-b3b3944e] .el-table th.el-table__cell{color:#333;background:#fafafa;padding:5px 0;font-size:16px}.lab-apply .tale-list[data-v-b3b3944e] .el-table .cell.el-tooltip{font-size:16px}.lab-apply .tale-list .review-status[data-v-b3b3944e]{display:flex;align-items:center}.lab-apply .tale-list .review-status .icon-circle[data-v-b3b3944e]{width:6px;height:6px;border-radius:3px;margin-right:8px;background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.grey[data-v-b3b3944e]{background:#d9d9d9}.lab-apply .tale-list .review-status .icon-circle.orange[data-v-b3b3944e]{background:#ffd859}.lab-apply .tale-list .review-status .icon-circle.green[data-v-b3b3944e]{background:#52c41a}.lab-apply .tale-list .review-status .icon-circle.red[data-v-b3b3944e]{background:#ff4d4f}.lab-apply[data-v-b3b3944e] .el-pagination,[data-v-b3b3944e] .el-pagination{text-align:right}[data-v-b3b3944e] .el-dialog__body{padding:10px}::-webkit-scrollbar{width:7px;height:7px}::-webkit-scrollbar-thumb{border-radius:7px;background-color:rgba(0,0,0,.25)}::-webkit-scrollbar-track{background-color:#f6f6f6}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{border:0}

@ -1 +0,0 @@
"use strict";(self["webpackChunkagile_portal_front"]=self["webpackChunkagile_portal_front"]||[]).push([[146],{53146:(t,e,s)=>{s.r(e),s.d(e,{default:()=>c});var a=function(){var t=this,e=t._self._c;return e("div",{staticClass:"personal-info"},[e("el-form",{ref:"form1",attrs:{model:t.form,"label-width":"140px",align:"left"}},[e("el-row",[e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{align:"left",label:"用户名"}},[e("span",[t._v(t._s(t.form.userName))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"手机号"}},[e("span",[t._v(t._s(t.form.phonenumber))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"状态"}},["0"==t.form.status?e("span",{staticStyle:{color:"#6CBD7F"}},[t._v("正常")]):e("span",{staticStyle:{color:"red"}},[t._v("停用")])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"企业名"}},[e("span",[t._v(t._s(t.form.enterpriseName))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"社会统一信用代码"}},[e("span",[t._v(t._s(t.form.socialCreditCode))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"行业类型"}},[e("span",[t._v(t._s(t.form.industryCategory))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"地址"}},[e("span",[t._v(t._s(t.form.enterpriseAddress))])])],1),e("el-col",{attrs:{span:24}},[e("el-form-item",{attrs:{label:"登录密码"}},[e("i",{staticClass:"icon el-icon-success"}),e("span",[t._v("已设置")]),e("router-link",{staticClass:"change-pwd-link",attrs:{to:"/resetpwd"}},[t._v("更改密码")])],1)],1)],1)],1)],1)},r=[],l=s(12223);const o={name:"UserInfo",data:function(){return{form:{}}},created:function(){this.getUserInfo()},methods:{getUserInfo:function(){var t=this;(0,l.C5)().then((function(e){t.form=e.data,"0"==t.form.firstFlag&&t.$router.push("/resetpwd")["catch"]((function(){}))}))}}},n=o;var f=s(1001),i=(0,f.Z)(n,a,r,!1,null,"5e8b44ac",null);const c=i.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
"use strict";(self["webpackChunkagile_portal_front"]=self["webpackChunkagile_portal_front"]||[]).push([[53],{77053:(t,a,s)=>{s.r(a),s.d(a,{default:()=>u});var i=function(){var t=this,a=t._self._c;return a("div",{staticClass:"api-list-container container"},[t._m(0),a("div",{staticClass:"inner-container"},[a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:4,xs:24}},[a("div",{staticClass:"routerList"},[a("h2",[t._v("数据服务")]),a("ul",[a("li",[a("router-link",{attrs:{to:"/service/introduce"}},[t._v("服务介绍")])],1),a("li",[a("router-link",{attrs:{to:"/service/guide"}},[t._v("服务指南")])],1),a("li",{staticClass:"on"},[a("router-link",{attrs:{to:"/service/api"}},[t._v("API列表")])],1)])])]),a("el-col",{attrs:{span:20,xs:24}},[a("div",{staticClass:"api-list",staticStyle:{overflow:"auto"}},[a("ul",{staticClass:"list"},t._l(t.apiList,(function(s){return a("li",{key:s.id},[a("div",{staticClass:"api-name"},[t._v(t._s(s.apiName))]),a("div",{staticClass:"aip-intro"},[t._v(" "+t._s(s.apiName)+" ")]),a("div",{staticClass:"api-info"},[a("div",{staticClass:"data-from"},[t._v("数据提供方:上海公共交通卡有限公司")]),a("div",{staticClass:"others"},[a("span",[t._v("更新时间:"+t._s(s.createTime))]),a("b",[t._v("有条件开放")])])])])})),0),a("pagination",{directives:[{name:"show",rawName:"v-show",value:t.total>0,expression:"total > 0"}],attrs:{total:t.total,page:t.queryParams.pageNum,limit:t.queryParams.pageSize},on:{"update:page":function(a){return t.$set(t.queryParams,"pageNum",a)},"update:limit":function(a){return t.$set(t.queryParams,"pageSize",a)},pagination:t.getList}})],1)])],1)],1)])},e=[function(){var t=this,a=t._self._c;return a("div",{staticClass:"top-banner guide-pic"},[a("div",{staticClass:"slogan"},[a("h3",{staticClass:"title"},[t._v("API列表 ")]),a("div",{staticClass:"summary"},[t._v("旨在优化数据对外服务方式,提高开发效率,为用户提供规范化数据服务")])])])}],r=s(47121);const n={name:"ApiList",data:function(){return{total:0,apiList:[],queryParams:{pageNum:1,pageSize:9}}},computed:{},mounted:function(){this.backToTop(),this.$parent.$parent.$parent.$refs.topnav.topbg=""},created:function(){this.getList()},methods:{backToTop:function(){window.scrollTo({top:0,behavior:"smooth"})},getList:function(){var t=this;(0,r.ZF)(this.queryParams).then((function(a){t.apiList=a.rows,t.total=a.total}))}}},o=n;var l=s(1001),c=(0,l.Z)(o,i,e,!1,null,"351a2db2",null);const u=c.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-ui</artifactId> <artifactId>agile-portal-ui</artifactId>

@ -37,11 +37,11 @@
<li v-for="item in apiList" :key="item.id"> <li v-for="item in apiList" :key="item.id">
<div class="api-name">{{ item.apiName }}</div> <div class="api-name">{{ item.apiName }}</div>
<div class="aip-intro"> <div class="aip-intro">
{{ item.apiName }} {{ item.remark }}
</div> </div>
<div class="api-info"> <div class="api-info">
<div class="data-from">数据提供方:上海公共交通卡有限公司</div> <div class="data-from">数据提供方:上海公共交通卡有限公司</div>
<div class="others"><span>更新时间:{{ item.createTime }}</span><b>有条件开放</b></div> <div class="others"><span>更新时间:{{ item.createTime }}</span></div>
</div> </div>
</li> </li>
</ul> </ul>

@ -1,7 +1,16 @@
<template> <template>
<div class="find-password container"> <div class="find-password container">
<h3 class="title">修改密码<span v-if="firstFlag == '0'" <h3 class="title">
style="text-align: center;padding: 10px;color: red;">(初次登陆需修改初始密码)</span> 修改密码<span
v-if="firstFlag == '0'"
style="text-align: center; padding: 10px; color: red"
>(初次登陆需修改初始密码)</span
>
<span
v-if="pwdRemainderDate <= 15 && pwdRemainderDate != null"
style="text-align: center; padding: 10px; color: red"
>(密码失效修改密码)</span
>
</h3> </h3>
<el-card class="procees-contaner"> <el-card class="procees-contaner">
@ -10,163 +19,228 @@
<el-step title="完成" description=""></el-step> <el-step title="完成" description=""></el-step>
</el-steps> </el-steps>
<!-- step2 --> <!-- step2 -->
<el-form v-if="processActive == 1" ref="form" :rules="rules" :model="form" label-width="100px"> <el-form
v-if="processActive == 1"
ref="form"
:rules="rules"
:model="form"
label-width="100px"
>
<el-form-item label="原密码" prop="oldPassword"> <el-form-item label="原密码" prop="oldPassword">
<el-input v-model="form.oldPassword" type="password"></el-input> <el-input v-model="form.oldPassword" type="password"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="新密码" prop="password"> <el-form-item label="新密码" prop="password">
<el-input v-model="form.password" :type="flagType" auto-complete="off" placeholder="" @input="strengthColor"> <el-input
<i style="cursor: pointer;" slot="suffix" class="el-input__icon el-icon-view" @click="getFlageye()"></i> v-model="form.password"
:type="flagType"
auto-complete="off"
placeholder=""
@input="strengthColor"
>
<i
style="cursor: pointer"
slot="suffix"
class="el-input__icon el-icon-view"
@click="getFlageye()"
></i>
</el-input> </el-input>
<div class="divClass"> <div class="divClass">
<span <span
:class="passwords == '1' ? 'weak' : '' || passwords == '2' ? 'medium' : '' || passwords == '3' ? 'strong' : ''"></span> :class="
<span :class="passwords == '2' ? 'medium' : '' || passwords == '3' ? 'strong' : ''"></span> passwords == '1'
? 'weak'
: '' || passwords == '2'
? 'medium'
: '' || passwords == '3'
? 'strong'
: ''
"
></span>
<span
:class="
passwords == '2'
? 'medium'
: '' || passwords == '3'
? 'strong'
: ''
"
></span>
<span :class="passwords == '3' ? 'strong' : ''"></span> <span :class="passwords == '3' ? 'strong' : ''"></span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="确认密码" prop="passwords"> <el-form-item label="确认密码" prop="passwords">
<el-input v-model="form.passwords" type="password"></el-input> <el-input v-model="form.passwords" type="password"></el-input>
</el-form-item> </el-form-item>
<el-form-item label=""> <el-button type="primary" @click="handleAuthon"> <el-form-item label="">
提交</el-button></el-form-item> <el-button type="primary" @click="handleAuthon">
提交</el-button
></el-form-item
>
</el-form> </el-form>
<!-- step3 --> <!-- step3 -->
<el-form v-if="processActive == 2" ref="form" :model="form" label-width="0px"> <el-form
v-if="processActive == 2"
ref="form"
:model="form"
label-width="0px"
>
<el-form-item label=""> <el-form-item label="">
<div class="success-tips" style="color: #1ae51ad1;font-size: 24px;font-weight: 600;text-align: center;"><i <div
class="icon el-icon-success"></i> 修改成功</div> class="success-tips"
<div class="go-back" style="text-align: center;"><span style="color: red;font-size: 18px;font-weight: bold;">{{ style="
remainingTime }}</span>秒后 <span>自动返回登录页</span></div> color: #1ae51ad1;
<div class="btn-back" style="text-align: center;"><el-button type="primary" @click="logout">重新登录</el-button> font-size: 24px;
font-weight: 600;
text-align: center;
"
>
<i class="icon el-icon-success"></i> 修改成功
</div>
<div class="go-back" style="text-align: center">
<span style="color: red; font-size: 18px; font-weight: bold">{{
remainingTime
}}</span
>秒后 <span>自动返回登录页</span>
</div>
<div class="btn-back" style="text-align: center">
<el-button type="primary" @click="logout">重新登录</el-button>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
import { changePassword } from "@/api/user"; import { changePassword } from "@/api/user";
import { getKeyiv } from "@/api/login"; import { getKeyiv } from "@/api/login";
import { encrypt } from '@/utils/jsencrypt' import { encrypt } from "@/utils/jsencrypt";
export default { export default {
name: "ResetPwd", name: "ResetPwd",
data() { data() {
return { return {
isShowMenu: false, isShowMenu: false,
passwords: '1', passwords: "1",
flagType: 'password', flagType: "password",
processActive: 1, processActive: 1,
form: { form: {
oldPassword: '', oldPassword: "",
password: '', password: "",
passwords: '', passwords: "",
}, },
firstFlag: '', firstFlag: "",
pwdRemainderDate: "",
remainingTime: 5, remainingTime: 5,
keyiv: '', keyiv: "",
countDown: 10, countDown: 10,
// 表单校验 // 表单校验
rules: { rules: {
oldPassword: [ oldPassword: [
{ required: true, message: "原密码不能为空", trigger: "blur" } { required: true, message: "原密码不能为空", trigger: "blur" },
], ],
password: [ password: [
{ required: true, message: "密码不能为空", trigger: "blur" }, { required: true, message: "密码不能为空", trigger: "blur" },
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: "密码须包含数字、大小写字母且长度在8-16之间",
trigger: 'blur' trigger: "blur",
}, },
], ],
passwords: [ passwords: [
{ required: true, message: "密码不能为空", trigger: "blur" }, { required: true, message: "密码不能为空", trigger: "blur" },
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: "密码须包含数字、大小写字母且长度在8-16之间",
trigger: 'blur' trigger: "blur",
}, },
], ],
} },
} };
}, },
created() { created() {
const storedData = localStorage.getItem('myData'); const storedData = localStorage.getItem("myData");
if (storedData) { if (storedData) {
const data = JSON.parse(storedData); const data = JSON.parse(storedData);
this.firstFlag = data.firstFlag this.firstFlag = data.firstFlag;
this.pwdRemainderDate = data.pwdRemainderDate;
} }
this.getKeyiv(); this.getKeyiv();
}, },
methods: { methods: {
getFlageye() { getFlageye() {
this.flagType = this.flagType == 'password' ? 'text' : 'password';//text为显示密码;password为隐藏密码 this.flagType = this.flagType == "password" ? "text" : "password"; //text为显示密码;password为隐藏密码
}, },
strengthColor() { strengthColor() {
if (this.form.password.length <= 6) { if (this.form.password.length <= 6) {
this.passwords = '1'// 红色 this.passwords = "1"; // 红色
} else if (this.form.password.length <= 10) { } else if (this.form.password.length <= 10) {
this.passwords = '2'// 橙色 this.passwords = "2"; // 橙色
} else { } else {
this.passwords = '3' // 绿色 this.passwords = "3"; // 绿色
} }
}, },
getKeyiv() { getKeyiv() {
getKeyiv().then((response) => { getKeyiv().then((response) => {
this.keyiv = response.data this.keyiv = response.data;
}) });
}, },
logout() { logout() {
this.$store.dispatch('LogOut').then(() => { this.$store.dispatch("LogOut").then(() => {
this.$router.push("/login") this.$router.push("/login");
}) });
}, },
//提交 //提交
handleAuthon() { handleAuthon() {
if (this.form.password != this.form.passwords) { if (this.form.password != this.form.passwords) {
this.$message({ this.$message({
type: 'warning', type: "warning",
message: '新密码与确认密码不一致!' message: "新密码与确认密码不一致!",
}); });
return return;
} }
this.$refs["form"].validate(valid => { this.$refs["form"].validate((valid) => {
if (valid) { if (valid) {
this.form.passwords = '' this.form.passwords = "";
this.form.oldPassword = encrypt(this.keyiv, this.form.oldPassword + ',' + new Date().getTime()) this.form.oldPassword = encrypt(
this.form.password = encrypt(this.keyiv, this.form.password + ',' + new Date().getTime()) this.keyiv,
changePassword(this.form).then(res => { this.form.oldPassword + "," + new Date().getTime()
this.processActive++ );
this.countdownInterval = setInterval(() => { this.form.password = encrypt(
// 倒计时结束后执行的操作 this.keyiv,
console.log('倒计时结束'); this.form.password + "," + new Date().getTime()
if (this.remainingTime > 0) { );
this.remainingTime--; // 每秒递减1秒 changePassword(this.form).then((res) => {
} else { debugger;
clearInterval(this.countdownInterval); // 如果倒计时结束,清除计时器 if (res.code == 200) {
} this.processActive++;
this.$store.dispatch('LogOut').then(() => { this.countdownInterval = setInterval(() => {
this.$router.push("/login") // 倒计时结束后执行的操作
}) console.log("倒计时结束");
if (this.remainingTime > 0) {
}, 1000); this.remainingTime--; // 每秒递减1秒
}) } else {
clearInterval(this.countdownInterval); // 如果倒计时结束,清除计时器
}
this.$store.dispatch("LogOut").then(() => {
this.$router.push("/login");
});
}, 1000);
} else {
this.form.oldPassword = "";
this.form.password = "";
this.strengthColor();
}
});
} }
}) });
},
}
}, },
beforeDestroy() { beforeDestroy() {
clearTimeout(this.countdownInterval); // 在组件销毁之前清除倒计时 clearTimeout(this.countdownInterval); // 在组件销毁之前清除倒计时
}, },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -214,21 +288,18 @@ export default {
} }
.weak { .weak {
background-color: #F56C6C; background-color: #f56c6c;
/* 红色 */ /* 红色 */
} }
.medium { .medium {
background-color: #E6A23C; background-color: #e6a23c;
/* 橙色 */ /* 橙色 */
} }
.strong { .strong {
background-color: #67C23A; background-color: #67c23a;
/* 绿色 */ /* 绿色 */
} }
} }
</style> </style>

@ -14,8 +14,8 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="状态"> <el-form-item label="状态">
<span v-if="form.status == '0'" style="color: #6CBD7F;">正常</span> <span v-if="form.status == '0'" style="color: #6cbd7f">正常</span>
<span v-else style="color: red;">停用</span> <span v-else style="color: red">停用</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- <el-col :span="24"> <!-- <el-col :span="24">
@ -45,41 +45,82 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="登录密码"> <el-form-item label="登录密码">
<i class="icon el-icon-success"></i><span>已设置</span><router-link to="/resetpwd" <i class="icon el-icon-success"></i><span>已设置</span
class="change-pwd-link">更改密码</router-link> ><router-link to="/resetpwd" class="change-pwd-link"
>更改密码</router-link
>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<el-dialog
width="400px"
title="密码到期提示"
:visible.sync="opens"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div style="text-align: center; font-size: 18px">
登录密码还有<span
style="color: red; font-size: 25px; font-weight: bold"
>{{ form.pwdRemainderDate }}</span
>天到期,请尽快修改密码!
</div>
<div slot="footer" class="dialog-footer" style="text-align: right">
<el-button @click="opens = false">关闭</el-button>
<el-button type="primary" @click="handlefile">去修改</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { getInfo } from '@/api/login' import { getInfo } from "@/api/login";
export default { export default {
name: "UserInfo", name: "UserInfo",
data() { data() {
return { return {
form: { opens: false,
} form: {},
} };
}, },
created() { created() {
this.getUserInfo() this.getUserInfo();
}, },
methods: { methods: {
getUserInfo() { getUserInfo() {
getInfo().then(res => { getInfo().then((res) => {
this.form = res.data this.form = res.data;
if (this.form.firstFlag == '0') { if (this.form.firstFlag == "0") {
this.$router.push("/resetpwd").catch(() => { this.$router.push("/resetpwd").catch(() => {});
}
debugger;
if (
this.form.pwdRemainderDate >= 0 &&
this.form.pwdRemainderDate != null
) {
this.opens = true;
}
if (
this.form.pwdRemainderDate < 0 &&
this.form.pwdRemainderDate != null
) {
this.$message({
type: "error",
message: "登陆密码到期,请修改密码!",
}); });
this.$router.push("/resetpwd").catch(() => {});
} }
}) });
} },
} handlefile() {
} this.$router.push("/resetpwd").catch(() => {});
},
},
};
</script> </script>
<style lang="scss"> <style lang="scss">
.personal-info { .personal-info {
@ -104,14 +145,13 @@ export default {
.el-icon-success { .el-icon-success {
margin-right: 6px; margin-right: 6px;
color: #6CBD7F; color: #6cbd7f;
} }
.change-pwd-link { .change-pwd-link {
// font-weight: 600; // font-weight: 600;
margin-left: 15px; margin-left: 15px;
color: #3165DB; color: #3165db;
} }
} }
</style> </style>

@ -10,7 +10,7 @@
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.6-SNAPSHOT</version> <version>0.2.8-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>

@ -23,10 +23,13 @@ import org.springframework.web.bind.annotation.RestController;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jiuyv.sptcc.agile.batch.batchTask.entity.vo.TblBatchTaskVO; import com.jiuyv.sptcc.agile.batch.batchTask.entity.vo.TblBatchTaskVO;
import com.jiuyv.sptcc.agile.batch.common.BaseTime; import com.jiuyv.sptcc.agile.batch.common.BaseTime;
import com.jiuyv.sptcc.agile.batch.common.Constants;
import com.jiuyv.sptcc.agile.batch.common.R; import com.jiuyv.sptcc.agile.batch.common.R;
import com.jiuyv.sptcc.agile.batch.common.constant.TblPublicFilesEnum; import com.jiuyv.sptcc.agile.batch.common.constant.TblPublicFilesEnum;
import com.jiuyv.sptcc.agile.batch.common.util.Sm4Util;
import com.jiuyv.sptcc.agile.batch.common.util.sftp.SFTPChannel; import com.jiuyv.sptcc.agile.batch.common.util.sftp.SFTPChannel;
import com.jiuyv.sptcc.agile.batch.common.util.sftp.model.SFTPConfig; import com.jiuyv.sptcc.agile.batch.common.util.sftp.model.SFTPConfig;
import com.jiuyv.sptcc.agile.batch.entity.TblDockerClientInfo;
import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles; import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles;
import com.jiuyv.sptcc.agile.batch.framework.SftpConfigProperties; import com.jiuyv.sptcc.agile.batch.framework.SftpConfigProperties;
import com.jiuyv.sptcc.agile.batch.service.ISftpTempFileClearService; import com.jiuyv.sptcc.agile.batch.service.ISftpTempFileClearService;
@ -171,43 +174,60 @@ public class SftpTempFileClearController {
public R<String> clearDockerLogFile() throws Exception{ public R<String> clearDockerLogFile() throws Exception{
BaseTime timeVO = sftpTempFileClearService.getSysDate(); BaseTime timeVO = sftpTempFileClearService.getSysDate();
//查询实验室服务器清单,遍历
List<TblDockerClientInfo> clientlist = sftpTempFileClearService.getDockerClientList();
boolean flag=true; boolean flag=true;
//连接文件服务器清理批处理
SFTPChannel channelx = new SFTPChannel(); //因为实验室总数量就几个,直接扫描实验室总目录下的文件
try { if(!dockerDataPath.endsWith("/")) {
//创建容器前先创建目录挂载目录(后续要使用sftp操作) dockerDataPath+="/";
channelx.setConnect(createSftpCfg(), 60000); }
String lscommand= String.format(DOCKER_SHELL_STAT_GREP, dockerDataPath,dockerDataPath);
//因为实验室总数量就几个,直接扫描实验室总目录下的文件
if(!dockerDataPath.endsWith("/")) { for(TblDockerClientInfo clientlistx:clientlist) {
dockerDataPath+="/";
} //连接文件服务器清理批处理
String lscommand= String.format(DOCKER_SHELL_STAT_GREP, dockerDataPath,dockerDataPath); SFTPChannel channelx = new SFTPChannel();
List<String> list =channelx.commitCurrShellCmd(lscommand); try {
if(!list.isEmpty()) { SFTPConfig cfg = new SFTPConfig();
for(String x:list) { cfg.setUsername(clientlistx.getDockerServerUsername());
if(StringUtils.isBlank(x)) { try {
continue; cfg.setPassword(Sm4Util.decryptEcb(Constants.SM4_SECERT_KEY, clientlistx.getDockerServerPassword()));
} }catch (Exception e) {
String[] arrs= x.split(" +"); // 兼容写法,不加密也可以
if(arrs[1].length()==10) {//没有毫秒,补全 cfg.setPassword(clientlistx.getDockerServerPassword());
arrs[1]=arrs[1]+"000";
}
// 获取文件的修改时间
Date modifiedDate = new Date(Long.valueOf(arrs[1]));
long d= timeVO.getDate().getTime()-modifiedDate.getTime();
Duration duration = Duration.of(d, ChronoUnit.MILLIS);
if(duration.toDays()>=clearLogFileDays) {
channelx.commitCurrShellCmd(String.format(SHELL_RM, arrs[0])
+" && "+ String.format(SHELL_RM, arrs[0].replace(".pid", "")));
}
} }
cfg.setPort(Integer.valueOf(clientlistx.getDockerServerPort()));
cfg.setHost(clientlistx.getDockerServerIp());
//创建容器前先创建目录挂载目录(后续要使用sftp操作)
channelx.setConnect(cfg, 60000);
List<String> list =channelx.commitCurrShellCmd(lscommand);
if(!list.isEmpty()) {
for(String x:list) {
if(StringUtils.isBlank(x)) {
continue;
}
String[] arrs= x.split(" +");
if(arrs[1].length()==10) {//没有毫秒,补全
arrs[1]=arrs[1]+"000";
}
// 获取文件的修改时间
Date modifiedDate = new Date(Long.valueOf(arrs[1]));
long d= timeVO.getDate().getTime()-modifiedDate.getTime();
Duration duration = Duration.of(d, ChronoUnit.MILLIS);
if(duration.toDays()>=clearLogFileDays) {
channelx.commitCurrShellCmd(String.format(SHELL_RM, arrs[0])
+" && "+ String.format(SHELL_RM, arrs[0].replace(".pid", "")));
}
}
}
} catch (Exception e) {
LOGGER.info("initDocker error>>" ,e);
flag=false;
}finally {
channelx.closeChannel();
} }
} catch (Exception e) {
LOGGER.info("initDocker error>>" ,e);
flag=false;
}finally {
channelx.closeChannel();
} }
if(!flag) { if(!flag) {

@ -3,6 +3,7 @@ package com.jiuyv.sptcc.agile.batch.service;
import java.util.List; import java.util.List;
import com.jiuyv.sptcc.agile.batch.common.BaseTime; import com.jiuyv.sptcc.agile.batch.common.BaseTime;
import com.jiuyv.sptcc.agile.batch.entity.TblDockerClientInfo;
import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles; import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles;
@ -24,5 +25,7 @@ public interface ISftpTempFileClearService {
/** 更新文件状态*/ /** 更新文件状态*/
public void doUpdateDataStatus(List<Long> filedIds) throws Exception; public void doUpdateDataStatus(List<Long> filedIds) throws Exception;
/** 查询实验室服务器*/
public List<TblDockerClientInfo> getDockerClientList() throws Exception;
} }

@ -12,7 +12,9 @@ import org.springframework.stereotype.Service;
import com.jiuyv.sptcc.agile.batch.common.BaseTime; import com.jiuyv.sptcc.agile.batch.common.BaseTime;
import com.jiuyv.sptcc.agile.batch.common.constant.TblPublicFilesEnum; import com.jiuyv.sptcc.agile.batch.common.constant.TblPublicFilesEnum;
import com.jiuyv.sptcc.agile.batch.dao.ISysTimeBaseMapper; import com.jiuyv.sptcc.agile.batch.dao.ISysTimeBaseMapper;
import com.jiuyv.sptcc.agile.batch.dao.TblDockerClientInfoMapper;
import com.jiuyv.sptcc.agile.batch.dao.TblPublicFilesMapper; import com.jiuyv.sptcc.agile.batch.dao.TblPublicFilesMapper;
import com.jiuyv.sptcc.agile.batch.entity.TblDockerClientInfo;
import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles; import com.jiuyv.sptcc.agile.batch.entity.TblPublicFiles;
import com.jiuyv.sptcc.agile.batch.entity.vo.TblPublicFilesVO; import com.jiuyv.sptcc.agile.batch.entity.vo.TblPublicFilesVO;
@ -28,6 +30,8 @@ public class SftpTempFileClearImpl implements ISftpTempFileClearService {
private TblPublicFilesMapper tblPublicFilesMapper; private TblPublicFilesMapper tblPublicFilesMapper;
@Autowired @Autowired
private ISysTimeBaseMapper sysTimeBaseMapper; private ISysTimeBaseMapper sysTimeBaseMapper;
@Autowired
private TblDockerClientInfoMapper tblDockerClientInfoMapper;
@Override @Override
public List<TblPublicFiles> getTempFileList(String dateStr,List<String> excludeFileSourceTypes) throws Exception { public List<TblPublicFiles> getTempFileList(String dateStr,List<String> excludeFileSourceTypes) throws Exception {
@ -72,5 +76,11 @@ public class SftpTempFileClearImpl implements ISftpTempFileClearService {
public BaseTime getSysDate() throws Exception { public BaseTime getSysDate() throws Exception {
return sysTimeBaseMapper.selectSysCurrentTime(); return sysTimeBaseMapper.selectSysCurrentTime();
} }
@Override
public List<TblDockerClientInfo> getDockerClientList() throws Exception {
TblDockerClientInfo param = new TblDockerClientInfo();
param.setDataStatus(TblPublicFilesEnum.DATA_STATUS.NORMAL.getCode());
return tblDockerClientInfoMapper.selectItemList(param);
}
} }

@ -43,7 +43,14 @@ console:
remoteApiService: http://172.16.12.107:18090 remoteApiService: http://172.16.12.107:18090
#测试模式,默认关闭false;开启测试为true,会跳过一些逻辑 #测试模式,默认关闭false;开启测试为true,会跳过一些逻辑
testFlag: false testFlag: false
#密码过期天数
passwordExpireDays: 9999
#密码过期提醒天数
passwordExpireReminderDays: 7
#登陆错误/密码修改错误次数
passwordErrorNum: 3
#登陆错误/密码修改错误锁定时间(分)
loginErrorLockTime: 30
spring: spring:
application: application:
@ -102,6 +109,9 @@ filesftp:
maxIdle: 3 maxIdle: 3
minIdle: 1 minIdle: 1
maxWait: PT3M maxWait: PT3M
minEvictableIdleTime: PT15M
timeBetweenEvictionRuns: PT1M
softMinEvictableIdleTime: PT10M
sftpUserFile: sftpUserFile:
# host: 172.16.12.104 # host: 172.16.12.104
# port: 22 # port: 22
@ -133,6 +143,8 @@ operationtoken:
tokenTimes: 100 tokenTimes: 100
skipUrls: skipUrls:
- '/getInfo' - '/getInfo'
- '/sftp/file/addUpload'
- '/files/upload/**'
# 日志配置 # 日志配置
logging: logging:

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

@ -21,8 +21,8 @@ public class IpUtils {
// 未知地址 // 未知地址
public static final String UNKNOWN = "XX XX"; public static final String UNKNOWN = "XX XX";
private static final Logger LOGGER = LoggerFactory.getLogger(IpUtils.class); private static final Logger LOGGER = LoggerFactory.getLogger(IpUtils.class);
private static final RestTemplate restTemplate = new RestTemplate(); private static RestTemplate restTemplate = new RestTemplate();
private static final ObjectMapper objectMapper = new ObjectMapper(); private static ObjectMapper objectMapper = new ObjectMapper();
public static String getRealAddressByIP(String ip, boolean isAddressEnabled) { public static String getRealAddressByIP(String ip, boolean isAddressEnabled) {
// 内网不查询 // 内网不查询

@ -127,6 +127,11 @@ public class PortalUserDTO implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
/** /**
* Get用户id * Get用户id
*/ */
@ -456,4 +461,12 @@ public class PortalUserDTO implements Serializable {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
} }

@ -12,7 +12,6 @@ import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import static com.jiuyv.sptccc.agile.common.utils.IpUtils.UNKNOWN; import static com.jiuyv.sptccc.agile.common.utils.IpUtils.UNKNOWN;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -40,17 +39,13 @@ class IpUtilsTest {
@BeforeEach @BeforeEach
void setUp() throws ReflectiveOperationException { void setUp() throws ReflectiveOperationException {
Field modifier = Field.class.getDeclaredField("modifiers");
modifier.setAccessible(true);
Field restTemplateField = IpUtils.class.getDeclaredField("restTemplate"); Field restTemplateField = IpUtils.class.getDeclaredField("restTemplate");
restTemplateField.setAccessible(true); restTemplateField.setAccessible(true);
modifier.setInt(restTemplateField, restTemplateField.getModifiers() & ~Modifier.FINAL);
restTemplateField.set(null, restTemplate); restTemplateField.set(null, restTemplate);
Field objectMapperField = IpUtils.class.getDeclaredField("objectMapper"); Field objectMapperField = IpUtils.class.getDeclaredField("objectMapper");
objectMapperField.setAccessible(true); objectMapperField.setAccessible(true);
modifier.setInt(objectMapperField, objectMapperField.getModifiers() & ~Modifier.FINAL);
objectMapperField.set(null, objectMapper); objectMapperField.set(null, objectMapper);
} }

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-gateway</artifactId> <artifactId>agile-portal-gateway</artifactId>

@ -147,7 +147,7 @@ public class SysLoginService {
captcha = StringUtil.randomNumber(6); captcha = StringUtil.randomNumber(6);
localCache.setValueOfCacheName(CacheNames.CACHE_1MIN, phone, captcha); localCache.setValueOfCacheName(CacheNames.CACHE_1MIN, phone, captcha);
localCache.setValueOfCacheName(CacheNames.CACHE_5MIN, phone, captcha); localCache.setValueOfCacheName(CacheNames.CACHE_5MIN, phone, captcha);
LOGGER.info("手机{}验证码:{}", phone, captcha); LOGGER.info("手机{}验证码:{}", StringUtil.strHide(phone), captcha);
if (consoleProperties.isCaptchaTest()) { if (consoleProperties.isCaptchaTest()) {
return captcha; return captcha;
@ -302,7 +302,11 @@ public class SysLoginService {
if (!passwordEncoder.matches(oldPassword, user.getPassword())) { if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
throw new ServiceException("原密码错误"); throw new ServiceException("原密码错误");
} }
String encodePassword = passwordEncoder.encode(secretService.decodePassword(userPasswordDTO.getPassword())); String password = secretService.decodePassword(userPasswordDTO.getPassword());
if (password.equals(oldPassword)) {
throw new ServiceException("新密码不能与原密码相同");
}
String encodePassword = passwordEncoder.encode(password);
userPasswordDTO.setPassword(encodePassword); userPasswordDTO.setPassword(encodePassword);
userPasswordDTO.setUserId(user.getUserId()); userPasswordDTO.setUserId(user.getUserId());
R<Void> r = userService.resetUserPwd(userPasswordDTO); R<Void> r = userService.resetUserPwd(userPasswordDTO);

@ -59,7 +59,8 @@ public class UserDetailsServiceImpl implements UserDetailsService {
// 第一次登录,只有基本权限,修改密码后获取所有权限 // 第一次登录,只有基本权限,修改密码后获取所有权限
List<GrantedAuthority> authorities = new ArrayList<>(); List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_BASE)); authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_BASE));
if (userDTO.getFirstFlag() != null) { Integer pwdUpdateTime = userDTO.getPwdRemainderDate();
if (userDTO.getFirstFlag() != null && (pwdUpdateTime == null || pwdUpdateTime >= 0)) {
authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_ALL)); authorities.add(new SimpleGrantedAuthority(FrontConstant.AUTHORITY_ALL));
} }
return new LoginUser(user.getUserId(), user.getDeptId(), user, authorities); return new LoginUser(user.getUserId(), user.getDeptId(), user, authorities);

@ -175,6 +175,10 @@ public class TblPortalUser implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
/** /**
* 请求参数 * 请求参数
@ -623,6 +627,14 @@ public class TblPortalUser implements Serializable {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
public Map<String, Object> getParams() { public Map<String, Object> getParams() {
if (params == null) { if (params == null) {
params = new HashMap<>(); params = new HashMap<>();

@ -91,6 +91,11 @@ public class UserInfoDTO implements Serializable {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码过期剩余天数
*/
private Integer pwdRemainderDate;
public Long getUserId() { public Long getUserId() {
return userId; return userId;
} }
@ -226,4 +231,12 @@ public class UserInfoDTO implements Serializable {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Integer getPwdRemainderDate() {
return pwdRemainderDate;
}
public void setPwdRemainderDate(Integer pwdRemainderDate) {
this.pwdRemainderDate = pwdRemainderDate;
}
} }

@ -283,6 +283,10 @@ class SysLoginServiceTest {
@Test @Test
void changePassword() { void changePassword() {
ResUserPasswordDTO userPasswordDTO = mock(ResUserPasswordDTO.class); ResUserPasswordDTO userPasswordDTO = mock(ResUserPasswordDTO.class);
when(userPasswordDTO.getPassword()).thenReturn("a");
when(userPasswordDTO.getOldPassword()).thenReturn("a");
when(secretService.decodePassword("a")).thenReturn("A");
when(secretService.decodePassword("b")).thenReturn("B");
LoginUser loginUser = mock(LoginUser.class); LoginUser loginUser = mock(LoginUser.class);
securityUtilsMockedStatic.when(SecurityUtils::getLoginUser).thenReturn(loginUser); securityUtilsMockedStatic.when(SecurityUtils::getLoginUser).thenReturn(loginUser);
TblPortalUser portalUser = mock(TblPortalUser.class); TblPortalUser portalUser = mock(TblPortalUser.class);
@ -304,6 +308,14 @@ class SysLoginServiceTest {
assertTrue(e instanceof ServiceException); assertTrue(e instanceof ServiceException);
} }
when(userPasswordDTO.getOldPassword()).thenReturn("b");
try {
sysLoginService.changePassword(userPasswordDTO);
fail();
} catch (Exception e) {
assertTrue(e instanceof ServiceException);
}
when(userService.resetUserPwd(userPasswordDTO)).thenReturn(R.ok()); when(userService.resetUserPwd(userPasswordDTO)).thenReturn(R.ok());
servletUtilsMockedStatic.when(ServletUtils::getSession).thenReturn(mock(HttpSession.class)); servletUtilsMockedStatic.when(ServletUtils::getSession).thenReturn(mock(HttpSession.class));
try { try {

@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

@ -30,4 +30,4 @@ eureka:
register-with-eureka: true register-with-eureka: true
fetch-registry: true fetch-registry: true
service-url: service-url:
defaultZone: http://172.16.12.107:8761/eureka/ defaultZone: http://172.16.12.104:8761/eureka/

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-service</artifactId> <artifactId>agile-portal-service</artifactId>

@ -43,6 +43,16 @@ public class ConsoleProperties {
*/ */
private long downloadMaxFile = 100L; private long downloadMaxFile = 100L;
/**
* 密码过期时间,默认1年
*/
private int passwordExpirationDates = 60;
/**
* 密码快过期时间提醒,默认提前7天
*/
private int passwordExpirationWarnDates = 15;
public boolean isAddressEnabled() { public boolean isAddressEnabled() {
return addressEnabled; return addressEnabled;
@ -91,4 +101,20 @@ public class ConsoleProperties {
public void setDownloadMaxFile(long downloadMaxFile) { public void setDownloadMaxFile(long downloadMaxFile) {
this.downloadMaxFile = downloadMaxFile; this.downloadMaxFile = downloadMaxFile;
} }
public int getPasswordExpirationDates() {
return passwordExpirationDates;
}
public void setPasswordExpirationDates(int passwordExpirationDates) {
this.passwordExpirationDates = passwordExpirationDates;
}
public int getPasswordExpirationWarnDates() {
return passwordExpirationWarnDates;
}
public void setPasswordExpirationWarnDates(int passwordExpirationWarnDates) {
this.passwordExpirationWarnDates = passwordExpirationWarnDates;
}
} }

@ -7,13 +7,15 @@ import com.jiuyv.sptccc.agile.common.core.domain.R;
import com.jiuyv.sptccc.agile.common.enums.BusinessType; import com.jiuyv.sptccc.agile.common.enums.BusinessType;
import com.jiuyv.sptccc.agile.dto.PortalUserDTO; import com.jiuyv.sptccc.agile.dto.PortalUserDTO;
import com.jiuyv.sptccc.agile.dto.ResUserPasswordDTO; import com.jiuyv.sptccc.agile.dto.ResUserPasswordDTO;
import com.jiuyv.sptccc.agile.framework.config.ConsoleProperties;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalUser;
import com.jiuyv.sptccc.agile.portal.service.IPortalUserService;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalUser; import java.util.Date;
import com.jiuyv.sptccc.agile.portal.service.IPortalUserService;
import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX; import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX;
@ -28,9 +30,11 @@ import static com.jiuyv.sptccc.agile.api.PortalUserFeignApi.API_PATH_PREFIX;
public class PortalUserController implements PortalUserFeignApi { public class PortalUserController implements PortalUserFeignApi {
private final IPortalUserService userService; private final IPortalUserService userService;
private final ConsoleProperties consoleProperties;
public PortalUserController(IPortalUserService userService) { public PortalUserController(IPortalUserService userService, ConsoleProperties consoleProperties) {
this.userService = userService; this.userService = userService;
this.consoleProperties = consoleProperties;
} }
/** /**
@ -49,6 +53,13 @@ public class PortalUserController implements PortalUserFeignApi {
String[] split = avatar.split("/"); String[] split = avatar.split("/");
userDTO.setAvatar("content/images/" + split[split.length - 1]); userDTO.setAvatar("content/images/" + split[split.length - 1]);
} }
// 计算密码过期时间
Date pwdUpdateTime = user.getPwdUpdateTime();
long diff = consoleProperties.getPasswordExpirationDates()
- (System.currentTimeMillis() - pwdUpdateTime.getTime()) / 1000 / 60 / 60 / 24;
if (diff <= consoleProperties.getPasswordExpirationWarnDates()) {
userDTO.setPwdRemainderDate((int) diff);
}
return R.ok(userDTO); return R.ok(userDTO);
} }

@ -173,6 +173,11 @@ public class TblPortalUser extends BaseEntity {
*/ */
private String firstFlag; private String firstFlag;
/**
* 密码更新时间
*/
private Date pwdUpdateTime;
/** /**
* Get用户id * Get用户id
@ -615,4 +620,12 @@ public class TblPortalUser extends BaseEntity {
public void setFirstFlag(String firstFlag) { public void setFirstFlag(String firstFlag) {
this.firstFlag = firstFlag; this.firstFlag = firstFlag;
} }
public Date getPwdUpdateTime() {
return pwdUpdateTime;
}
public void setPwdUpdateTime(Date pwdUpdateTime) {
this.pwdUpdateTime = pwdUpdateTime;
}
} }

@ -20,4 +20,4 @@ eureka:
register-with-eureka: true register-with-eureka: true
fetchRegistry: true fetchRegistry: true
service-url: service-url:
defaultZone: http://172.16.12.107:8761/eureka/ defaultZone: http://172.16.12.104:8761/eureka/

@ -34,6 +34,7 @@
<result property="loginErrorCount" column="login_error_count"/> <result property="loginErrorCount" column="login_error_count"/>
<result property="lastLoginErrorTime" column="last_login_error_time"/> <result property="lastLoginErrorTime" column="last_login_error_time"/>
<result property="firstFlag" column="first_flag"/> <result property="firstFlag" column="first_flag"/>
<result property="pwdUpdateTime" column="pwd_update_time"/>
</resultMap> </resultMap>
<sql id="selectUserVo"> <sql id="selectUserVo">
@ -63,7 +64,8 @@
u.social_credit_code, u.social_credit_code,
u.enterprise_industry, u.enterprise_industry,
u.enterprise_address, u.enterprise_address,
u.first_flag u.first_flag,
u.pwd_update_time
from tbl_portal_user u from tbl_portal_user u
</sql> </sql>
@ -118,7 +120,9 @@
update tbl_portal_user update tbl_portal_user
set version_num = version_num + 1, set version_num = version_num + 1,
password= #{password}, password= #{password},
first_flag='1' first_flag='1',
update_time = now(),
pwd_update_time = now()
where user_id = #{userId} where user_id = #{userId}
</update> </update>
</mapper> </mapper>

@ -2,6 +2,7 @@ package com.jiuyv.sptccc.agile.portal.service.impl;
import com.github.pagehelper.Page; import com.github.pagehelper.Page;
import com.jiuyv.sptccc.agile.common.exception.ServiceException; import com.jiuyv.sptccc.agile.common.exception.ServiceException;
import com.jiuyv.sptccc.agile.framework.config.ConsoleProperties;
import com.jiuyv.sptccc.agile.portal.domain.TblPortalContent; import com.jiuyv.sptccc.agile.portal.domain.TblPortalContent;
import com.jiuyv.sptccc.agile.portal.mapper.PortalContentMapper; import com.jiuyv.sptccc.agile.portal.mapper.PortalContentMapper;
import com.jiuyv.sptccc.agile.portal.service.IFileService; import com.jiuyv.sptccc.agile.portal.service.IFileService;
@ -35,6 +36,9 @@ class PortalContentServiceImplTest {
@Mock @Mock
private IFileService fileService; private IFileService fileService;
@Mock
private ConsoleProperties consoleProperties;
@Test @Test
void getContentList() { void getContentList() {
String showType = "1"; String showType = "1";

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-portal-ui</artifactId> <artifactId>agile-portal-ui</artifactId>

@ -1,7 +1,16 @@
<template> <template>
<div class="find-password container"> <div class="find-password container">
<h3 class="title">修改密码<span v-if="firstFlag == '0'" <h3 class="title">
style="text-align: center;padding: 10px;color: red;">(初次登陆需修改初始密码)</span> 修改密码<span
v-if="firstFlag == '0'"
style="text-align: center; padding: 10px; color: red"
>(初次登陆需修改初始密码)</span
>
<span
v-if="pwdRemainderDate <= 15 && pwdRemainderDate != null"
style="text-align: center; padding: 10px; color: red"
>(密码失效修改密码)</span
>
</h3> </h3>
<el-card class="procees-contaner"> <el-card class="procees-contaner">
@ -10,163 +19,228 @@
<el-step title="完成" description=""></el-step> <el-step title="完成" description=""></el-step>
</el-steps> </el-steps>
<!-- step2 --> <!-- step2 -->
<el-form v-if="processActive == 1" ref="form" :rules="rules" :model="form" label-width="100px"> <el-form
v-if="processActive == 1"
ref="form"
:rules="rules"
:model="form"
label-width="100px"
>
<el-form-item label="原密码" prop="oldPassword"> <el-form-item label="原密码" prop="oldPassword">
<el-input v-model="form.oldPassword" type="password"></el-input> <el-input v-model="form.oldPassword" type="password"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="新密码" prop="password"> <el-form-item label="新密码" prop="password">
<el-input v-model="form.password" :type="flagType" auto-complete="off" placeholder="" @input="strengthColor"> <el-input
<i style="cursor: pointer;" slot="suffix" class="el-input__icon el-icon-view" @click="getFlageye()"></i> v-model="form.password"
:type="flagType"
auto-complete="off"
placeholder=""
@input="strengthColor"
>
<i
style="cursor: pointer"
slot="suffix"
class="el-input__icon el-icon-view"
@click="getFlageye()"
></i>
</el-input> </el-input>
<div class="divClass"> <div class="divClass">
<span <span
:class="passwords == '1' ? 'weak' : '' || passwords == '2' ? 'medium' : '' || passwords == '3' ? 'strong' : ''"></span> :class="
<span :class="passwords == '2' ? 'medium' : '' || passwords == '3' ? 'strong' : ''"></span> passwords == '1'
? 'weak'
: '' || passwords == '2'
? 'medium'
: '' || passwords == '3'
? 'strong'
: ''
"
></span>
<span
:class="
passwords == '2'
? 'medium'
: '' || passwords == '3'
? 'strong'
: ''
"
></span>
<span :class="passwords == '3' ? 'strong' : ''"></span> <span :class="passwords == '3' ? 'strong' : ''"></span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="确认密码" prop="passwords"> <el-form-item label="确认密码" prop="passwords">
<el-input v-model="form.passwords" type="password"></el-input> <el-input v-model="form.passwords" type="password"></el-input>
</el-form-item> </el-form-item>
<el-form-item label=""> <el-button type="primary" @click="handleAuthon"> <el-form-item label="">
提交</el-button></el-form-item> <el-button type="primary" @click="handleAuthon">
提交</el-button
></el-form-item
>
</el-form> </el-form>
<!-- step3 --> <!-- step3 -->
<el-form v-if="processActive == 2" ref="form" :model="form" label-width="0px"> <el-form
v-if="processActive == 2"
ref="form"
:model="form"
label-width="0px"
>
<el-form-item label=""> <el-form-item label="">
<div class="success-tips" style="color: #1ae51ad1;font-size: 24px;font-weight: 600;text-align: center;"><i <div
class="icon el-icon-success"></i> 修改成功</div> class="success-tips"
<div class="go-back" style="text-align: center;"><span style="color: red;font-size: 18px;font-weight: bold;">{{ style="
remainingTime }}</span>秒后 <span>自动返回登录页</span></div> color: #1ae51ad1;
<div class="btn-back" style="text-align: center;"><el-button type="primary" @click="logout">重新登录</el-button> font-size: 24px;
font-weight: 600;
text-align: center;
"
>
<i class="icon el-icon-success"></i> 修改成功
</div>
<div class="go-back" style="text-align: center">
<span style="color: red; font-size: 18px; font-weight: bold">{{
remainingTime
}}</span
>秒后 <span>自动返回登录页</span>
</div>
<div class="btn-back" style="text-align: center">
<el-button type="primary" @click="logout">重新登录</el-button>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
import { changePassword } from "@/api/user"; import { changePassword } from "@/api/user";
import { getKeyiv } from "@/api/login"; import { getKeyiv } from "@/api/login";
import { encrypt } from '@/utils/jsencrypt' import { encrypt } from "@/utils/jsencrypt";
export default { export default {
name: "ResetPwd", name: "ResetPwd",
data() { data() {
return { return {
isShowMenu: false, isShowMenu: false,
passwords: '1', passwords: "1",
flagType: 'password', flagType: "password",
processActive: 1, processActive: 1,
form: { form: {
oldPassword: '', oldPassword: "",
password: '', password: "",
passwords: '', passwords: "",
}, },
firstFlag: '', firstFlag: "",
pwdRemainderDate: "",
remainingTime: 5, remainingTime: 5,
keyiv: '', keyiv: "",
countDown: 10, countDown: 10,
// 表单校验 // 表单校验
rules: { rules: {
oldPassword: [ oldPassword: [
{ required: true, message: "原密码不能为空", trigger: "blur" } { required: true, message: "原密码不能为空", trigger: "blur" },
], ],
password: [ password: [
{ required: true, message: "密码不能为空", trigger: "blur" }, { required: true, message: "密码不能为空", trigger: "blur" },
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: "密码须包含数字、大小写字母且长度在8-16之间",
trigger: 'blur' trigger: "blur",
}, },
], ],
passwords: [ passwords: [
{ required: true, message: "密码不能为空", trigger: "blur" }, { required: true, message: "密码不能为空", trigger: "blur" },
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: "密码须包含数字、大小写字母且长度在8-16之间",
trigger: 'blur' trigger: "blur",
}, },
], ],
} },
} };
}, },
created() { created() {
const storedData = localStorage.getItem('myData'); const storedData = localStorage.getItem("myData");
if (storedData) { if (storedData) {
const data = JSON.parse(storedData); const data = JSON.parse(storedData);
this.firstFlag = data.firstFlag this.firstFlag = data.firstFlag;
this.pwdRemainderDate = data.pwdRemainderDate;
} }
this.getKeyiv(); this.getKeyiv();
}, },
methods: { methods: {
getFlageye() { getFlageye() {
this.flagType = this.flagType == 'password' ? 'text' : 'password';//text为显示密码;password为隐藏密码 this.flagType = this.flagType == "password" ? "text" : "password"; //text为显示密码;password为隐藏密码
}, },
strengthColor() { strengthColor() {
if (this.form.password.length <= 6) { if (this.form.password.length <= 6) {
this.passwords = '1'// 红色 this.passwords = "1"; // 红色
} else if (this.form.password.length <= 10) { } else if (this.form.password.length <= 10) {
this.passwords = '2'// 橙色 this.passwords = "2"; // 橙色
} else { } else {
this.passwords = '3' // 绿色 this.passwords = "3"; // 绿色
} }
}, },
getKeyiv() { getKeyiv() {
getKeyiv().then((response) => { getKeyiv().then((response) => {
this.keyiv = response.data this.keyiv = response.data;
}) });
}, },
logout() { logout() {
this.$store.dispatch('LogOut').then(() => { this.$store.dispatch("LogOut").then(() => {
this.$router.push("/login") this.$router.push("/login");
}) });
}, },
//提交 //提交
handleAuthon() { handleAuthon() {
if (this.form.password != this.form.passwords) { if (this.form.password != this.form.passwords) {
this.$message({ this.$message({
type: 'warning', type: "warning",
message: '新密码与确认密码不一致!' message: "新密码与确认密码不一致!",
}); });
return return;
} }
this.$refs["form"].validate(valid => { this.$refs["form"].validate((valid) => {
if (valid) { if (valid) {
this.form.passwords = '' this.form.passwords = "";
this.form.oldPassword = encrypt(this.keyiv, this.form.oldPassword + ',' + new Date().getTime()) this.form.oldPassword = encrypt(
this.form.password = encrypt(this.keyiv, this.form.password + ',' + new Date().getTime()) this.keyiv,
changePassword(this.form).then(res => { this.form.oldPassword + "," + new Date().getTime()
this.processActive++ );
this.countdownInterval = setInterval(() => { this.form.password = encrypt(
// 倒计时结束后执行的操作 this.keyiv,
console.log('倒计时结束'); this.form.password + "," + new Date().getTime()
if (this.remainingTime > 0) { );
this.remainingTime--; // 每秒递减1秒 changePassword(this.form).then((res) => {
} else { debugger;
clearInterval(this.countdownInterval); // 如果倒计时结束,清除计时器 if (res.code == 200) {
} this.processActive++;
this.$store.dispatch('LogOut').then(() => { this.countdownInterval = setInterval(() => {
this.$router.push("/login") // 倒计时结束后执行的操作
}) console.log("倒计时结束");
if (this.remainingTime > 0) {
}, 1000); this.remainingTime--; // 每秒递减1秒
}) } else {
clearInterval(this.countdownInterval); // 如果倒计时结束,清除计时器
}
this.$store.dispatch("LogOut").then(() => {
this.$router.push("/login");
});
}, 1000);
} else {
this.form.oldPassword = "";
this.form.password = "";
this.strengthColor();
}
});
} }
}) });
},
}
}, },
beforeDestroy() { beforeDestroy() {
clearTimeout(this.countdownInterval); // 在组件销毁之前清除倒计时 clearTimeout(this.countdownInterval); // 在组件销毁之前清除倒计时
}, },
} };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -214,21 +288,18 @@ export default {
} }
.weak { .weak {
background-color: #F56C6C; background-color: #f56c6c;
/* 红色 */ /* 红色 */
} }
.medium { .medium {
background-color: #E6A23C; background-color: #e6a23c;
/* 橙色 */ /* 橙色 */
} }
.strong { .strong {
background-color: #67C23A; background-color: #67c23a;
/* 绿色 */ /* 绿色 */
} }
} }
</style> </style>

@ -14,8 +14,8 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="状态"> <el-form-item label="状态">
<span v-if="form.status == '0'" style="color: #6CBD7F;">正常</span> <span v-if="form.status == '0'" style="color: #6cbd7f">正常</span>
<span v-else style="color: red;">停用</span> <span v-else style="color: red">停用</span>
</el-form-item> </el-form-item>
</el-col> </el-col>
<!-- <el-col :span="24"> <!-- <el-col :span="24">
@ -45,41 +45,82 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="登录密码"> <el-form-item label="登录密码">
<i class="icon el-icon-success"></i><span>已设置</span><router-link to="/resetpwd" <i class="icon el-icon-success"></i><span>已设置</span
class="change-pwd-link">更改密码</router-link> ><router-link to="/resetpwd" class="change-pwd-link"
>更改密码</router-link
>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<el-dialog
width="400px"
title="密码到期提示"
:visible.sync="opens"
append-to-body
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<div style="text-align: center; font-size: 18px">
登录密码还有<span
style="color: red; font-size: 25px; font-weight: bold"
>{{ form.pwdRemainderDate }}</span
>天到期,请尽快修改密码!
</div>
<div slot="footer" class="dialog-footer" style="text-align: right">
<el-button @click="opens = false">关闭</el-button>
<el-button type="primary" @click="handlefile">去修改</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { getInfo } from '@/api/login' import { getInfo } from "@/api/login";
export default { export default {
name: "UserInfo", name: "UserInfo",
data() { data() {
return { return {
form: { opens: false,
} form: {},
} };
}, },
created() { created() {
this.getUserInfo() this.getUserInfo();
}, },
methods: { methods: {
getUserInfo() { getUserInfo() {
getInfo().then(res => { getInfo().then((res) => {
this.form = res.data this.form = res.data;
if (this.form.firstFlag == '0') { if (this.form.firstFlag == "0") {
this.$router.push("/resetpwd").catch(() => { this.$router.push("/resetpwd").catch(() => {});
}
debugger;
if (
this.form.pwdRemainderDate >= 0 &&
this.form.pwdRemainderDate != null
) {
this.opens = true;
}
if (
this.form.pwdRemainderDate < 0 &&
this.form.pwdRemainderDate != null
) {
this.$message({
type: "error",
message: "登陆密码到期,请修改密码!",
}); });
this.$router.push("/resetpwd").catch(() => {});
} }
}) });
} },
} handlefile() {
} this.$router.push("/resetpwd").catch(() => {});
},
},
};
</script> </script>
<style lang="scss"> <style lang="scss">
.personal-info { .personal-info {
@ -104,14 +145,13 @@ export default {
.el-icon-success { .el-icon-success {
margin-right: 6px; margin-right: 6px;
color: #6CBD7F; color: #6cbd7f;
} }
.change-pwd-link { .change-pwd-link {
// font-weight: 600; // font-weight: 600;
margin-left: 15px; margin-left: 15px;
color: #3165DB; color: #3165db;
} }
} }
</style> </style>

@ -10,7 +10,7 @@
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-portal</artifactId> <artifactId>agile-portal</artifactId>
<version>0.2.8-SNAPSHOT</version> <version>0.2.9-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<properties> <properties>

@ -1,14 +1,14 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>agile-common</artifactId> <artifactId>agile-common</artifactId>
<version>1.0.14-SNAPSHOT</version> <version>1.2.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<description /> <description />
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-system</artifactId> <artifactId>agile-system</artifactId>
<version>1.0.14-SNAPSHOT</version> <version>1.2.2-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>

@ -5,12 +5,12 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-system</artifactId> <artifactId>agile-system</artifactId>
<version>1.0.14-SNAPSHOT</version> <version>1.2.2-SNAPSHOT</version>
</parent> </parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-system-console-ui</artifactId> <artifactId>agile-system-console-ui</artifactId>
<version>1.0.14-SNAPSHOT</version> <version>1.2.2-SNAPSHOT</version>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<frontend-maven-plugin.version>1.12.1</frontend-maven-plugin.version> <frontend-maven-plugin.version>1.12.1</frontend-maven-plugin.version>

@ -64,3 +64,17 @@ export function getCodeImg() {
closeLoading : true closeLoading : true
}) })
} }
// 登录前重置密码
export function loginResetPwd(data) {
return request({
url: '/loginResetPwd',
headers: {
isToken: false
},
method: 'post',
data: data,
closeLoading : true
})
}

@ -16,7 +16,7 @@ import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false }) NProgress.configure({ showSpinner: false })
const whiteList = ['/login'] const whiteList = ['/login','/loginResetPwd','/loginResetPassword']
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {

@ -66,6 +66,16 @@ export const constantRoutes = [
component: () => import('@/views/error/401'), component: () => import('@/views/error/401'),
hidden: true hidden: true
}, },
{
path: '/loginResetPwd',
component: () => import('@/views/loginResetPwd'),
hidden: true
},
{
path: '/loginResetPassword',
component: () => import('@/views/loginResetPassword'),
hidden: true
},
// { // {
// path: '', // path: '',
// component: Layout, // component: Layout,

@ -1,6 +1,9 @@
import { login, logout, getInfo } from '@/api/login' import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth' import { getToken, setToken, removeToken,setLoginPasswordExpiringReminder,
setLoginPasswordExpiringReminderFinished,getLoginPasswordExpiringReminder,getLoginPasswordExpiringReminderFinished
} from '@/utils/auth'
import { encrypt, decrypt } from '@/utils/jsencrypt' import { encrypt, decrypt } from '@/utils/jsencrypt'
import { MessageBox} from 'element-ui'
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
@ -47,6 +50,11 @@ const user = {
const uuid = userInfo.uuid const uuid = userInfo.uuid
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => { login(username, password, code, uuid).then(res => {
if(res === 'password_expired'){
reject('password_expired');
return;
}
setLoginPasswordExpiringReminder();//每次登陆校验密码是否快过期,只要不清理缓存,每次都会提醒
setToken('res.token') setToken('res.token')
commit('SET_TOKEN', 'res.token') commit('SET_TOKEN', 'res.token')
resolve() resolve()
@ -62,6 +70,22 @@ const user = {
getInfo().then(res => { getInfo().then(res => {
const user = res.user const user = res.user
const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.png") : process.env.VUE_APP_BASE_API + user.avatar; const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.png") : process.env.VUE_APP_BASE_API + user.avatar;
//只要没有缓存标志,每次登陆都会都提醒
if(res.passwordExpiringReminder && getLoginPasswordExpiringReminder()!=null && getLoginPasswordExpiringReminderFinished()==null){
setLoginPasswordExpiringReminderFinished();//设置已提醒
MessageBox.confirm('您的密码将于'+res.passwordExpiredDate+'过期,请及时修改密码', '系统提示', {
confirmButtonText: '立即修改',
cancelButtonText: '稍后修改',
type: 'warning'
}
).then(() => {
location.href = '/#/user/profile';
}).catch(() => {
});
}
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles) commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions) commit('SET_PERMISSIONS', res.permissions)

@ -4,21 +4,38 @@ import cache from '@/plugins/cache'
const TokenKey = 'Admin-Token' const TokenKey = 'Admin-Token'
const passwordExpiringReminder = 'passwordExpiringReminder'
const passwordExpiringReminderFinished = 'passwordExpiringReminderFinished'
//其实这个token没用,只是保留了原来的写法 //其实这个token没用,只是保留了原来的写法
export function getToken() { export function getToken() {
//return Cookies.get(TokenKey) return Cookies.get(TokenKey)
return cache.local.get(TokenKey); //return cache.local.get(TokenKey);
} }
export function setToken(token) { export function setToken(token) {
//return Cookies.set(TokenKey, token) return Cookies.set(TokenKey, token)
cache.local.set(TokenKey,token); //cache.local.set(TokenKey,token);
return token; //return token;
} }
export function removeToken() { export function removeToken() {
//return Cookies.remove(TokenKey); return Cookies.remove(TokenKey);
cache.local.remove(TokenKey); //cache.local.remove(TokenKey);
return TokenKey; //return TokenKey;
}
export function setLoginPasswordExpiringReminder() {
cache.local.set(passwordExpiringReminder,"1");
}
export function setLoginPasswordExpiringReminderFinished() {
cache.local.remove(passwordExpiringReminder);
cache.local.set(passwordExpiringReminderFinished,"1");
}
export function getLoginPasswordExpiringReminder() {
return cache.local.get(passwordExpiringReminder);
} }
export function getLoginPasswordExpiringReminderFinished() {
return cache.local.get(passwordExpiringReminderFinished);
}

@ -153,7 +153,20 @@ service.interceptors.response.use(res => {
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') { if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data return res.data
} }
if (code === '401') { if (code === 'password_expired') {
MessageBox.confirm('密码已过期,请修改密码', '系统提示', {
confirmButtonText: '立即修改',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
location.href = '/#/loginResetPassword';
}).catch(() => {
});
return code;
}
else if (code === '401') {
if (!isRelogin.show) { if (!isRelogin.show) {
isRelogin.show = true; isRelogin.show = true;
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {

@ -234,3 +234,14 @@ export async function blobValidate(data) {
return true; return true;
} }
} }
// 生成一个唯一ID,处理过程临时使用,应该不会重复
export function generateUniqueID() {
// 获取当前时间戳
const timestamp = new Date().getTime();
// 生成一个随机10位整数
const randomNum = Math.floor(Math.random() * 10000000000);
// 组合时间戳和随机数来创建唯一ID
const uniqueID = timestamp.toString() + randomNum.toString();
return uniqueID;
}

@ -37,7 +37,9 @@
<span v-else>登 录 中...</span> <span v-else>登 录 中...</span>
</el-button> </el-button>
<div style="float: right;" v-if="register"> <div style="float: right;" v-if="register">
<router-link class="link-type" :to="'/register'">立即注册</router-link> <!-- <router-link class="link-type" :to="'/register'">立即注册</router-link> -->
<!-- <router-link class="link-type" :to="'/loginResetPwd'"> 修改密码 </router-link> -->
<router-link class="link-type" :to="'/loginResetPassword'"> 修改密码 </router-link>
</div> </div>
</el-form-item> </el-form-item>
</div> </div>
@ -82,7 +84,7 @@ export default {
// 验证码开关 // 验证码开关
captchaOnOff: true, captchaOnOff: true,
// 注册开关 // 注册开关
register: false, register: true,
redirect: undefined redirect: undefined
}; };
}, },
@ -148,8 +150,11 @@ export default {
}); });
// this.$router.push({ path: this.redirect || "/" }).catch(() => { // this.$router.push({ path: this.redirect || "/" }).catch(() => {
// }); // });
}).catch(() => { }).catch((err) => {
this.loading = false; this.loading = false;
if(err === 'password_expired'){
return;
}
if (this.captchaOnOff) { if (this.captchaOnOff) {
this.getCode(); this.getCode();
} }
@ -204,7 +209,7 @@ export default {
.divform { .divform {
width: 400px; width: 400px;
padding: 70px 40px 50px; padding: 70px 40px 10px;
border-radius: 6px; border-radius: 6px;
background: #ffffff; background: #ffffff;
margin: auto; margin: auto;

@ -328,20 +328,20 @@ export default {
// 表单校验 // 表单校验
rules: { rules: {
userName: [ userName: [
{required: true, message: "账户名不能为空", trigger: "blur"}, {required: true, message: "用户名不能为空", trigger: "blur"},
{min: 2, max: 20, message: '账户名长度必须介于 2 和 20 之间', trigger: 'blur'} {min: 2, max: 20, message: '用户名长度必须介于 2 和 20 之间', trigger: 'blur'}
], ],
nickName: [ nickName: [
{required: true, message: "用户姓名不能为空", trigger: "blur"} {required: true, message: "姓名不能为空", trigger: "blur"}
], ],
enterpriseIndustry: [ enterpriseIndustry: [
{required: true, message: "企业行业不能为空", trigger: "blur"} {required: true, message: "企业行业不能为空", trigger: "blur"}
], ],
password: [ password: [
{required: true, message: "账户密码不能为空", trigger: "blur"}, {required: true, message: "密码不能为空", trigger: "blur"},
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: '须含大小写字母、数字,长度8-16',
trigger: 'blur' trigger: 'blur'
}, },
], ],

@ -1,7 +1,7 @@
<template> <template>
<div class="register"> <div class="register">
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form"> <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
<h3 class="title">若依后台管理系统</h3> <h3 class="title">用户注册</h3>
<el-form-item prop="username"> <el-form-item prop="username">
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号"> <el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />

@ -344,17 +344,17 @@ export default {
rules: { rules: {
deptId: [{required: true, message: "归属部门不能为空", trigger: "blur"}], deptId: [{required: true, message: "归属部门不能为空", trigger: "blur"}],
userName: [ userName: [
{required: true, message: "用户账号不能为空", trigger: "blur"}, {required: true, message: "用户名不能为空", trigger: "blur"},
{min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur'} {min: 2, max: 20, message: '用户名长度必须介于 2 和 20 之间', trigger: 'blur'}
], ],
nickName: [ nickName: [
{required: true, message: "用户姓名不能为空", trigger: "blur"} {required: true, message: "姓名不能为空", trigger: "blur"}
], ],
password: [ password: [
{required: true, message: "账户密码不能为空", trigger: "blur"}, {required: true, message: "密码不能为空", trigger: "blur"},
{ {
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/, pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/,
message: '密码须包含数字、大小写字母且长度在8-16之间', message: '须含大小写字母、数字,长度8-16',
trigger: 'blur' trigger: 'blur'
}, },
], ],

@ -30,12 +30,9 @@ import { encrypt, decrypt } from '@/utils/jsencrypt'
export default { export default {
data() { data() {
const equalToPassword = (rule, value, callback) => { const equalToPassword = (rule, value, callback) => {
const reg = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,16}$/
if (this.user.newPassword !== value) { if (this.user.newPassword !== value) {
callback(new Error("两次输入的密码不一致")); callback(new Error("两次输入的密码不一致"));
} else if (reg.test(value) === false) { }else {
callback(new Error('密码须包含数字、大小写字母且长度在8-16之间'))
} else {
callback(); callback();
} }
}; };
@ -55,7 +52,9 @@ export default {
], ],
confirmPassword: [ confirmPassword: [
{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, message: "确认密码不能为空", trigger: "blur" },
{ required: true, validator: equalToPassword, trigger: "blur" } { required: true, validator: equalToPassword, trigger: "blur" },
{ pattern: /[^\u4e00-\u9fa5\s]+/, message: '不允许有中文或空格', trigger: 'blur' },
{ pattern: /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[!@#$%^&*()_+])[A-Za-z\d!@#$%^&*()_+]{8,20}$/, message: '需包含大、小写字母+数字+特殊字符,长度8-20', trigger: 'blur' },
] ]
} }
}; };

@ -3,7 +3,7 @@
<parent> <parent>
<groupId>com.jiuyv.sptcc.agile</groupId> <groupId>com.jiuyv.sptcc.agile</groupId>
<artifactId>agile-system</artifactId> <artifactId>agile-system</artifactId>
<version>1.0.14-SNAPSHOT</version> <version>1.2.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>agile-system-console</artifactId> <artifactId>agile-system-console</artifactId>

@ -41,6 +41,17 @@ public class ConsoleConfig {
/** 测试类标志,为了屏蔽一些远程结果 */ /** 测试类标志,为了屏蔽一些远程结果 */
private static boolean testFlag=false; private static boolean testFlag=false;
//密码过期时间,登陆前修改密码
private static int passwordExpireDays=90;
//密码快期天数提醒
private static int passwordExpireReminderDays=7;
//密码过期后,修改错误次数
private static int passwordErrorNum=3;
//登陆错误/密码修改错误锁定时间(分)
private static int loginErrorLockTime=30;
public String getName() { public String getName() {
return name; return name;
} }
@ -183,5 +194,72 @@ public class ConsoleConfig {
public static void setTestFlag2(boolean testFlag) { public static void setTestFlag2(boolean testFlag) {
ConsoleConfig.testFlag = testFlag; ConsoleConfig.testFlag = testFlag;
} }
/**
* @return the passwordExpireDays
*/
public static int getPasswordExpireDays() {
return passwordExpireDays;
}
/**
* @param passwordExpireDays the passwordExpireDays to set
*/
public static void setPasswordExpireDays(int passwordExpireDays) {
setPasswordExpireDays2(passwordExpireDays);
}
public static void setPasswordExpireDays2(int passwordExpireDays) {
ConsoleConfig.passwordExpireDays = passwordExpireDays;
}
/**
* @return the passwordErrorNum
*/
public static int getPasswordErrorNum() {
return passwordErrorNum;
}
/**
* @param passwordErrorNum the passwordErrorNum to set
*/
public static void setPasswordErrorNum(int passwordErrorNum) {
setPasswordErrorNum2(passwordErrorNum);
}
public static void setPasswordErrorNum2(int passwordErrorNum) {
ConsoleConfig.passwordErrorNum = passwordErrorNum;
}
/**
* @return the loginErrorLockTime
*/
public static int getLoginErrorLockTime() {
return loginErrorLockTime;
}
/**
* @param loginErrorLockTime the loginErrorLockTime to set
*/
public static void setLoginErrorLockTime(int loginErrorLockTime) {
setLoginErrorLockTime2(loginErrorLockTime);
}
public static void setLoginErrorLockTime2(int loginErrorLockTime) {
ConsoleConfig.loginErrorLockTime = loginErrorLockTime;
}
/**
* @return the passwordExpireReminderDays
*/
public static int getPasswordExpireReminderDays() {
return passwordExpireReminderDays;
}
/**
* @param passwordExpireReminderDays the passwordExpireReminderDays to set
*/
public static void setPasswordExpireReminderDays(int passwordExpireReminderDays) {
setPasswordExpireReminderDays2(passwordExpireReminderDays);
}
public static void setPasswordExpireReminderDays2(int passwordExpireReminderDays) {
ConsoleConfig.passwordExpireReminderDays = passwordExpireReminderDays;
}
} }

@ -92,6 +92,15 @@ public class SFTPChannel {
} }
LOG.debug("Channel connection close!"); LOG.debug("Channel connection close!");
} }
/**
* 关闭连接
*/
public void closeInnerChannel() {
if (channel != null) {
channel.disconnect();
}
}
/** /**
* 提交单条命令,执行并解析结果 * 提交单条命令,执行并解析结果
* 每次使用独立exec,(不用shell,处理结束麻烦) * 每次使用独立exec,(不用shell,处理结束麻烦)

@ -1,19 +1,22 @@
package com.jiuyv.sptccc.agile.common.utils.sftp; package com.jiuyv.sptccc.agile.common.utils.sftp;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URLDecoder;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.util.StreamUtils; import org.springframework.util.StreamUtils;
import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session; import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpATTRS;
import com.jiuyv.sptccc.agile.common.exception.UtilException; import com.jiuyv.sptccc.agile.common.exception.UtilException;
@ -23,8 +26,6 @@ import com.jiuyv.sptccc.agile.common.utils.sftp.model.SftpProgress;
import com.jiuyv.sptccc.agile.common.utils.sftp.monitor.SftpComplexProgressMonitor; import com.jiuyv.sptccc.agile.common.utils.sftp.monitor.SftpComplexProgressMonitor;
import com.jiuyv.sptccc.agile.common.utils.sftp.monitor.SftpSimpleProgressMonitor; import com.jiuyv.sptccc.agile.common.utils.sftp.monitor.SftpSimpleProgressMonitor;
import org.apache.commons.lang3.StringUtils;
/** /**
* sftp工具类 * sftp工具类
* 都是单例连接操作后就会关闭,要多个操作的自己构建SFTPChannel * 都是单例连接操作后就会关闭,要多个操作的自己构建SFTPChannel
@ -39,7 +40,7 @@ public class SftpFileUtils
private static final Logger LOG = LoggerFactory.getLogger(SftpFileUtils.class); private static final Logger LOG = LoggerFactory.getLogger(SftpFileUtils.class);
//sftp等待时间,单位毫秒 //sftp等待时间,单位毫秒
private static final int TIMEOUT = 30000; private static final int TIMEOUT = 120000;
//是文件路径 //是文件路径
private static final Pattern FILE_SUFFIX = Pattern.compile("\\.[A-Z0-9]+$",Pattern.CASE_INSENSITIVE); private static final Pattern FILE_SUFFIX = Pattern.compile("\\.[A-Z0-9]+$",Pattern.CASE_INSENSITIVE);
@ -206,6 +207,7 @@ public class SftpFileUtils
throw new UtilException("uploadComplexMonitor sftp error"); throw new UtilException("uploadComplexMonitor sftp error");
}finally { }finally {
// channel.closeChannel(); // channel.closeChannel();
channel.closeInnerChannel();
hostPool.returnSession(session);//不再关闭,直接返还连接 hostPool.returnSession(session);//不再关闭,直接返还连接
} }
} }
@ -241,12 +243,16 @@ public class SftpFileUtils
return; return;
} }
long start=progress.getTransferedSize(); long start=progress.getTransferedSize();
//response.setHeader(HttpHeaders.LAST_MODIFIED, "");//基于文件修改时间的字符串 response.setHeader(HttpHeaders.LAST_MODIFIED, attrs.getSize()+"");//基于文件修改时间的字符串
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/octet-stream"); response.setHeader(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+ServletUtils.urlEncode(progress.getFileName())); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+ServletUtils.urlEncode(progress.getFileName()));
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes"); response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
response.setHeader(HttpHeaders.CONTENT_LENGTH, (attrs.getSize() - start)+""); response.setHeader(HttpHeaders.CONTENT_LENGTH, (attrs.getSize() - start)+"");
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + (start>0?start+1:start) + "-" + (attrs.getSize() - 1) + "/" +attrs.getSize()); if(start==0) {
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes 0-" + (attrs.getSize() - 1) + "/" +attrs.getSize());
}else {
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + start + "-" + (attrs.getSize()-1) + "/" +attrs.getSize());
}
}catch(Exception e){ }catch(Exception e){
//返回 //返回
LOG.info("downloadComplexMonitor sftp error :file not exist"); LOG.info("downloadComplexMonitor sftp error :file not exist");
@ -265,6 +271,93 @@ public class SftpFileUtils
} }
} }
public static void downloadComplexMonitorEach(SFTPConfig sftpDetails,String src, HttpServletResponse response
,SftpProgress progress,ISftpProressService progressService) throws Exception {
if(!isFile(src)) {
throw new UtilException("Not a file path");
}
SFTPChannel channel = new SFTPChannel();
try {
ChannelSftp chSftp = channel.getChannel(sftpDetails, TIMEOUT);
String oldMtime=progress.getFactLastTime();
try {
//自动判断是否存在文件
SftpATTRS attrs = chSftp.stat(src);
progress.setFactLastTime(attrs.getMTime()+"");//最后修改时间
progress.setFileSize(attrs.getSize());//文件总大小
//如果传入了oldMtime,有变更则不会进行下载
if(progress.getFileChangeFlag(oldMtime)) {
chSftp.quit();
return;
}
long start=progress.getTransferedSize();
response.setHeader(HttpHeaders.LAST_MODIFIED, attrs.getSize()+"");//基于文件修改时间的字符串
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+ServletUtils.urlEncode(progress.getFileName()));
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
response.setHeader(HttpHeaders.CONTENT_LENGTH, (attrs.getSize() - start)+"");
if(start==0) {
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes 0-" + (attrs.getSize() - 1) + "/" +attrs.getSize());
}else {
response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes " + start + "-" + (attrs.getSize()-1) + "/" +attrs.getSize());
}
}catch(Exception e){
//返回
LOG.info("downloadComplexMonitor sftp error :file not exist");
progress.setFactLastTime("-1");//文件不存在,方便判断
chSftp.quit();
return;
}
ServletOutputStream outputStream = response.getOutputStream();
handleSftpInputStream(sftpDetails, channel, chSftp, src, outputStream, progress, progressService, 1, progress.getTransferedSize());
outputStream.flush();
chSftp.quit();
}catch(Exception e) {
LOG.error("downloadComplexMonitor sftp error :{}",e.getMessage(),e);
throw new UtilException("downloadComplexMonitor sftp error");
}finally {
channel.closeChannel();
}
}
private static void handleSftpInputStream(SFTPConfig sftpDetails,SFTPChannel channel ,ChannelSftp chSftp,String src,
ServletOutputStream outputStream,SftpProgress progress,ISftpProressService progressService,int num,long totalSize) throws IOException {
if(num>4) {
channel.closeInnerChannel();
return;
}
num++;//加一次
long nowTotalSize=0L;
InputStream in = null;
try {
in = chSftp.get(src,new SftpComplexProgressMonitor(progress,progressService) ,totalSize);
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
nowTotalSize = nowTotalSize + bytesRead;
outputStream.write(buffer,0,bytesRead);
outputStream.flush();
}
chSftp.quit();
} catch (Exception e) {
LOG.info("downloadComplexMonitor sftp again connect");
totalSize = totalSize + nowTotalSize;
channel.closeChannel();
try {
channel = new SFTPChannel();
chSftp = channel.getChannel(sftpDetails, TIMEOUT);
} catch (JSchException e1) {
LOG.info("downloadComplexMonitor sftp reconnect error>> num = {}",num);
}
handleSftpInputStream(sftpDetails,channel, chSftp, src, outputStream, progress, progressService, num, totalSize);
}finally {
if(in!=null) {
in.close();
}
}
}
/** /**
* 删除文件 * 删除文件

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save