增加操作员管理功能
diff --git a/backend/build.gradle b/backend/build.gradle
index 631933b..684619c 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -74,7 +74,7 @@
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.9.1'
compile group: 'log4j', name: 'log4j', version: '1.2.17'
- compile group: 'com.supwisdom', name: 'payapi-sdk', version: '1.0.26-5-gf114ee1'
+ compile group: 'com.supwisdom', name: 'payapi-sdk', version: '1.0.28-1-g7415df3'
implementation 'org.hamcrest:hamcrest:2.1'
}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperatorDao.java b/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperatorDao.java
index 28cc18e..ed4e68a 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperatorDao.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperatorDao.java
@@ -1,12 +1,13 @@
package com.supwisdom.dlpay.framework.dao;
import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.portal.dao.OperatorRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
-public interface OperatorDao extends JpaRepository<TOperator, String>, JpaSpecificationExecutor<TOperator> {
+public interface OperatorDao extends JpaRepository<TOperator, String>, JpaSpecificationExecutor<TOperator>, OperatorRepository {
TOperator findByOpercode(String opercode);
TOperator findByOperid(String operid);
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperator.java b/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperator.java
index be38fed..ba7e07e 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperator.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperator.java
@@ -75,6 +75,9 @@
private String jti;
@Transient
+ private String rolename;
+
+ @Transient
private Collection<? extends GrantedAuthority> authorities; //权限
public TOperator() {
@@ -200,6 +203,14 @@
this.authorities = authorities;
}
+ public String getRolename() {
+ return rolename;
+ }
+
+ public void setRolename(String rolename) {
+ this.rolename = rolename;
+ }
+
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java b/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
index 4c31b55..eebda6d 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/service/OperatorDetailService.java
@@ -1,8 +1,12 @@
package com.supwisdom.dlpay.framework.service;
import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.jpa.page.Pagination;
+import com.supwisdom.dlpay.portal.bean.OperatorSearchBean;
import com.supwisdom.dlpay.portal.domain.TBResource;
+import com.supwisdom.dlpay.portal.domain.TBRole;
import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -11,5 +15,22 @@
TOperator saveOper(TOperator operator);
+ TOperator saveOrUpdateOper(TOperator operator);
+
+ Boolean checkExistOper(String opercode, String operid);
+
+ void resetPassword(String operid);
+
+ String switchStatus(String operid, String status);
+
List<TBResource> getResByRoleId(String roleId);
+
+ @Transactional(readOnly = true)
+ List<TBRole> getAllRoles();
+
+ @Transactional(readOnly = true)
+ Pagination getOperatorList(OperatorSearchBean bean);
+
+ @Transactional(readOnly = true)
+ TBRole findRoleById(String roleId);
}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java b/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
index d2e1153..6df8991 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/service/impl/OperatorDetailServiceImpl.java
@@ -2,18 +2,30 @@
import com.supwisdom.dlpay.framework.dao.OperatorDao;
import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.jpa.page.Pagination;
import com.supwisdom.dlpay.framework.service.OperatorDetailService;
+import com.supwisdom.dlpay.framework.tenant.TenantContext;
+import com.supwisdom.dlpay.framework.util.DateUtil;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.framework.util.TradeDict;
+import com.supwisdom.dlpay.mobile.exception.PortalBusinessException;
+import com.supwisdom.dlpay.portal.bean.OperatorSearchBean;
import com.supwisdom.dlpay.portal.dao.ResourceDao;
+import com.supwisdom.dlpay.portal.dao.RoleDao;
import com.supwisdom.dlpay.portal.domain.TBResource;
+import com.supwisdom.dlpay.portal.domain.TBRole;
+import com.supwisdom.dlpay.portal.util.PortalConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import java.util.Optional;
@Service
public class OperatorDetailServiceImpl implements OperatorDetailService {
@@ -21,6 +33,8 @@
private OperatorDao operatorDao;
@Autowired
private ResourceDao resourceDao;
+ @Autowired
+ private RoleDao roleDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -46,6 +60,60 @@
}
@Override
+ public Boolean checkExistOper(String opercode, String operid) {
+ TOperator oper = operatorDao.findByOpercode(opercode.trim());
+ if (null != oper && StringUtil.isEmpty(operid)) {
+ return true;
+ }
+ return null != oper && !StringUtil.isEmpty(operid) && !operid.trim().equals(oper.getOperid());
+ }
+
+ @Override
+ public void resetPassword(String operid) {
+ TOperator operator = operatorDao.findByOperid(operid);
+ if (null == operator) {
+ throw new PortalBusinessException("该管理员账号不存在");
+ }
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ operator.setOperpwd(encoder.encode(PortalConstant.OPERPWD_DEFAULT));
+ operatorDao.save(operator);
+ }
+
+ @Override
+ public String switchStatus(String operid, String status) {
+ TOperator operator = operatorDao.findByOperid(operid);
+ if (null == operator) {
+ throw new PortalBusinessException("该管理员账号不存在");
+ }
+ operator.setStatus(status);
+ operatorDao.save(operator);
+ return operator.getStatus();
+ }
+
+ @Override
+ public TOperator saveOrUpdateOper(TOperator operator) {
+ if (StringUtil.isEmpty(operator.getOperid())){
+ operator.setOpendate(DateUtil.getNow("yyyyMMdd"));
+ operator.setStatus(TradeDict.STATUS_NORMAL);
+ operator.setOpertype(PortalConstant.OPERTYPE_DEFAULT);
+ operator.setTenantId(TenantContext.getTenantSchema());
+ BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
+ operator.setOperpwd(encoder.encode(PortalConstant.OPERPWD_DEFAULT));
+ return operatorDao.save(operator);
+ }else {
+ TOperator op = operatorDao.findByOperid(operator.getOperid());
+ if (op == null) {
+ throw new PortalBusinessException("未找到待修改的管理员信息");
+ }
+ op.setOpername(operator.getOpername());
+ op.setRoleid(operator.getRoleid());
+ op.setMobile(operator.getMobile());
+ op.setEmail(operator.getEmail());
+ return operatorDao.save(op);
+ }
+ }
+
+ @Override
public List<TBResource> getResByRoleId(String roleId) {
List<TBResource> rootResource = resourceDao.findRootListByRole(roleId);
for (TBResource resource : rootResource) {
@@ -54,4 +122,19 @@
}
return rootResource;
}
+
+ @Override
+ public List<TBRole> getAllRoles() {
+ return roleDao.findAll();
+ }
+
+ @Override
+ public Pagination getOperatorList(OperatorSearchBean bean) {
+ return operatorDao.getOperatorList(bean);
+ }
+
+ @Override
+ public TBRole findRoleById(String roleId) {
+ return roleDao.findById(roleId).orElse(null);
+ }
}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/OperatorRepositoryImpl.java b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/OperatorRepositoryImpl.java
new file mode 100644
index 0000000..93ca48a
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/OperatorRepositoryImpl.java
@@ -0,0 +1,44 @@
+package com.supwisdom.dlpay.portal.dao.impl;
+
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.framework.jpa.BaseRepository;
+import com.supwisdom.dlpay.framework.jpa.Finder;
+import com.supwisdom.dlpay.framework.jpa.page.Pagination;
+import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.portal.bean.OperatorSearchBean;
+import com.supwisdom.dlpay.portal.dao.OperatorRepository;
+import org.hibernate.transform.Transformers;
+import org.jetbrains.annotations.NotNull;
+
+public class OperatorRepositoryImpl extends BaseRepository implements OperatorRepository {
+ @NotNull
+ @Override
+ public Pagination getOperatorList(@NotNull OperatorSearchBean bean) {
+ String opername = bean.getOpername();
+ String opercode = bean.getOpercode();
+ String status = bean.getStatus();
+ int pageno = bean.getPageno();
+ int pagesize = bean.getPagesize();
+ StringBuilder sql = new StringBuilder("select o.operid,o.opercode,o.opername,o.email,o.mobile,o.opendate,o.status,o.roleid,r.rolename from tb_operator o left join tb_role r on o.roleid = r.roleid where 1=1");
+ if (!StringUtil.isEmpty(opername)) {
+ sql.append(" and o.opername like :opername");
+ }
+ if (!StringUtil.isEmpty(opercode)) {
+ sql.append(" and o.opercode like :opercode");
+ }
+ if (!StringUtil.isEmpty(status)) {
+ sql.append(" and o.status=:status");
+ }
+ Finder f = Finder.create(sql.toString());
+ if (!StringUtil.isEmpty(opername)) {
+ f.setParameter("opername", "%" + opername.trim() + "%");
+ }
+ if (!StringUtil.isEmpty(opercode)) {
+ f.setParameter("opercode", "%" + opercode.trim() + "%");
+ }
+ if (!StringUtil.isEmpty(status)) {
+ f.setParameter("status", status);
+ }
+ return findNative(f, Transformers.aliasToBean(TOperator.class), pageno, pagesize);
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
index 21fc3a6..d738d2a 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
@@ -4,6 +4,9 @@
public static final String YES = "1";
public static final String NO = "0";
+ public static final String OPERPWD_DEFAULT = "123456";
+ public static final String OPERTYPE_DEFAULT = "oper";
+
public static final String SYSPARA_IMAGESERVER_URL = "imageserver.url.image";
public static final String SYSPARA_IMAGE_MAXSIZE = "imagemaxsize";
public static final String SYSPARA_IMAGE_MINISIZE = "minimagesize";
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index 22b08fc..71aed08 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -722,7 +722,15 @@
return JsonResult.error("用户不存在,请注册")
}
if (!user.userid.isNullOrEmpty()) {
- val response = userProxy.signbxy(user.userid, agree, user.phone)
+ val response = userProxy.signbxy(SignBxyParam().apply {
+ this.userid = user.userid
+ this.code = agree
+ this.phone = user.phone
+ this.uid = user.uid
+ this.rsaprivate = user.rsaprivate
+ this.rsapublic = user.rsapublic
+ this.secertkey = user.secertkey
+ })
if (response.retcode != 0) {
logger.error { "用户签约失败:${response.retmsg}" }
return JsonResult.error("签约失败,${response.retmsg}")
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt
index 7d4d4e6..7ac0a95 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt
@@ -16,6 +16,7 @@
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.security.authentication.BadCredentialsException
+import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.Authentication
import org.springframework.security.core.AuthenticationException
@@ -93,6 +94,7 @@
val errmsg = when (exception) {
is BadCredentialsException -> "账号或密码错误"
is LockedException -> "账户被锁定"
+ is DisabledException -> "账户已被注销,请联系管理员"
else -> exception.message!!
}
response.status = HttpStatus.OK.value()
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
index 23d7284..35bfe6e 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
@@ -101,12 +101,14 @@
return try {
val p = SecurityContextHolder.getContext().authentication
val oper = operatorDetailService.findByOperid(p.name)
+ val role = operatorDetailService.findRoleById(oper.roleid)
+ ?: return JsonResult.error("操作员的角色不存在")
val data = HashMap<String, String>()
val url = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_IMAGE_URLPUSH)
val mapKey = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_PORTAL_AMAPKEY)
val mapUrl = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_PORTAL_AMAPURL)
data["name"] = oper.opername
- data["roles"] = "admin"
+ data["roles"] = role.rolecode
data["url"] = url
data["mapkey"] = mapKey
data["mapurl"] = mapUrl
@@ -119,7 +121,7 @@
}
@RequestMapping("/user/updateinfo")
- fun updateUserInfo(@RequestBody bean:TOperator): JsonResult?{
+ fun updateUserInfo(@RequestBody bean: TOperator): JsonResult? {
return try {
val p = SecurityContextHolder.getContext().authentication
val oper = operatorDetailService.findByOperid(p.name)
@@ -151,6 +153,7 @@
}
}
+
@RequestMapping("/user/resource")
fun getUserResource(): JsonResult? {
return try {
@@ -555,4 +558,83 @@
JsonResult.error("切换网点是否开启异常")
}
}
+
+ /**
+ * 获取所有角色
+ */
+ @RequestMapping(value = ["/role/all"], method = [RequestMethod.GET])
+ fun getAllRoles(): JsonResult? {
+ return try {
+ val list = operatorDetailService.allRoles
+ return JsonResult.ok().put("list", list)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("查询所有角色失败")
+ }
+ }
+
+ @RequestMapping(value = ["/operator/list"], method = [RequestMethod.GET])
+ fun getOperatorList(bean: OperatorSearchBean): JsonResult? {
+ return try {
+ val page = operatorDetailService.getOperatorList(bean)
+ if (page.list == null || page.list.size == 0) {
+ return JsonResult.ok().put("msg", "无数据")
+ }
+ return JsonResult.ok().put("page", page)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("查询操作员列表失败")
+ }
+ }
+
+ @RequestMapping(value = ["/operator/save"], method = [RequestMethod.POST])
+ fun saveOutlets(@RequestBody operatorParam: TOperator): JsonResult? {
+ return try {
+ if (operatorDetailService.checkExistOper(operatorParam.opercode, operatorParam.operid)) {
+ return JsonResult.error("管理员账号重复,请更换")
+ }
+ val operator = TOperator()
+ operator.opercode = operatorParam.opercode
+ operator.opername = operatorParam.opername
+ operator.roleid = operatorParam.roleid
+ operator.mobile = operatorParam.mobile
+ operator.email = operatorParam.email
+ operator.operid = operatorParam.operid
+ operator.thirdadmin = if ("yes".equals(operatorParam.thirdadmin, ignoreCase = true)) "yes" else "no"
+ operatorDetailService.saveOrUpdateOper(operator)
+ JsonResult.ok()
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("保存管理员异常")
+ }
+ }
+
+ /**
+ * 重置管理员密码
+ */
+ @RequestMapping(value = ["/operator/resetpwd/{operid}"], method = [RequestMethod.POST])
+ fun resetPassword(@PathVariable operid:String): JsonResult? {
+ return try {
+ operatorDetailService.resetPassword(operid)
+ JsonResult.ok()
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("重置管理员密码异常")
+ }
+ }
+
+ /**
+ * 设置管理员状态
+ */
+ @RequestMapping(value = ["/operator/switchstatus/{operid}"], method = [RequestMethod.POST])
+ fun switchStatus(@PathVariable(value = "operid") operid: String,
+ @RequestParam(value = "status") status: String): JsonResult? {
+ return try {
+ val result = operatorDetailService.switchStatus(operid, status)
+ JsonResult.ok().put("result", result)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("设置管理员状态异常")
+ }
+ }
}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/OperatorSearchBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/OperatorSearchBean.kt
new file mode 100644
index 0000000..cfb75b1
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/OperatorSearchBean.kt
@@ -0,0 +1,9 @@
+package com.supwisdom.dlpay.portal.bean
+
+class OperatorSearchBean {
+ var opercode: String = ""
+ var opername: String = ""
+ var status: String = ""
+ var pageno: Int = 0
+ var pagesize: Int = 10
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/OperatorRepository.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/OperatorRepository.kt
new file mode 100644
index 0000000..78b5369
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/OperatorRepository.kt
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.portal.bean.OperatorSearchBean
+
+interface OperatorRepository {
+ fun getOperatorList(bean:OperatorSearchBean):Pagination
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt
new file mode 100644
index 0000000..c5b553d
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/RoleDao.kt
@@ -0,0 +1,9 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBRole
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface RoleDao : JpaRepository<TBRole, String>{
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
index b993822..0d67838 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -281,6 +281,8 @@
return
}
TenantContext.setTenantSchema(tenantId)
+ }else{
+ TenantContext.setTenantSchema(Constants.DEFAULT_TENANTID)
}
val auth = UsernamePasswordAuthenticationToken(claims[Constants.JWT_CLAIM_UID], null,
(claims[Constants.JWT_CLAIM_AUTHORITIES] as ArrayList<*>)
diff --git a/backend/src/main/resources/data-postgresql.sql b/backend/src/main/resources/data-postgresql.sql
index 8b708c6..9880a3d 100644
--- a/backend/src/main/resources/data-postgresql.sql
+++ b/backend/src/main/resources/data-postgresql.sql
@@ -37,6 +37,8 @@
INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('4665765bf07d455486f2a5215dd97380', '1', 5, 'f066939ecbf64da3a54fa93d56e4391b', '文章管理', '/article/list', '1', NULL);
INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('80e0326446a643069bc8d26c132d45ea', '1', 7, 'f066939ecbf64da3a54fa93d56e4391b', '咨询问答管理', '/advisory/index', '1', NULL);
INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('7e60ec8e741441fe9a2f351b5ab8c965', '1', 8, 'f066939ecbf64da3a54fa93d56e4391b', '网点管理', '/outlets/index', '1', NULL);
+INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('67291cc80fc148ceb939d98554977bc3', '1', 9, 'f066939ecbf64da3a54fa93d56e4391b', '角色管理', '/role/index', '1', NULL);
+
INSERT INTO "tb_operator"("operid", "closedate", "email", "mobile", "opendate", "opercode", "opername", "operpwd", "opertype", "sex", "status", "tenantid", "thirdadmin", "jti", "roleid") VALUES ('LOR2IwRkbOjp+sVG9KR2BpHZbwGKepS4', '20500101', NULL, NULL, '20190101', 'system', '系统管理员', '$2a$10$Ex9xp11.vCaD8D0a7ahiUOKqDij1TcCUBwRAmrqXeDvAkmzLibn4.', 'oper', NULL, 'normal', '{tenantid}', 'no', 'QwC1ln7rReYmBOhq57op6Q', '20497f2fa27a44f7841492288ab75d88');
@@ -52,6 +54,8 @@
INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('460d7f0b57eb4dcfb73fb1b51ad37f4f', '20200827142245', '99604b8d18b34417befe051a3720cbed', '20497f2fa27a44f7841492288ab75d88');
INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('49cb562956534d7dbf54b762b2b6af0d', '20200921162433', '80e0326446a643069bc8d26c132d45ea', '20497f2fa27a44f7841492288ab75d88');
INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('5f78e1eea840497c8b991323fab4541d', '20200923170348', '7e60ec8e741441fe9a2f351b5ab8c965', '20497f2fa27a44f7841492288ab75d88');
+INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('bb2f8e1a9aa74732bf1f35828ef8a87b', '20201027172455', '67291cc80fc148ceb939d98554977bc3', '20497f2fa27a44f7841492288ab75d88');
+
diff --git a/frontend/src/api/operator.js b/frontend/src/api/operator.js
new file mode 100644
index 0000000..50aae8d
--- /dev/null
+++ b/frontend/src/api/operator.js
@@ -0,0 +1,33 @@
+import request from '@/utils/request'
+
+export function saveOperator(data) {
+ return request({
+ url: '/operator/save',
+ method: 'post',
+ data
+ })
+}
+
+export function resetPassword(operid) {
+ return request({
+ url: '/operator/resetpwd/' + operid,
+ method: 'post'
+ })
+}
+
+export function getOperatorList(query) {
+ return request({
+ url: '/operator/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function switchStatus(operid, status) {
+ return request({
+ url: '/operator/switchstatus/' + operid,
+ method: 'post',
+ params: status
+ })
+}
+
diff --git a/frontend/src/api/role.js b/frontend/src/api/role.js
index 959bbd2..4d1a002 100644
--- a/frontend/src/api/role.js
+++ b/frontend/src/api/role.js
@@ -1,5 +1,12 @@
import request from '@/utils/request'
+export function getAllRoles() {
+ return request({
+ url: '/role/all',
+ method: 'get'
+ })
+}
+
export function getRoutes() {
return request({
url: '/vue-element-admin/routes',
diff --git a/frontend/src/store/modules/permission.js b/frontend/src/store/modules/permission.js
index a35f884..1782f6a 100644
--- a/frontend/src/store/modules/permission.js
+++ b/frontend/src/store/modules/permission.js
@@ -97,13 +97,12 @@
const data = response.resource
Object.assign(loadMenuData, data)
generaMenu(asyncRoutes, loadMenuData)
- let accessedRoutes
- if (roles.includes('admin')) {
- // alert(JSON.stringify(asyncRoutes))
- accessedRoutes = asyncRoutes || []
- } else {
- accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
- }
+ const accessedRoutes = asyncRoutes || []
+ // if (roles.includes('admin')) {
+ // accessedRoutes = asyncRoutes || []
+ // } else {
+ // accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+ // }
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
diff --git a/frontend/src/views/article/list.vue b/frontend/src/views/article/list.vue
index 21491c5..87c5858 100644
--- a/frontend/src/views/article/list.vue
+++ b/frontend/src/views/article/list.vue
@@ -20,6 +20,7 @@
end-placeholder="结束日期"
value-format="yyyyMMdd"
:picker-options="pickerOptions"
+ class="filter-item"
/>
</div>
<div class="filter-container">
@@ -35,11 +36,13 @@
end-placeholder="结束日期"
value-format="yyyyMMdd"
:picker-options="pickerOptions"
+ class="filter-item"
/>
<div class="filter-item" style="margin-right:15px">文章状态</div>
<el-select
v-model="formData.status"
style="width:200px;margin-right:120px"
+ class="filter-item"
>
<el-option
v-for="item in statusOptions"
diff --git a/frontend/src/views/feedback/index.vue b/frontend/src/views/feedback/index.vue
index 95b0835..76dd654 100644
--- a/frontend/src/views/feedback/index.vue
+++ b/frontend/src/views/feedback/index.vue
@@ -29,11 +29,13 @@
end-placeholder="结束日期"
value-format="yyyyMMdd"
:picker-options="pickerOptions"
+ class="filter-item"
/>
<div class="filter-item" style="margin-right:15px">留言状态</div>
<el-select
v-model="formData.status"
style="width:200px;margin-right:100px"
+ class="filter-item"
>
<el-option
v-for="item in statusOptions"
diff --git a/frontend/src/views/login/index.vue b/frontend/src/views/login/index.vue
index 2abcff9..2b38390 100644
--- a/frontend/src/views/login/index.vue
+++ b/frontend/src/views/login/index.vue
@@ -13,7 +13,7 @@
<el-input
ref="username"
v-model="loginForm.username"
- placeholder="Username"
+ placeholder="用户名"
name="username"
type="text"
tabindex="1"
@@ -21,7 +21,7 @@
/>
</el-form-item>
- <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
+ <el-tooltip v-model="capsTooltip" content="大写锁定已开" placement="right" manual>
<el-form-item prop="password">
<span class="svg-container">
<svg-icon icon-class="password" />
@@ -31,7 +31,7 @@
ref="password"
v-model="loginForm.password"
:type="passwordType"
- placeholder="Password"
+ placeholder="密码"
name="password"
tabindex="2"
autocomplete="on"
@@ -46,54 +46,33 @@
</el-tooltip>
<el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">登录</el-button>
-
- <div style="position:relative">
- <div class="tips">
- <span>Username : admin</span>
- <span>Password : any</span>
- </div>
- <div class="tips">
- <span style="margin-right:18px;">Username : editor</span>
- <span>Password : any</span>
- </div>
-
- <el-button class="thirdparty-button" type="primary" @click="showDialog=true">
- Or connect with
- </el-button>
- </div>
</el-form>
- <el-dialog title="Or connect with" :visible.sync="showDialog">
- Can not be simulated on local, so please combine you own business simulation! ! !
- <br>
- <br>
- <br>
- <social-sign />
- </el-dialog>
</div>
</template>
<script>
-import SocialSign from './components/SocialSignin'
export default {
name: 'Login',
- components: { SocialSign },
data() {
const validateUsername = (rule, value, callback) => {
+ if (value === '') {
+ callback(new Error('用户名不能为空'))
+ }
callback()
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
- callback(new Error('The password can not be less than 6 digits'))
+ callback(new Error('密码不能少于6位'))
} else {
callback()
}
}
return {
loginForm: {
- username: 'system',
- password: '123456'
+ username: '',
+ password: ''
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
@@ -102,7 +81,6 @@
passwordType: 'password',
capsTooltip: false,
loading: false,
- showDialog: false,
redirect: undefined,
otherQuery: {}
}
diff --git a/frontend/src/views/operator/index.vue b/frontend/src/views/operator/index.vue
index 5956c3f..64ddeb5 100644
--- a/frontend/src/views/operator/index.vue
+++ b/frontend/src/views/operator/index.vue
@@ -1,9 +1,437 @@
+/* eslint-disable vue/valid-v-model */
<template>
- <div class="app-container" /></template>
+ <div class="app-container">
+ <div class="filter-container">
+ <div class="filter-item" style="margin-right:15px">账号</div>
+ <el-input
+ v-model="formData.opercode"
+ placeholder="管理员登录名"
+ style="width: 350px;margin-right:50px"
+ class="filter-item"
+ />
+ <div class="filter-item" style="margin-right:15px">状态</div>
+ <el-select
+ v-model="formData.status"
+ style="width:200px;margin-right:100px"
+ class="filter-item"
+ >
+ <el-option
+ v-for="item in statusOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ <el-button
+ style=""
+ class="filter-item"
+ type="primary"
+ icon="el-icon-search"
+ @click="handleFilter()"
+ >
+ 搜索
+ </el-button>
+ </div>
+ <div class="filter-container">
+ <div class="filter-item" style="margin-right:15px">名称</div>
+ <el-input
+ v-model="formData.opername"
+ placeholder="管理员名称"
+ style="width: 350px;margin-right:50px"
+ class="filter-item"
+ />
+
+ </div>
+ <el-tooltip class="item" effect="dark" content="新用户密码123456" placement="top">
+ <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addOperator()">新增</el-button>
+ </el-tooltip>
+
+ <el-table
+ :key="tableKey"
+ v-loading="listLoading"
+ :data="list"
+ border
+ fit
+ highlight-current-row
+ style="width: 100%;margin-top:10px"
+ >
+ <el-table-column label="管理员账号" width="150">
+ <template slot-scope="{row}">
+ <span>{{ row.opercode }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="管理员名称" align="center">
+ <template slot-scope="{row}">
+ <span>{{ row.opername }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="状态" align="center" width="100">
+ <template slot-scope="{row}">
+ <div>
+ <span class="text_switch">
+ <el-switch
+ :value="row.status==='normal'"
+ active-text="正常"
+ inactive-text="注销"
+ active-color="#13ce66"
+ inactive-color="#A7A7A7"
+ disabled
+ @click.native.prevent="switchStatus(row)"
+ />
+ </span>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="手机号" width="120" align="center">
+ <template slot-scope="{row}">
+ <span>{{ row.mobile }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="邮箱" align="center">
+ <template slot-scope="{row}">
+ <span>{{ row.email }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="注册时间" align="center" width="100">
+ <template slot-scope="{row}">
+ <span>{{ timeFormat(row.opendate) }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="操作" align="center" width="100">
+ <template slot-scope="{row}">
+ <el-tooltip class="item" effect="dark" content="修改" placement="bottom">
+ <el-button type="primary" icon="el-icon-edit" circle size="mini" @click="updateOperator(row)" />
+ </el-tooltip>
+ <el-tooltip class="item" effect="dark" content="重置密码" placement="bottom">
+ <el-button type="warning" icon="el-icon-refresh" circle size="mini" @click="resetPassword(row)" />
+ </el-tooltip>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ :page.sync="formData.pageno"
+ :limit.sync="formData.pagesize"
+ style="margin-top:0;"
+ @pagination="getOperatorList"
+ />
+ <el-dialog
+ :title="title"
+ :visible.sync="operatorDialogVisible"
+ width="30%"
+ ><div>
+ <el-form ref="operatorForm" :model="operatorForm" :rules="rules" label-width="100px">
+ <el-form-item label="登录账号" prop="opercode" class="form-input-item">
+ <el-input
+ v-model="operatorForm.opercode"
+ maxlength="16"
+ :disabled="opercodeDisable"
+ show-word-limit
+ style="width:80%"
+ />
+ </el-form-item>
+ <el-form-item label="用户名称" prop="opername" class="form-input-item">
+ <el-input
+ v-model="operatorForm.opername"
+ maxlength="30"
+ show-word-limit
+ style="width:80%"
+ />
+ </el-form-item>
+ <el-form-item label="角色" prop="roleid" class="form-input-item">
+ <el-select
+ v-model="operatorForm.roleid"
+ style="width:80%"
+ >
+ <el-option
+ v-for="item in roles"
+ :key="item.roleid"
+ :label="item.rolename"
+ :value="item.roleid"
+ />
+ </el-select>
+ </el-form-item>
+ <el-form-item label="手机号" prop="mobile" class="form-input-item">
+ <el-input
+ v-model="operatorForm.mobile"
+ style="width:80%"
+ />
+ </el-form-item>
+ <el-form-item label="邮箱" prop="email" class="form-input-item">
+ <el-input
+ v-model="operatorForm.email"
+ style="width:80%"
+ />
+ </el-form-item>
+ </el-form>
+ </div>
+ <div style="text-align:center">
+ <el-button
+ type="primary"
+ @click="saveOperator('operatorForm')"
+ >保存
+ </el-button>
+ <el-button @click="operatorDialogVisible = false">取消</el-button>
+ </div>
+ </el-dialog>
+ </div>
+</template>
<script>
+import { getAllRoles } from '@/api/role'
+import { getOperatorList, saveOperator, resetPassword, switchStatus } from '@/api/operator'
+import moment from 'moment'
+import Pagination from '@/components/Pagination'
export default {
- name: 'Operator'
+ name: 'Operator',
+ components: {
+ Pagination
+ },
+ data() {
+ var validateMobile = (rule, value, callback) => {
+ if (value !== null && value !== '') {
+ var reg = /^1[3456789]\d{9}$/
+ if (!reg.test(value)) {
+ callback(new Error('请输入有效的手机号码'))
+ }
+ }
+ callback()
+ }
+ var validateEmail = (rule, value, callback) => {
+ if (value !== null && value !== '') {
+ var reg = /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/
+ if (!reg.test(value)) {
+ callback(new Error('请输入有效的邮箱'))
+ }
+ }
+ callback()
+ }
+ return {
+ ssss: true,
+ formData: {
+ opercode: '',
+ opername: '',
+ status: '',
+ roleid: '',
+ pageno: 1,
+ pagesize: 10
+ },
+ operatorForm: {
+ operid: '',
+ opercode: '',
+ opername: '',
+ roleid: '',
+ mobile: '',
+ email: ''
+ },
+ roles: [],
+ statusOptions: [{
+ value: '',
+ label: '所有'
+ },
+ {
+ value: 'normal',
+ label: '正常'
+ }, {
+ value: 'closed',
+ label: '注销'
+ }],
+ opercodeDisable: true,
+ listLoading: false,
+ tableKey: 0,
+ list: null,
+ total: 0,
+ title: '',
+ operatorDialogVisible: false,
+ rules: {
+ opercode: [
+ { required: true, message: '请输入用户名称', trigger: 'blur' }
+ ],
+ opername: [
+ { required: true, message: '请输入用户名称', trigger: 'blur' }
+ ],
+ roleid: [
+ { required: true, message: '请选择操作员角色', trigger: 'blur' }
+ ],
+ mobile: [
+ { validator: validateMobile, trigger: 'blur' }
+ ],
+ email: [
+ { validator: validateEmail, trigger: 'blur' }
+ ]
+ }
+ }
+ },
+ created() {
+ this.getAllRoles()
+ this.getOperatorList()
+ },
+ methods: {
+ getAllRoles() {
+ getAllRoles().then(response => {
+ this.roles = response.list
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ },
+ handleFilter() {
+ this.formData.pageno = 1
+ this.getOperatorList()
+ },
+ getOperatorList() {
+ getOperatorList(this.formData).then(response => {
+ if (response.page) {
+ this.list = response.page.list
+ this.total = response.page.totalCount
+ } else {
+ this.list = null
+ this.total = 0
+ }
+ this.listLoading = false
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ this.listLoading = false
+ })
+ },
+ addOperator() {
+ this.title = '新增管理员'
+ this.opercodeDisable = false
+ this.resetForm('operatorForm')
+ this.operatorDialogVisible = true
+ },
+ updateOperator(row) {
+ this.title = '信息修改'
+ this.opercodeDisable = true
+ this.resetForm('operatorForm')
+ this.operatorForm = Object.assign({}, row)
+ this.operatorDialogVisible = true
+ },
+ resetForm(formName) {
+ this.operatorForm = {
+ operid: '',
+ opercode: '',
+ opername: '',
+ roleid: '',
+ mobile: '',
+ email: ''
+ }
+ this.$nextTick(() => {
+ this.$refs[formName].clearValidate()
+ })
+ },
+ resetPassword(row) {
+ this.$confirm('确认重置此管理员的密码为123456吗?', '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning'
+ }).then(() => {
+ resetPassword(row.operid).then(response => {
+ this.$message({
+ type: 'success',
+ message: '重置密码成功!'
+ })
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ })
+ },
+ saveOperator(formName) {
+ this.$refs[formName].validate((valid) => {
+ if (valid) {
+ saveOperator(this.operatorForm).then(response => {
+ this.$notify({
+ title: '成功',
+ message: '保存成功!',
+ type: 'success',
+ duration: 2000
+ })
+ this.operatorDialogVisible = false
+ this.getOperatorList()
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ } else {
+ return false
+ }
+ })
+ },
+ switchStatus(row) {
+ switchStatus(row.operid, { status: row.status === 'normal' ? 'closed' : 'normal' }).then(response => {
+ this.$message({
+ type: 'success',
+ message: '操作成功!'
+ })
+ row.status = response.result
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ },
+ timeFormat(time) {
+ if (time === null) {
+ return ''
+ }
+ return moment(time, 'YYYYMMDD').format('YYYY-MM-DD')
+ }
+ }
}
</script>
+<style>
+.text_switch .el-switch__label--left {
+ position: relative;
+ left: 22px;
+ color: #fff;
+ margin-right: 0;
+ z-index: -1111;
+ }
+
+ .text_switch .el-switch__label--left span {
+ font-size: 10px;
+ }
+
+ .text_switch .el-switch__core {
+ width: 55px !important;
+ position: absolute;
+ }
+
+ .text_switch .el-switch__label--right {
+ position: relative;
+ right: 25px;
+ color: #fff;
+ z-index: -1111;
+ }
+
+ .text_switch .el-switch__label--right span {
+ font-size: 10px;
+ }
+
+ .text_switch .el-switch__label.is-active {
+ z-index: 1111;
+ color: #fff;
+ }
+
+ .text_switch .el-switch.is-disabled {
+ opacity: 1;
+ }
+
+ .text_switch .el-switch.is-disabled .el-switch__core, .el-switch.is-disabled .el-switch__label {
+ cursor: pointer;
+ }
+</style>