完成留言管理功能
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperRoleDao.java b/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperRoleDao.java
deleted file mode 100644
index fa3dd5a..0000000
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/dao/OperRoleDao.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.supwisdom.dlpay.framework.dao;
-
-import com.supwisdom.dlpay.framework.domain.TOperRole;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.Query;
-import org.springframework.stereotype.Repository;
-
-import java.util.List;
-
-@Repository
-public interface OperRoleDao extends JpaRepository<TOperRole, String> {
-
- @Query(value = "select distinct rolecode from TB_OPER_ROLE a,TB_ROLE b where a.roleid=b.roleid and a.operid=?1", nativeQuery = true)
- List<String> getRolecodeByOperid(String operid);
-
- void deleteByRoleId(String roleId);
-
- List<TOperRole> findAllByOperid(String operid);
-
- void deleteByOperid(String operid);
-}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperRole.java b/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperRole.java
deleted file mode 100644
index 54df513..0000000
--- a/backend/src/main/java/com/supwisdom/dlpay/framework/domain/TOperRole.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.supwisdom.dlpay.framework.domain;
-
-import org.hibernate.annotations.GenericGenerator;
-
-import javax.persistence.*;
-import javax.validation.constraints.NotNull;
-
-@Entity
-@Table(name = "TB_OPER_ROLE",
- indexes = {@Index(name = "operrole_operid_idx", columnList = "operid")})
-public class TOperRole {
- @Id
- @GenericGenerator(name = "idGenerator", strategy = "uuid")
- @GeneratedValue(generator = "idGenerator")
- @Column(name = "ID", nullable = false, length = 32)
- private String id;
-
- @Column(name = "ROLEID", length = 32)
- @NotNull
- private String roleId;
-
- @Column(name = "OPERID", length = 32)
- @NotNull
- private String operid;
-
- @Column(name = "tenantid", length = 20)
- @NotNull
- private String tenantId;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getRoleId() {
- return roleId;
- }
-
- public void setRoleId(String roleId) {
- this.roleId = roleId;
- }
-
- public String getOperid() {
- return operid;
- }
-
- public void setOperid(String operid) {
- this.operid = operid;
- }
-
- public String getTenantId() {
- return tenantId;
- }
-
- public void setTenantId(String tenantId) {
- this.tenantId = tenantId;
- }
-}
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 8e8f83b..be38fed 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
@@ -59,8 +59,9 @@
@Column(name = "CLOSEDATE", length = 8)
private String closedate;
- @Transient
- private String roleids;
+
+ @Column(name = "ROLEID", length = 32)
+ private String roleid;
@Column(name = "tenantid", length = 20)
@NotNull
@@ -70,6 +71,9 @@
@NotNull
private String thirdadmin;
+ @Column(name = "jti", length = 64)
+ private String jti;
+
@Transient
private Collection<? extends GrantedAuthority> authorities; //权限
@@ -81,7 +85,7 @@
this.opername = opername;
}
- public TOperator(String opercode, String opertype, String opername, String operpwd, String status, String sex, String mobile, String email, String opendate, String closedate, Collection<? extends GrantedAuthority> authorities) {
+ public TOperator(String opercode, String opertype, String opername, String operpwd, String status, String sex, String mobile, String email, String opendate, String closedate,String jti, Collection<? extends GrantedAuthority> authorities) {
this.opercode = opercode;
this.opertype = opertype;
this.opername = opername;
@@ -92,6 +96,7 @@
this.email = email;
this.opendate = opendate;
this.closedate = closedate;
+ this.jti = jti;
this.authorities = authorities;
}
@@ -183,6 +188,14 @@
this.closedate = closedate;
}
+ public String getJti() {
+ return jti;
+ }
+
+ public void setJti(String jti) {
+ this.jti = jti;
+ }
+
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
@@ -222,12 +235,12 @@
return !TradeDict.STATUS_CLOSED.equals(this.status); //注销操作员不启用
}
- public String getRoleids() {
- return roleids;
+ public String getRoleid() {
+ return roleid;
}
- public void setRoleids(String roleids) {
- this.roleids = roleids;
+ public void setRoleid(String roleid) {
+ this.roleid = roleid;
}
public String getTenantId() {
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/BaseRepository.java b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/BaseRepository.java
new file mode 100644
index 0000000..34cecc8
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/BaseRepository.java
@@ -0,0 +1,113 @@
+package com.supwisdom.dlpay.framework.jpa;
+
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination;
+import org.hibernate.query.NativeQuery;
+import org.hibernate.transform.ResultTransformer;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.*;
+
+public class BaseRepository {
+ @Autowired
+ protected EntityManager entityManager;
+
+ /**
+ * 查询全部(不分页) HQL 写法
+ *
+ * */
+ protected List find(Finder finder) {
+ Query query = entityManager.createQuery(finder.getOrigHql());
+ finder.setParamsToQuery(query);
+ return query.getResultList();
+ }
+
+ /**
+ * 分页方法 HQL 写法
+ * 直接查询Entity对象
+ *
+ * */
+ protected Pagination find(Finder finder, int pageNo, int pageSize) {
+ int totalCount = countQueryResult(finder);
+ Pagination p = new Pagination(pageNo, pageSize, totalCount);
+ if (totalCount < 1) {
+ p.setList(new ArrayList());
+ return p;
+ }
+ Query query = entityManager.createQuery(finder.getOrigHql());
+ finder.setParamsToQuery(query);
+ query.setFirstResult(p.getFirstResult());
+ query.setMaxResults(p.getPageSize());
+ List list = query.getResultList();
+ p.setList(list);
+ return p;
+ }
+ /**
+ *
+ * 分页方法 Native SQL 写法
+ * 原生SQL
+ * 使用finder.addScalar()方法,添加字段映射
+ *
+ * */
+ protected Pagination findNative(Finder finder, ResultTransformer transformer,
+ int pageNo, int pageSize) {
+ int totalCount = countNativeQueryResult(finder);
+ Pagination p = new Pagination(pageNo, pageSize, totalCount);
+ if (totalCount < 1) {
+ p.setList(new ArrayList());
+ return p;
+ }
+ Query query = entityManager.createNativeQuery(finder.getOrigHql());
+ finder.setParamsToQuery(query);
+ NativeQuery nativeQuery = query.unwrap(NativeQuery.class);
+ if(finder.columAlias!=null){
+ Set<Map.Entry<String, org.hibernate.type.Type>> entrySet = finder.columAlias.entrySet();
+ Iterator<Map.Entry<String, org.hibernate.type.Type>> iter = entrySet.iterator();
+ while (iter.hasNext())
+ {
+ Map.Entry<String, org.hibernate.type.Type> entry = iter.next();
+ nativeQuery.addScalar(entry.getKey(),entry.getValue());
+ }
+ }
+ if(transformer!=null){
+ nativeQuery.setResultTransformer(transformer);
+ }
+ query.setFirstResult(p.getFirstResult());
+ query.setMaxResults(p.getPageSize());
+ List list = nativeQuery.getResultList();
+ p.setList(list);
+ return p;
+ }
+ protected int countNativeQueryResult(Finder finder) {
+ Query query = entityManager.createNativeQuery(finder.getRowCountHql());
+ finder.setParamsToQuery(query);
+ return ((Number) query.getSingleResult()).intValue();
+ }
+
+ protected int countQueryResult(Finder finder) {
+ Query query = entityManager.createQuery(finder.getRowCountHql());
+ finder.setParamsToQuery(query);
+ return ((Number) query.getSingleResult()).intValue();
+ }
+ /**
+ * 创建本地SQL语句的方法,不带addScalor等
+ * */
+ protected NativeQuery createNativeQuery(String sql){
+ return entityManager.createNativeQuery(sql).unwrap(NativeQuery.class);
+ }
+ /**
+ * 创建本地SQL语句的方法,与createNativeQuery类似,区别是不需要转换类型
+ * */
+ protected Query createNavQuery(String sql){
+ return entityManager.createNativeQuery(sql);
+ }
+
+ /**
+ * Hql 语句
+ * */
+ protected Query createQuery(String hql){
+ return entityManager.createQuery(hql);
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/Finder.java b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/Finder.java
new file mode 100644
index 0000000..a344ce8
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/Finder.java
@@ -0,0 +1,287 @@
+package com.supwisdom.dlpay.framework.jpa;
+
+import com.google.common.collect.Maps;
+import org.hibernate.Session;
+import org.hibernate.type.Type;
+
+import javax.persistence.Query;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * HQL语句分页查询
+ */
+public class Finder {
+ protected Finder() {
+ hqlBuilder = new StringBuilder();
+ }
+ protected Map<String, Type> columAlias = Maps.newHashMap();
+ protected Finder(String hql) {
+ hqlBuilder = new StringBuilder(hql);
+ columAlias.clear();
+ }
+
+ public static Finder create() {
+ return new Finder();
+ }
+
+ public static Finder create(String hql) {
+
+ return new Finder(hql);
+ }
+ public Finder addScalar(String columnAlias, Type type){
+ columAlias.put(columnAlias,type);
+ return this;
+ }
+
+ public Finder append(String hql) {
+ hqlBuilder.append(hql);
+ return this;
+ }
+
+ /**
+ * 获得原始hql语句
+ *
+ * @return
+ */
+ public String getOrigHql() {
+ return hqlBuilder.toString();
+ }
+
+ /**
+ * 获得查询数据库记录数的hql语句。
+ *
+ * @return
+ */
+ public String getRowCountHql() {
+ String hql = hqlBuilder.toString();
+
+ int fromIndex = hql.toLowerCase().indexOf(FROM);
+ String projectionHql = hql.substring(0, fromIndex);
+
+ hql = hql.substring(fromIndex);
+ String rowCountHql = hql.replace(HQL_FETCH, "");
+
+ int groupIndex = hql.toLowerCase().indexOf(GROUP_BY);
+ int orderIndex = hql.toLowerCase().indexOf(ORDER_BY);
+ if (orderIndex > 0) {
+ rowCountHql = rowCountHql.substring(0, orderIndex);
+ }
+ if (groupIndex > 0) {
+ return wrapProjectionWithGroupBy(projectionHql) + rowCountHql +") t ";
+ } else {
+ return wrapProjection(projectionHql) + rowCountHql;
+ }
+
+ }
+
+ public int getFirstResult() {
+ return firstResult;
+ }
+
+ public void setFirstResult(int firstResult) {
+ this.firstResult = firstResult;
+ }
+
+ public int getMaxResults() {
+ return maxResults;
+ }
+
+ public void setMaxResults(int maxResults) {
+ this.maxResults = maxResults;
+ }
+
+ /**
+ * 是否使用查询缓存
+ *
+ * @return
+ */
+ public boolean isCacheable() {
+ return cacheable;
+ }
+
+ /**
+ * 设置是否使用查询缓存
+ *
+ * @param cacheable
+ */
+ public void setCacheable(boolean cacheable) {
+ this.cacheable = cacheable;
+ }
+
+ /**
+ * 设置参数
+ *
+ * @param param
+ * @param value
+ * @return
+ * @see Query#setParameter(String, Object)
+ */
+ public Finder setParameter(String param, Object value) {
+ return setParameter(param, value, null);
+ }
+
+ /**
+ * 设置参数。与hibernate的Query接口一致。
+ *
+ * @param param
+ * @param value
+ * @param type
+ * @return
+ */
+ public Finder setParameter(String param, Object value, Type type) {
+ getParams().add(param);
+ getValues().add(value);
+ getTypes().add(type);
+ return this;
+ }
+
+ /**
+ * 将finder中的参数设置到query中。
+ *
+ * @param query
+ */
+ public Query setParamsToQuery(Query query) {
+ if (params != null) {
+ for (int i = 0; i < params.size(); i++) {
+ if (types.get(i) == null) {
+ query.setParameter(params.get(i), values.get(i));
+ }
+ }
+ }
+ if (paramsList != null) {
+ for (int i = 0; i < paramsList.size(); i++) {
+ if (typesList.get(i) == null) {
+ query.setParameter(paramsList.get(i), valuesList.get(i));
+ }
+ }
+ }
+ if (paramsArray != null) {
+ for (int i = 0; i < paramsArray.size(); i++) {
+ if (typesArray.get(i) == null) {
+ query.setParameter(paramsArray.get(i),
+ valuesArray.get(i));
+ }
+ }
+ }
+ return query;
+ }
+
+ public Query createQuery(Session s) {
+ Query query = setParamsToQuery(s.createQuery(getOrigHql()));
+ if (getFirstResult() > 0) {
+ query.setFirstResult(getFirstResult());
+ }
+ if (getMaxResults() > 0) {
+ query.setMaxResults(getMaxResults());
+ }
+ return query;
+ }
+
+ private String wrapProjection(String projection) {
+ return ROW_COUNT;
+ }
+
+ private String wrapProjectionWithGroupBy(String projection) {
+ return " select count(*) from ("+projection;
+
+ }
+
+ private List<String> getParams() {
+ if (params == null) {
+ params = new ArrayList<String>();
+ }
+ return params;
+ }
+
+ private List<Object> getValues() {
+ if (values == null) {
+ values = new ArrayList<Object>();
+ }
+ return values;
+ }
+
+ private List<Type> getTypes() {
+ if (types == null) {
+ types = new ArrayList<Type>();
+ }
+ return types;
+ }
+
+ private List<String> getParamsList() {
+ if (paramsList == null) {
+ paramsList = new ArrayList<String>();
+ }
+ return paramsList;
+ }
+
+ private List<Collection<Object>> getValuesList() {
+ if (valuesList == null) {
+ valuesList = new ArrayList<Collection<Object>>();
+ }
+ return valuesList;
+ }
+
+ private List<Type> getTypesList() {
+ if (typesList == null) {
+ typesList = new ArrayList<Type>();
+ }
+ return typesList;
+ }
+
+ private List<String> getParamsArray() {
+ if (paramsArray == null) {
+ paramsArray = new ArrayList<String>();
+ }
+ return paramsArray;
+ }
+
+ private List<Object[]> getValuesArray() {
+ if (valuesArray == null) {
+ valuesArray = new ArrayList<Object[]>();
+ }
+ return valuesArray;
+ }
+
+ private List<Type> getTypesArray() {
+ if (typesArray == null) {
+ typesArray = new ArrayList<Type>();
+ }
+ return typesArray;
+ }
+
+ private StringBuilder hqlBuilder;
+
+ private List<String> params;
+ private List<Object> values;
+ private List<Type> types;
+
+ private List<String> paramsList;
+ private List<Collection<Object>> valuesList;
+ private List<Type> typesList;
+
+ private List<String> paramsArray;
+ private List<Object[]> valuesArray;
+ private List<Type> typesArray;
+
+ private int firstResult = 0;
+
+ private int maxResults = 0;
+
+ private boolean cacheable = false;
+
+ public static final String ROW_COUNT = "select count(*) ";
+ public static final String FROM = "from";
+ public static final String HQL_FETCH = "fetch";
+ public static final String ORDER_BY = "order by";
+ public static final String GROUP_BY = "group by";
+
+ public static void main(String[] args) {
+ Finder find = Finder
+ .create("select distinct p FROM BookType join fetch p");
+ System.out.println(find.getRowCountHql());
+ System.out.println(find.getOrigHql());
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Paginable.java b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Paginable.java
new file mode 100644
index 0000000..1687fde
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Paginable.java
@@ -0,0 +1,58 @@
+package com.supwisdom.dlpay.framework.jpa.page;
+
+/**
+ * 分页接口
+ */
+public interface Paginable {
+ /**
+ * 总记录数
+ *
+ * @return
+ */
+ public int getTotalCount();
+
+ /**
+ * 总页数
+ *
+ * @return
+ */
+ public int getTotalPage();
+
+ /**
+ * 每页记录数
+ *
+ * @return
+ */
+ public int getPageSize();
+
+ /**
+ * 当前页号
+ *
+ * @return
+ */
+ public int getPageNo();
+
+ /**
+ * 是否第一页
+ *
+ * @return
+ */
+ public boolean isFirstPage();
+
+ /**
+ * 是否最后一页
+ *
+ * @return
+ */
+ public boolean isLastPage();
+
+ /**
+ * 返回下页的页号
+ */
+ public int getNextPage();
+
+ /**
+ * 返回上页的页号
+ */
+ public int getPrePage();
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Pagination.java b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Pagination.java
new file mode 100644
index 0000000..38919de
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/Pagination.java
@@ -0,0 +1,85 @@
+package com.supwisdom.dlpay.framework.jpa.page;
+
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+/**
+ * 列表分页。包含list属性。
+ */
+@SuppressWarnings("serial")
+public class Pagination extends SimplePage implements java.io.Serializable,
+ Paginable {
+
+ public Pagination() {
+ }
+
+ /**
+ * 构造器
+ *
+ * @param pageNo
+ * 页码
+ * @param pageSize
+ * 每页几条数据
+ * @param totalCount
+ * 总共几条数据
+ */
+ public Pagination(int pageNo, int pageSize, int totalCount) {
+ super(pageNo, pageSize, totalCount);
+ }
+
+ /**
+ * 构造器
+ *
+ * @param pageNo
+ * 页码
+ * @param pageSize
+ * 每页几条数据
+ * @param totalCount
+ * 总共几条数据
+ * @param list
+ * 分页内容
+ */
+ public Pagination(int pageNo, int pageSize, int totalCount, List<?> list) {
+ super(pageNo, pageSize, totalCount);
+ this.list = list;
+ }
+
+ /**
+ * 第一条数据位置
+ *
+ * @return
+ */
+ public int getFirstResult() {
+ return (pageNo - 1) * pageSize;
+ }
+
+ /**
+ * 当前页的数据
+ */
+ private List<?> list;
+
+ /**
+ * 获得分页内容
+ *
+ * @return
+ */
+ public List<?> getList() {
+ return list;
+ }
+
+ /**
+ * 设置分页内容
+ *
+ * @param list
+ */
+ @SuppressWarnings("unchecked")
+ public void setList(List list) {
+ this.list = list;
+ }
+
+ public Pagination(Page page){
+ super(page.getNumber(),page.getSize(),(int)page.getTotalElements());
+ this.list = page.getContent();
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/SimplePage.java b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/SimplePage.java
new file mode 100644
index 0000000..6386838
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/framework/jpa/page/SimplePage.java
@@ -0,0 +1,171 @@
+package com.supwisdom.dlpay.framework.jpa.page;
+
+/**
+ * 简单分页类
+ */
+public class SimplePage implements Paginable {
+ private static final long serialVersionUID = 1L;
+ public static final int DEF_COUNT = 20;
+
+ /**
+ * 检查页码 checkPageNo
+ *
+ * @param pageNo
+ * @return if pageNo==null or pageNo<1 then return 1 else return pageNo
+ */
+ public static int cpn(Integer pageNo) {
+ return (pageNo == null || pageNo < 1) ? 1 : pageNo;
+ }
+
+ public SimplePage() {
+ }
+
+ /**
+ * 构造器
+ *
+ * @param pageNo
+ * 页码
+ * @param pageSize
+ * 每页几条数据
+ * @param totalCount
+ * 总共几条数据
+ */
+ public SimplePage(int pageNo, int pageSize, int totalCount) {
+ setTotalCount(totalCount);
+ setPageSize(pageSize);
+ setPageNo(pageNo);
+ adjustPageNo();
+ }
+
+ /**
+ * 调整页码,使不超过最大页数
+ */
+ public void adjustPageNo() {
+ if (pageNo == 1) {
+ return;
+ }
+ int tp = getTotalPage();
+ if (pageNo > tp) {
+ pageNo = tp;
+ }
+ }
+
+ /**
+ * 获得页码
+ */
+ @Override
+ public int getPageNo() {
+ return pageNo;
+ }
+
+ /**
+ * 每页几条数据
+ */
+ @Override
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ /**
+ * 总共几条数据
+ */
+ @Override
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ /**
+ * 总共几页
+ */
+ @Override
+ public int getTotalPage() {
+ int totalPage = totalCount / pageSize;
+ if (totalPage == 0 || totalCount % pageSize != 0) {
+ totalPage++;
+ }
+ return totalPage;
+ }
+
+ /**
+ * 是否第一页
+ */
+ @Override
+ public boolean isFirstPage() {
+ return pageNo <= 1;
+ }
+
+ /**
+ * 是否最后一页
+ */
+ @Override
+ public boolean isLastPage() {
+ return pageNo >= getTotalPage();
+ }
+
+ /**
+ * 下一页页码
+ */
+ @Override
+ public int getNextPage() {
+ if (isLastPage()) {
+ return pageNo;
+ } else {
+ return pageNo + 1;
+ }
+ }
+
+ /**
+ * 上一页页码
+ */
+ @Override
+ public int getPrePage() {
+ if (isFirstPage()) {
+ return pageNo;
+ } else {
+ return pageNo - 1;
+ }
+ }
+
+ protected int totalCount = 0;
+ protected int pageSize = 20;
+ protected int pageNo = 1;
+
+ /**
+ * if totalCount<0 then totalCount=0
+ *
+ * @param totalCount
+ */
+ public void setTotalCount(int totalCount) {
+ if (totalCount < 0) {
+ this.totalCount = 0;
+ } else {
+ this.totalCount = totalCount;
+ }
+ }
+
+ /**
+ * if pageSize< 1 then pageSize=DEF_COUNT
+ *
+ * @param pageSize
+ */
+ public void setPageSize(int pageSize) {
+ if (pageSize < 1) {
+ this.pageSize = DEF_COUNT;
+ } else {
+ this.pageSize = pageSize;
+ }
+ }
+
+ /**
+ * if pageNo < 1 then pageNo=1
+ *
+ * @param pageNo
+ */
+ public void setPageNo(int pageNo) {
+ if (pageNo < 1) {
+ this.pageNo = 1;
+ } else {
+ this.pageNo = pageNo;
+ }
+ }
+}
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 bf72bfe..4c31b55 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,6 +1,15 @@
package com.supwisdom.dlpay.framework.service;
+import com.supwisdom.dlpay.framework.domain.TOperator;
+import com.supwisdom.dlpay.portal.domain.TBResource;
import org.springframework.security.core.userdetails.UserDetailsService;
+import java.util.List;
+
public interface OperatorDetailService extends UserDetailsService {
+ TOperator findByOperid(String operid);
+
+ TOperator saveOper(TOperator operator);
+
+ List<TBResource> getResByRoleId(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 755828d..d2e1153 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
@@ -1,13 +1,12 @@
package com.supwisdom.dlpay.framework.service.impl;
-import com.supwisdom.dlpay.framework.dao.OperRoleDao;
import com.supwisdom.dlpay.framework.dao.OperatorDao;
import com.supwisdom.dlpay.framework.domain.TOperator;
import com.supwisdom.dlpay.framework.service.OperatorDetailService;
-import com.supwisdom.dlpay.framework.util.StringUtil;
+import com.supwisdom.dlpay.portal.dao.ResourceDao;
+import com.supwisdom.dlpay.portal.domain.TBResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@@ -21,7 +20,7 @@
@Autowired
private OperatorDao operatorDao;
@Autowired
- private OperRoleDao operRoleDao;
+ private ResourceDao resourceDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -32,11 +31,27 @@
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>() {
};
- List<String> roles = operRoleDao.getRolecodeByOperid(oper.getOperid());
- if (!StringUtil.isEmpty(roles)) {
- authorities = AuthorityUtils.createAuthorityList(roles.toArray(new String[0]));
- }
oper.setAuthorities(authorities);
return oper;
}
+
+ @Override
+ public TOperator findByOperid(String operid) {
+ return operatorDao.findByOperid(operid);
+ }
+
+ @Override
+ public TOperator saveOper(TOperator operator) {
+ return operatorDao.save(operator);
+ }
+
+ @Override
+ public List<TBResource> getResByRoleId(String roleId) {
+ List<TBResource> rootResource = resourceDao.findRootListByRole(roleId);
+ for (TBResource resource : rootResource) {
+ List<TBResource> children = resourceDao.findChildrenByRoleAndParent(roleId, resource.getResid());
+ resource.setChildren(children);
+ }
+ return rootResource;
+ }
}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/FeedbackRepositoryImpl.java b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/FeedbackRepositoryImpl.java
new file mode 100644
index 0000000..ef6c456
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/FeedbackRepositoryImpl.java
@@ -0,0 +1,59 @@
+package com.supwisdom.dlpay.portal.dao.impl;
+
+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.FeedbackSearchBean;
+import com.supwisdom.dlpay.portal.dao.FeedbackRepository;
+import com.supwisdom.dlpay.portal.domain.TBFeedback;
+import org.hibernate.transform.Transformers;
+import org.jetbrains.annotations.NotNull;
+
+public class FeedbackRepositoryImpl extends BaseRepository implements FeedbackRepository {
+ @NotNull
+ @Override
+ public Pagination getFeedbackList(@NotNull FeedbackSearchBean bean) {
+ StringBuilder sql = new StringBuilder("select f.*,p.name username from tb_feedback f left join tb_person p on f.userid = p.userid where 1=1 ");
+ String username = bean.getUsername();
+ String content = bean.getContent();
+ String startdate = bean.getStartdate();
+ String enddate = bean.getEnddate();
+ String replystatus = bean.getReplystatus();
+ int pageno = bean.getPageno();
+ int pagesize = bean.getPagesize();
+ if (!StringUtil.isEmpty(username)) {
+ sql.append(" and p.name like :username");
+ }
+ if (!StringUtil.isEmpty(content)) {
+ sql.append(" and f.content like :content");
+ }
+ if (!StringUtil.isEmpty(startdate)) {
+ sql.append(" and f.fbtime >= :startdate");
+ }
+ if (!StringUtil.isEmpty(enddate)) {
+ sql.append(" and f.fbtime <= :enddate");
+ }
+ if (!StringUtil.isEmpty(replystatus)) {
+ sql.append(" and f.replystatus = :replystatus");
+ }
+ sql.append(" order by f.fbtime desc");
+ Finder f = Finder.create(sql.toString());
+ if (!StringUtil.isEmpty(username)) {
+ f.setParameter("username", "%" + username.trim() + "%");
+ }
+ if (!StringUtil.isEmpty(content)) {
+ f.setParameter("content", "%" + content.trim() + "%");
+ }
+ if (!StringUtil.isEmpty(startdate)) {
+ f.setParameter("startdate", startdate + "000000");
+ }
+ if (!StringUtil.isEmpty(enddate)) {
+ f.setParameter("enddate", enddate + "235959");
+ }
+ if (!StringUtil.isEmpty(replystatus)) {
+ f.setParameter("replystatus", replystatus);
+ }
+ return findNative(f, Transformers.aliasToBean(TBFeedback.class), pageno, pagesize);
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAnnex.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAnnex.java
new file mode 100644
index 0000000..2679855
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAnnex.java
@@ -0,0 +1,53 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_annex")
+public class TBAnnex {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "annexid", nullable = false, length = 32)
+ private String annexid;
+ @Column(name = "fbid", length = 32)
+ private String fbid;
+ @Column(name = "picid", length = 32)
+ private String picid;
+ @Column(name = "minpicid", length = 14)
+ private String minpicid;
+
+ public String getAnnexid() {
+ return annexid;
+ }
+
+ public void setAnnexid(String annexid) {
+ this.annexid = annexid;
+ }
+
+ public String getFbid() {
+ return fbid;
+ }
+
+ public void setFbid(String fbid) {
+ this.fbid = fbid;
+ }
+
+ public String getPicid() {
+ return picid;
+ }
+
+ public void setPicid(String picid) {
+ this.picid = picid;
+ }
+
+ public String getMinpicid() {
+ return minpicid;
+ }
+
+ public void setMinpicid(String minpicid) {
+ this.minpicid = minpicid;
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBFeedback.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBFeedback.java
new file mode 100644
index 0000000..951b947
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBFeedback.java
@@ -0,0 +1,96 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+@Table(name = "tb_feedback")
+public class TBFeedback {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "fbid", nullable = false, length = 32)
+ private String fbid;
+ @Column(name = "userid", nullable = false, length = 32)
+ private String userid;
+ @Column(name = "content", nullable = false, length = 200)
+ private String content;
+ @Column(name = "fbtime", length = 14)
+ private String fbtime;
+ @Column(name = "fbip", length = 32)
+ private String fbip;
+ @Column(name = "replystatus", length = 1)
+ private String replystatus;
+ @Transient
+ private String username;
+ @Transient
+ private List<TBAnnex> pictures;
+
+ public String getFbid() {
+ return fbid;
+ }
+
+ public void setFbid(String fbid) {
+ this.fbid = fbid;
+ }
+
+ public String getUserid() {
+ return userid;
+ }
+
+ public void setUserid(String userid) {
+ this.userid = userid;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public String getFbtime() {
+ return fbtime;
+ }
+
+ public void setFbtime(String fbtime) {
+ this.fbtime = fbtime;
+ }
+
+ public String getFbip() {
+ return fbip;
+ }
+
+ public void setFbip(String fbip) {
+ this.fbip = fbip;
+ }
+
+
+ public String getReplystatus() {
+ return replystatus;
+ }
+
+ public void setReplystatus(String replystatus) {
+ this.replystatus = replystatus;
+ }
+
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public List<TBAnnex> getPictures() {
+ return pictures;
+ }
+
+ public void setPictures(List<TBAnnex> pictures) {
+ this.pictures = pictures;
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBReply.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBReply.java
new file mode 100644
index 0000000..4a65054
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBReply.java
@@ -0,0 +1,63 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_reply")
+public class TBReply {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "replyid", nullable = false, length = 32)
+ private String replyid;
+ @Column(name = "replycontent", length = 200)
+ private String replycontent;
+ @Column(name = "operid", length = 32)
+ private String operid;
+ @Column(name = "updatetime", length = 14)
+ private String updatetime;
+ @Column(name = "fbid", length = 32)
+ private String fbid;
+
+ public String getReplyid() {
+ return replyid;
+ }
+
+ public void setReplyid(String replyid) {
+ this.replyid = replyid;
+ }
+
+ public String getReplycontent() {
+ return replycontent;
+ }
+
+ public void setReplycontent(String replycontent) {
+ this.replycontent = replycontent;
+ }
+
+ public String getOperid() {
+ return operid;
+ }
+
+ public void setOperid(String operid) {
+ this.operid = operid;
+ }
+
+ public String getUpdatetime() {
+ return updatetime;
+ }
+
+ public void setUpdatetime(String updatetime) {
+ this.updatetime = updatetime;
+ }
+
+ public String getFbid() {
+ return fbid;
+ }
+
+ public void setFbid(String fbid) {
+ this.fbid = fbid;
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBResource.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBResource.java
new file mode 100644
index 0000000..031e189
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBResource.java
@@ -0,0 +1,112 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.List;
+
+@Entity
+@Table(name = "tb_resource")
+public class TBResource {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "resid", nullable = false, length = 32)
+ private String resid;
+
+ @Column(name = "respath", length = 100)
+ private String respath;
+
+ @Column(name = "resname", length = 50)
+ private String resname;
+
+ @Column(name = "parentid", length = 32)
+ private String parentid;
+
+ @Column(name = "isleaf", length = 1)
+ private String isleaf;
+
+ @Column(name = "showflag", length = 1)
+ private String showflag;
+
+ @Column(name = "ordernum", precision = 3)
+ private int ordernum;
+
+ @Column(name = "icon",length = 50)
+ private String icon;
+
+ @Transient
+ private List<TBResource> children;
+
+ public String getResid() {
+ return resid;
+ }
+
+ public void setResid(String resid) {
+ this.resid = resid;
+ }
+
+ public String getRespath() {
+ return respath;
+ }
+
+ public void setRespath(String respath) {
+ this.respath = respath;
+ }
+
+ public String getResname() {
+ return resname;
+ }
+
+ public void setResname(String resname) {
+ this.resname = resname;
+ }
+
+ public String getParentid() {
+ return parentid;
+ }
+
+ public void setParentid(String parentid) {
+ this.parentid = parentid;
+ }
+
+ public String getIsleaf() {
+ return isleaf;
+ }
+
+ public void setIsleaf(String isleaf) {
+ this.isleaf = isleaf;
+ }
+
+ public String getShowflag() {
+ return showflag;
+ }
+
+ public void setShowflag(String showflag) {
+ this.showflag = showflag;
+ }
+
+ public int getOrdernum() {
+ return ordernum;
+ }
+
+ public void setOrdernum(int ordernum) {
+ this.ordernum = ordernum;
+ }
+
+ public String getIcon() {
+ return icon;
+ }
+
+ public void setIcon(String icon) {
+ this.icon = icon;
+ }
+
+ public List<TBResource> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<TBResource> children) {
+ this.children = children;
+ }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBRole.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBRole.java
new file mode 100644
index 0000000..9bb1a5d
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBRole.java
@@ -0,0 +1,68 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_role")
+public class TBRole {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "roleid", nullable = false, length = 32)
+ private String roleid;
+
+ @Column(name = "rolename", nullable = false, length = 32)
+ private String rolename;
+
+ @Column(name = "rolecode", nullable = false, length = 1)
+ private String rolecode;
+
+ @Column(name = "detail", length = 200)
+ private String detail;
+
+ @Column(name = "moditime", nullable = false, length = 14)
+ private String moditime;
+
+ public String getRoleid() {
+ return roleid;
+ }
+
+ public void setRoleid(String roleid) {
+ this.roleid = roleid;
+ }
+
+ public String getRolename() {
+ return rolename;
+ }
+
+ public void setRolename(String rolename) {
+ this.rolename = rolename;
+ }
+
+ public String getRolecode() {
+ return rolecode;
+ }
+
+ public void setRolecode(String rolecode) {
+ this.rolecode = rolecode;
+ }
+
+ public String getDetail() {
+ return detail;
+ }
+
+ public void setDetail(String detail) {
+ this.detail = detail;
+ }
+
+ public String getModitime() {
+ return moditime;
+ }
+
+ public void setModitime(String moditime) {
+ this.moditime = moditime;
+ }
+
+
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TRoleResource.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TRoleResource.java
new file mode 100644
index 0000000..08a3b6a
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TRoleResource.java
@@ -0,0 +1,55 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_role_resource")
+public class TRoleResource {
+ @Id
+ @GenericGenerator(name = "idGenerator", strategy = "uuid")
+ @GeneratedValue(generator = "idGenerator")
+ @Column(name = "id", nullable = false, length = 32)
+ private String id;
+
+ @Column(name = "roleid", nullable = false, length = 32)
+ private String roleid;
+
+ @Column(name = "resid", nullable = false, length = 32)
+ private String resid;
+
+ @Column(name = "addtime", length = 16)
+ private String addtime;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getRoleid() {
+ return roleid;
+ }
+
+ public void setRoleid(String roleid) {
+ this.roleid = roleid;
+ }
+
+ public String getResid() {
+ return resid;
+ }
+
+ public void setResid(String resid) {
+ this.resid = resid;
+ }
+
+ public String getAddtime() {
+ return addtime;
+ }
+
+ public void setAddtime(String addtime) {
+ this.addtime = addtime;
+ }
+}
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
new file mode 100644
index 0000000..4de5a35
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.portal.util;
+
+public class PortalConstant{
+ public static final String YES = "1";
+ public static final String NO = "0";
+
+ public static final String SYSPARA_IMAGESERVER_URL = "imageserver.url.image";
+}
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt
new file mode 100644
index 0000000..7d4d4e6
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/OperLoginHandler.kt
@@ -0,0 +1,102 @@
+package com.supwisdom.dlpay.portal
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.supwisdom.dlpay.api.bean.JsonResult
+import com.supwisdom.dlpay.framework.core.JwtConfig
+import com.supwisdom.dlpay.framework.core.JwtTokenUtil
+import com.supwisdom.dlpay.framework.domain.JwtRedis
+import com.supwisdom.dlpay.framework.domain.TOperator
+import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
+import com.supwisdom.dlpay.framework.service.OperatorDetailService
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.Constants
+import com.supwisdom.dlpay.framework.util.SysparaUtil
+import com.supwisdom.dlpay.framework.util.TradeDict
+import com.supwisdom.dlpay.mobile.exception.UserLoginFailException
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.http.HttpStatus
+import org.springframework.security.authentication.BadCredentialsException
+import org.springframework.security.authentication.LockedException
+import org.springframework.security.core.Authentication
+import org.springframework.security.core.AuthenticationException
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
+import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
+import org.springframework.stereotype.Component
+import java.io.IOException
+import javax.servlet.ServletException
+import javax.servlet.http.HttpServletRequest
+import javax.servlet.http.HttpServletResponse
+
+@Component("operLoginSuccessHandler")
+class OperLoginSuccessHandler : SimpleUrlAuthenticationSuccessHandler() {
+ @Autowired
+ lateinit var operatorDetailService: OperatorDetailService
+ @Autowired
+ lateinit var objectMapper: ObjectMapper
+ @Autowired
+ lateinit var jwtConfig: JwtConfig
+ @Autowired
+ lateinit var apiJwtRepository: ApiJwtRepository
+ @Autowired
+ lateinit var systemUtilService: SystemUtilService
+
+ override fun onAuthenticationSuccess(request: HttpServletRequest, response: HttpServletResponse, authentication: Authentication) {
+ val temp = authentication.principal as TOperator
+ val operator = operatorDetailService.findByOperid(temp.operid)
+ val exp = systemUtilService.getSysparaValueAsInt(SysparaUtil.MOBILE_LOGIN_EXPIRE_IN_SECONDS,60*60*24*3)
+ jwtConfig.expiration = exp.toLong()
+ if (operator != null) {
+ //TODO 从数据取jwtConfig.expiration
+ val token = JwtTokenUtil(jwtConfig).generateToken(
+ mapOf("uid" to operator.operid, "issuer" to "portal",
+ "audience" to operator.opername,
+ Constants.JWT_CLAIM_TENANTID to "portal",
+ Constants.JWT_CLAIM_AUTHORITIES to temp.authorities))
+ val jwt = JwtRedis().apply {
+ jti = token.jti
+ uid = operator.opername
+ status = TradeDict.JWT_STATUS_NORMAL
+ expiration = token.expiration.valueInMillis
+ }.apply {
+ //删除之前的token
+ if (!operator.jti.isNullOrEmpty()) {
+ apiJwtRepository.deleteById(operator.jti!!)
+ }
+ apiJwtRepository.save(this)
+ }
+ operator.jti = jwt.jti
+ operatorDetailService.saveOper(operator)
+ response.status = HttpStatus.OK.value()
+ response.contentType = "application/json;charset=UTF-8"
+ response.writer.write(objectMapper.writeValueAsString(JsonResult.ok()
+ .put("token", token.jwtToken)
+ ?.put("expire",token.expiration.valueInMillis)
+ ?.put("now",System.currentTimeMillis())
+ ?.put("tenantid", "mobile")
+ ?.put("uid", operator.operid)))
+ } else {
+ throw UserLoginFailException("登录错误")
+ }
+ }
+}
+
+
+@Component("operLoginFailHandler")
+class OperLoginFailHandler : SimpleUrlAuthenticationFailureHandler() {
+ @Autowired
+ lateinit var objectMapper: ObjectMapper
+
+ @Throws(IOException::class, ServletException::class)
+ override fun onAuthenticationFailure(request: HttpServletRequest,
+ response: HttpServletResponse, exception: AuthenticationException) {
+ logger.error("登录失败:" + exception.message + "|" + exception.javaClass)
+ val errmsg = when (exception) {
+ is BadCredentialsException -> "账号或密码错误"
+ is LockedException -> "账户被锁定"
+ else -> exception.message!!
+ }
+ response.status = HttpStatus.OK.value()
+ response.contentType = "application/json;charset=UTF-8"
+ response.writer.write(objectMapper.writeValueAsString(JsonResult.error(errmsg)))
+ }
+}
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 3ea8bbc..50f52a3 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
@@ -1,14 +1,131 @@
package com.supwisdom.dlpay.portal
+import com.supwisdom.dlpay.api.bean.JsonResult
+import com.supwisdom.dlpay.framework.core.JwtConfig
+import com.supwisdom.dlpay.framework.core.JwtTokenUtil
+import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
+import com.supwisdom.dlpay.framework.service.OperatorDetailService
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.portal.bean.FeedbackSearchBean
+import com.supwisdom.dlpay.portal.domain.TBReply
+import com.supwisdom.dlpay.portal.service.FeedbackService
+import com.supwisdom.dlpay.portal.util.PortalConstant
+import mu.KotlinLogging
+import org.jose4j.jwt.ReservedClaimNames
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
-import org.springframework.web.bind.annotation.RequestMapping
-import org.springframework.web.bind.annotation.RestController
+import org.springframework.security.core.context.SecurityContextHolder
+import org.springframework.web.bind.annotation.*
@RestController
@RequestMapping("/portalapi")
-class PortalApi{
+class PortalApi {
+ @Autowired
+ lateinit var operatorDetailService: OperatorDetailService
+ @Autowired
+ lateinit var feedbackService: FeedbackService
+ @Autowired
+ lateinit var jwtConfig: JwtConfig
+ @Autowired
+ lateinit var apiJwtRepository: ApiJwtRepository
+ @Autowired
+ lateinit var systemUtilService: SystemUtilService
+ val logger = KotlinLogging.logger { }
+
@RequestMapping("/test")
- fun test(): ResponseEntity<Any>{
- return ResponseEntity.ok("测试")
+ fun test(): JsonResult {
+ return JsonResult.ok("测试")
+ }
+
+ @RequestMapping("user/logout")
+ fun logout(@RequestHeader("Authorization") auth: String?): ResponseEntity<Any>{
+ if (auth == null) {
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
+ }
+ val jwt = auth.substring(jwtConfig.tokenHeader.length)
+ val claims = JwtTokenUtil(jwtConfig).verifyToken(jwt)
+ SecurityContextHolder.clearContext()
+ apiJwtRepository.deleteById(claims[ReservedClaimNames.JWT_ID].toString())
+ return ResponseEntity.ok().body(JsonResult.ok())
+ }
+
+ @RequestMapping("/user/info")
+ fun getUserInfo(): JsonResult? {
+ return try {
+ val p = SecurityContextHolder.getContext().authentication
+ val oper = operatorDetailService.findByOperid(p.name)
+ val data = HashMap<String, String>()
+ val url = systemUtilService.getBusinessValue(PortalConstant.SYSPARA_IMAGESERVER_URL)
+ data["name"] = oper.opername
+ data["roles"] = "admin"
+ data["url"] = url
+ JsonResult.ok().put("data", data)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("查询用户信息异常")
+ }
+
+ }
+
+ @RequestMapping("/user/resource")
+ fun getUserResource(): JsonResult? {
+ return try {
+ val p = SecurityContextHolder.getContext().authentication
+ val oper = operatorDetailService.findByOperid(p.name)
+ val resource = operatorDetailService.getResByRoleId(oper.roleid)
+ JsonResult.ok().put("resource", resource)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("查询功能列表异常")
+ }
+
+ }
+
+ @RequestMapping("/feedback/list")
+ fun getFeedbackList(bean: FeedbackSearchBean): JsonResult? {
+ return try {
+ val page = feedbackService.getFeedbackList(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("/feedback/reply/{fbid}")
+ fun getFeedbackReply(@PathVariable("fbid") fbid: String): JsonResult? {
+ return try {
+ val list = feedbackService.getReplyListByFbId(fbid)
+ if (list.isEmpty()) {
+ return JsonResult.ok().put("msg", "无数据")
+ }
+ return JsonResult.ok().put("list", list)
+ } catch (e: Exception) {
+ logger.error { e.message }
+ JsonResult.error("查询用户留言回复异常")
+ }
+ }
+
+ @RequestMapping(value= ["/feedback/reply/save"],method = [RequestMethod.POST])
+ fun saveFeedbackReply(@RequestBody reply:TBReply): JsonResult? {
+ return try {
+ val p = SecurityContextHolder.getContext().authentication
+ val oper = operatorDetailService.findByOperid(p.name)
+ reply.operid = oper.operid
+ val msg = feedbackService.saveReplyListByFbId(reply)
+ return if (StringUtil.isEmpty(msg)) {
+ JsonResult.ok()
+ } else {
+ JsonResult.error(msg)
+ }
+ } 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/FeedbackSearchBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/FeedbackSearchBean.kt
new file mode 100644
index 0000000..3b15a48
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/FeedbackSearchBean.kt
@@ -0,0 +1,11 @@
+package com.supwisdom.dlpay.portal.bean
+
+class FeedbackSearchBean {
+ var username: String = ""
+ var content: String = ""
+ var startdate: String = ""
+ var enddate: String = ""
+ var replystatus: 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/AnnexDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AnnexDao.kt
new file mode 100644
index 0000000..59968d8
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AnnexDao.kt
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBAnnex
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface AnnexDao : JpaRepository<TBAnnex, String>, FeedbackRepository {
+ fun getByFbid(fbid: String): List<TBAnnex>
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackDao.kt
new file mode 100644
index 0000000..9d55724
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackDao.kt
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBFeedback
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface FeedbackDao :JpaRepository<TBFeedback,String>,FeedbackRepository{
+
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackRepository.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackRepository.kt
new file mode 100644
index 0000000..6a91a73
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/FeedbackRepository.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.FeedbackSearchBean
+
+interface FeedbackRepository {
+ fun getFeedbackList(bean:FeedbackSearchBean):Pagination
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ReplyDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ReplyDao.kt
new file mode 100644
index 0000000..e0a71bf
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ReplyDao.kt
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBReply
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface ReplyDao :JpaRepository<TBReply,String>{
+ fun getAllByFbid(fbid:String):List<TBReply>
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ResourceDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ResourceDao.kt
new file mode 100644
index 0000000..4d79afe
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ResourceDao.kt
@@ -0,0 +1,16 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBResource
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.data.jpa.repository.Query
+import org.springframework.stereotype.Repository
+
+@Repository
+interface ResourceDao : JpaRepository<TBResource, String> {
+
+ @Query("select t2 from TRoleResource t1,TBResource t2 where t1.resid = t2.resid and t2.isleaf = '0' and t1.roleid=?1 order by t2.ordernum")
+ fun findRootListByRole(roleId: String): List<TBResource>
+
+ @Query("select t2 from TRoleResource t1,TBResource t2 where t1.resid = t2.resid and t2.isleaf = '1' and t1.roleid=?1 and t2.parentid=?2 order by t2.ordernum")
+ fun findChildrenByRoleAndParent(roleId: String, parentId: String): List<TBResource>
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/FeedbackService.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/FeedbackService.kt
new file mode 100644
index 0000000..005de34
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/FeedbackService.kt
@@ -0,0 +1,11 @@
+package com.supwisdom.dlpay.portal.service
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.portal.bean.FeedbackSearchBean
+import com.supwisdom.dlpay.portal.domain.TBReply
+
+interface FeedbackService {
+ fun getFeedbackList(bean: FeedbackSearchBean): Pagination
+ fun getReplyListByFbId(fbId: String): List<TBReply>
+ fun saveReplyListByFbId(reply: TBReply):String?
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/FeedbackServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/FeedbackServiceImpl.kt
new file mode 100644
index 0000000..d690911
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/FeedbackServiceImpl.kt
@@ -0,0 +1,56 @@
+package com.supwisdom.dlpay.portal.service.Impl
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.framework.service.SystemUtilService
+import com.supwisdom.dlpay.framework.util.StringUtil
+import com.supwisdom.dlpay.portal.bean.FeedbackSearchBean
+import com.supwisdom.dlpay.portal.dao.AnnexDao
+import com.supwisdom.dlpay.portal.dao.FeedbackDao
+import com.supwisdom.dlpay.portal.dao.ReplyDao
+import com.supwisdom.dlpay.portal.domain.TBFeedback
+import com.supwisdom.dlpay.portal.domain.TBReply
+import com.supwisdom.dlpay.portal.service.FeedbackService
+import com.supwisdom.dlpay.portal.util.PortalConstant
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+
+@Service
+class FeedbackServiceImpl : FeedbackService {
+ @Autowired
+ lateinit var feedbackDao: FeedbackDao
+ @Autowired
+ lateinit var replyDao: ReplyDao
+ @Autowired
+ lateinit var systemUtilService: SystemUtilService
+ @Autowired
+ lateinit var annexDao: AnnexDao
+
+ override fun getFeedbackList(bean: FeedbackSearchBean): Pagination {
+ val page = feedbackDao.getFeedbackList(bean)
+ val list = page.list as List<TBFeedback>
+ list.forEach { feedback ->
+ run {
+ feedback.pictures = annexDao.getByFbid(feedback.fbid)
+ }
+ }
+ return page
+ }
+
+ override fun getReplyListByFbId(fbId: String): List<TBReply> {
+ return replyDao.getAllByFbid(fbId)
+ }
+
+ override fun saveReplyListByFbId(reply: TBReply): String? {
+ val optional = feedbackDao.findById(reply.fbid)
+ return if (optional.isPresent) {
+ val feedback = optional.get()
+ reply.updatetime = systemUtilService.sysdatetime.hostdatetime
+ replyDao.save(reply)
+ feedback.replystatus = PortalConstant.YES
+ feedbackDao.save(feedback)
+ null
+ } else {
+ "回复的留言不存在"
+ }
+ }
+}
\ 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 e8464f1..e1d5a1f 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -4,8 +4,6 @@
import com.supwisdom.dlpay.framework.core.JwtTokenUtil
import com.supwisdom.dlpay.framework.core.PasswordBCryptConfig
import com.supwisdom.dlpay.framework.redisrepo.ApiJwtRepository
-import com.supwisdom.dlpay.framework.security.MyAuthenticationFailureHandler
-import com.supwisdom.dlpay.framework.security.ValidateCodeSecurityConfig
import com.supwisdom.dlpay.framework.service.OperatorDetailService
import com.supwisdom.dlpay.framework.tenant.TenantContext
import com.supwisdom.dlpay.framework.util.Constants
@@ -13,6 +11,8 @@
import com.supwisdom.dlpay.mobile.AuthLoginFailHandler
import com.supwisdom.dlpay.mobile.AuthLoginSuccessHandler
import com.supwisdom.dlpay.mobile.service.MobileUserService
+import com.supwisdom.dlpay.portal.OperLoginFailHandler
+import com.supwisdom.dlpay.portal.OperLoginSuccessHandler
import org.jose4j.jwt.ReservedClaimNames
import org.jose4j.jwt.consumer.InvalidJwtException
import org.jose4j.lang.JoseException
@@ -34,8 +34,6 @@
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
-import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher
import org.springframework.stereotype.Component
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.CorsConfigurationSource
@@ -46,8 +44,6 @@
import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
-import javax.sql.DataSource
-
@Component
class ApiJwtAuthenticationFilter : OncePerRequestFilter() {
@@ -160,10 +156,6 @@
url = url.replace(context, "")
}
logger.info(url)
- if (!url.startsWith("/mobileapi/v1/")) {
- filterChain.doFilter(request, response)
- return
- }
request.getHeader(jwtConfig.header)?.let { authHeader ->
try {
val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
@@ -326,6 +318,37 @@
class WebSecurityConfig {
companion object {
+ @Configuration
+ @Order(1)
+ class ApiWebSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() {
+ @Autowired
+ lateinit var apiJwtAuthenticationFilter: ApiJwtAuthenticationFilter
+ override fun configure(http: HttpSecurity) {
+ // 设置 API 访问权限管理
+ http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and()
+ .antMatcher("/api/**")
+ .addFilterAfter(apiJwtAuthenticationFilter,
+ UsernamePasswordAuthenticationFilter::class.java)
+ .authorizeRequests()
+ .antMatchers("/api/auth/**").permitAll()
+ .antMatchers("/api/notify/**").permitAll()
+ .antMatchers("/api/common/**").permitAll()
+ .antMatchers("/api/consume/**").hasRole("THIRD_CONSUME")
+ .antMatchers("/api/recharge/**").hasRole("THIRD_DEPOSIT")
+ .antMatchers("/api/user/**").hasRole("THIRD_ADMIN")
+ .antMatchers("/api/shop/**").hasRole("THIRD_SHOP")
+ .anyRequest().hasRole("THIRD_COMMON")
+ .and()
+ .csrf().ignoringAntMatchers("/api/**", "oauth/**")
+
+ }
+
+ @Bean
+ override fun authenticationManager(): AuthenticationManager {
+ return super.authenticationManagerBean()
+ }
+ }
@Configuration
@Order(2)
@@ -348,11 +371,6 @@
}
@Bean
- override fun authenticationManager(): AuthenticationManager {
- return super.authenticationManagerBean()
- }
-
- @Bean
fun userProvider(): DaoAuthenticationProvider {
return DaoAuthenticationProvider().apply {
setUserDetailsService(userDetailsService)
@@ -396,7 +414,7 @@
configuration.allowedMethods = listOf("GET", "POST")
configuration.allowedHeaders = listOf("*")
val source = UrlBasedCorsConfigurationSource()
- source.registerCorsConfiguration("/mobileapi/**", configuration)
+ source.registerCorsConfiguration("/**", configuration)
return source
}
}
@@ -405,28 +423,32 @@
@Order(3)
class PortalApiSecurityConfigurationAdapter : WebSecurityConfigurerAdapter() {
@Autowired
+ lateinit var failureHandler: OperLoginFailHandler
+ @Autowired
+ lateinit var successHandler: OperLoginSuccessHandler
+ @Autowired
lateinit var passwordBCryptConfig: PasswordBCryptConfig
@Autowired
- lateinit var userDetailsService: MobileUserService
+ lateinit var operatorDetailService: OperatorDetailService
@Autowired
lateinit var portalApiSecurityFilter: PortalApiSecurityFilter
override fun configure(auth: AuthenticationManagerBuilder) {
- auth.authenticationProvider(portalUserProvider())
+ auth.authenticationProvider(operatorUserProvider())
}
@Bean
- fun portalUserProvider(): DaoAuthenticationProvider {
+ fun operatorUserProvider(): DaoAuthenticationProvider {
return DaoAuthenticationProvider().apply {
- setUserDetailsService(userDetailsService)
- setPasswordEncoder(portalUserPasswordEncoder())
+ setUserDetailsService(operatorDetailService)
+ setPasswordEncoder(operatorUserPasswordEncoder())
}
}
@Bean
- fun portalUserPasswordEncoder(): BCryptPasswordEncoder {
+ fun operatorUserPasswordEncoder(): BCryptPasswordEncoder {
return if (passwordBCryptConfig.seed.isBlank()) {
BCryptPasswordEncoder()
} else {
@@ -443,11 +465,13 @@
.antMatcher("/portalapi/**")
.addFilterAfter(portalApiSecurityFilter,
UsernamePasswordAuthenticationFilter::class.java)
- .authorizeRequests().antMatchers( "/mobileapi/login")
- .permitAll().anyRequest().authenticated()
+ .authorizeRequests().antMatchers("/portalapi/login").permitAll()
+ .anyRequest().authenticated()
.and()
.formLogin()
- .loginProcessingUrl("/mobileapi/login")
+ .loginProcessingUrl("/portalapi/login")
+ .failureHandler(failureHandler)
+ .successHandler(successHandler)
.and().csrf().disable()
}
}
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 091b5cf..ffe72fb 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -14,7 +14,8 @@
#################### JSP PAGE ####################
#spring.mvc.view.prefix=/pages/
#spring.mvc.view.suffix=.jsp
-server.servlet.context-path=/payapi
+server.servlet.context-path=/portal
+server.port=8089
#################### thymeleaf ####################
spring.mvc.static-path-pattern=/static/**
spring.thymeleaf.prefix=classpath:/templates/
diff --git a/backend/src/main/resources/data-postgresql.sql b/backend/src/main/resources/data-postgresql.sql
index 4298c90..562254a 100644
--- a/backend/src/main/resources/data-postgresql.sql
+++ b/backend/src/main/resources/data-postgresql.sql
@@ -1,16 +1,9 @@
--pg--
-INSERT INTO "tb_period" ("id", "period_year", "period_month", "startdate", "enddate", "settleflag" , "tenantid")
-VALUES ('8a53b7826c65b925016c65bfa7c3001c',to_number(to_char(CURRENT_TIMESTAMP,'yyyy'),'9999'),to_number(to_char(CURRENT_TIMESTAMP,'MM'),'99'), to_char(CURRENT_TIMESTAMP,'yyyyMM')||'01', to_char((to_date(to_char(CURRENT_TIMESTAMP+'1 month','yyyyMM')||'01','yyyyMMdd')-1)::Timestamp,'yyyyMMdd'), 0, '{tenantid}');
-
-insert into TB_SETTLECTL(BOOKSETNO,PERIODYEAR,PERIODMONTH,STATDATE,SETTLEDATE,STATUS,updtime, "tenantid")
-values (1,to_number(to_char(CURRENT_TIMESTAMP,'yyyy'),'9999'),to_number(to_char(CURRENT_TIMESTAMP,'MM'),'99'),to_number(to_char(CURRENT_TIMESTAMP,'yyyyMMdd'),'99999999'),to_number(to_char(CURRENT_TIMESTAMP,'yyyyMMdd'),'99999999'),0,to_char(CURRENT_TIMESTAMP,'yyyyMMddhh24miss'), '{tenantid}');
-
-insert into TB_VOUCHERNOCTL(VOUCHERTYPE,PERIODMONTH,VOUCHERNO,"tenantid")
-values (1,to_number(to_char(CURRENT_TIMESTAMP,'MM'),'99'),0, , '{tenantid}');
-
-update TB_SUBJECT set opendate = to_number(to_char(CURRENT_TIMESTAMP,'yyyymmdd'),'99999999');
-
-CREATE SEQUENCE seq_refno;
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('imageserver.url.assign', 'http://ykt.supwisdom.com:9333', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('imagemaxsize', '204800', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('minimagesize', '150,150', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('imageserver.url.image', 'http://ykt.supwisdom.com:9119/touchorder/dcpic', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('imageserver.url.push', 'http://ykt.supwisdom.com:8777', '{tenentid}');
--------- end of script
commit;
diff --git a/config/application-devel-pg.properties b/config/application-devel-pg.properties
index 4346bdc..53d2f04 100644
--- a/config/application-devel-pg.properties
+++ b/config/application-devel-pg.properties
@@ -6,7 +6,7 @@
# Postgresql settings
spring.datasource.platform=postgresql
#spring.datasource.url=jdbc:postgresql://ykt.supwisdom.com:15432/payapidev
-spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/payapidev
+spring.datasource.url=jdbc:postgresql://172.28.201.70:15432/portal
spring.datasource.username=payapi
spring.datasource.password=123456
spring.datasource.continue-on-error=true
diff --git a/frontend/.env.development b/frontend/.env.development
index de583d0..4dc439f 100644
--- a/frontend/.env.development
+++ b/frontend/.env.development
@@ -2,4 +2,5 @@
ENV = 'development'
# base api
-VUE_APP_BASE_API = '/dev-api'
+#VUE_APP_BASE_API = '/dev-api'
+VUE_APP_BASE_API = 'http://localhost:8089/portal/portalapi'
diff --git a/frontend/package.json b/frontend/package.json
index 02f68e2..f57cfa8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -28,6 +28,7 @@
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.1",
+ "moment": "^2.27.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
diff --git a/frontend/src/api/feedback.js b/frontend/src/api/feedback.js
new file mode 100644
index 0000000..016794e
--- /dev/null
+++ b/frontend/src/api/feedback.js
@@ -0,0 +1,24 @@
+import request from '@/utils/request'
+
+export function getFeedbackList(query) {
+ return request({
+ url: '/feedback/list',
+ method: 'get',
+ params: query
+ })
+}
+
+export function getFeedbackReply(fbid) {
+ return request({
+ url: '/feedback/reply/' + fbid,
+ method: 'get'
+ })
+}
+
+export function saveFeedbackReply(data) {
+ return request({
+ url: '/feedback/reply/save',
+ method: 'post',
+ data
+ })
+}
diff --git a/frontend/src/api/user.js b/frontend/src/api/user.js
index b8b8741..aba990c 100644
--- a/frontend/src/api/user.js
+++ b/frontend/src/api/user.js
@@ -2,15 +2,25 @@
export function login(data) {
return request({
- url: '/vue-element-admin/user/login',
+ url: '/login',
method: 'post',
- data
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ },
+ data,
+ transformRequest: [function(data) {
+ let ret = ''
+ for (const it in data) {
+ ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
+ }
+ return ret
+ }]
})
}
export function getInfo(token) {
return request({
- url: '/vue-element-admin/user/info',
+ url: '/user/info',
method: 'get',
params: { token }
})
@@ -18,7 +28,15 @@
export function logout() {
return request({
- url: '/vue-element-admin/user/logout',
+ url: '/user/logout',
method: 'post'
})
}
+
+export function getAuthMenu(token) {
+ return request({
+ url: '/user/resource',
+ method: 'get',
+ params: { token }
+ })
+}
diff --git a/frontend/src/components/Breadcrumb/index.vue b/frontend/src/components/Breadcrumb/index.vue
index e224ff7..8283946 100644
--- a/frontend/src/components/Breadcrumb/index.vue
+++ b/frontend/src/components/Breadcrumb/index.vue
@@ -2,7 +2,7 @@
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
- <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+ <span v-if="item.redirect==='noRedirect'||index==levelList.length-1||index==levelList.length-2" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
@@ -37,7 +37,7 @@
const first = matched[0]
if (!this.isDashboard(first)) {
- matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
+ matched = [{ path: '/', meta: { title: '首页' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
diff --git a/frontend/src/components/HeaderSearch/index.vue b/frontend/src/components/HeaderSearch/index.vue
index 6026ebb..9a30d1a 100644
--- a/frontend/src/components/HeaderSearch/index.vue
+++ b/frontend/src/components/HeaderSearch/index.vue
@@ -8,7 +8,7 @@
filterable
default-first-option
remote
- placeholder="Search"
+ placeholder="搜索功能"
class="header-search-select"
@change="change"
>
diff --git a/frontend/src/components/RightPanel/index.vue b/frontend/src/components/RightPanel/index.vue
index 55e8c1e..f437c0c 100644
--- a/frontend/src/components/RightPanel/index.vue
+++ b/frontend/src/components/RightPanel/index.vue
@@ -2,9 +2,6 @@
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
- <div class="handle-button" :style="{'top':buttonTop+'px','background-color':theme}" @click="show=!show">
- <i :class="show?'el-icon-close':'el-icon-setting'" />
- </div>
<div class="rightPanel-items">
<slot />
</div>
diff --git a/frontend/src/layout/components/Navbar.vue b/frontend/src/layout/components/Navbar.vue
index 37bc1e6..0b0ebeb 100644
--- a/frontend/src/layout/components/Navbar.vue
+++ b/frontend/src/layout/components/Navbar.vue
@@ -8,36 +8,20 @@
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
- <error-log class="errLog-container right-menu-item hover-effect" />
-
- <screenfull id="screenfull" class="right-menu-item hover-effect" />
-
- <el-tooltip content="Global Size" effect="dark" placement="bottom">
- <size-select id="size-select" class="right-menu-item hover-effect" />
- </el-tooltip>
-
</template>
-
- <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
+ <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
- <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar">
- <i class="el-icon-caret-bottom" />
+ <span v-html="getOperName()" />
</div>
<el-dropdown-menu slot="dropdown">
- <router-link to="/profile/index">
- <el-dropdown-item>Profile</el-dropdown-item>
+ <router-link to="/">
+ <el-dropdown-item>个人信息</el-dropdown-item>
</router-link>
<router-link to="/">
- <el-dropdown-item>Dashboard</el-dropdown-item>
+ <el-dropdown-item>修改密码</el-dropdown-item>
</router-link>
- <a target="_blank" href="https://github.com/PanJiaChen/vue-element-admin/">
- <el-dropdown-item>Github</el-dropdown-item>
- </a>
- <a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/">
- <el-dropdown-item>Docs</el-dropdown-item>
- </a>
<el-dropdown-item divided @click.native="logout">
- <span style="display:block;">Log Out</span>
+ <span style="display:block;">退出</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
@@ -47,20 +31,15 @@
<script>
import { mapGetters } from 'vuex'
+import user from '@/store/modules/user'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
-import ErrorLog from '@/components/ErrorLog'
-import Screenfull from '@/components/Screenfull'
-import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
export default {
components: {
Breadcrumb,
Hamburger,
- ErrorLog,
- Screenfull,
- SizeSelect,
Search
},
computed: {
@@ -75,8 +54,14 @@
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
- await this.$store.dispatch('user/logout')
- this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+ this.$store.dispatch('user/logout').then(() => {
+ this.$router.push(`/login?redirect=${this.$route.fullPath}`)
+ }).catch((response) => {
+ console.log(response)
+ })
+ },
+ getOperName() {
+ return user.state.name
}
}
}
diff --git a/frontend/src/layout/components/Sidebar/Logo.vue b/frontend/src/layout/components/Sidebar/Logo.vue
index ac0c8d8..4979dc2 100644
--- a/frontend/src/layout/components/Sidebar/Logo.vue
+++ b/frontend/src/layout/components/Sidebar/Logo.vue
@@ -24,7 +24,7 @@
},
data() {
return {
- title: 'Vue Element Admin',
+ title: '门户系统',
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
}
}
diff --git a/frontend/src/main.js b/frontend/src/main.js
index b5fa135..e750af9 100644
--- a/frontend/src/main.js
+++ b/frontend/src/main.js
@@ -6,7 +6,7 @@
import Element from 'element-ui'
import './styles/element-variables.scss'
-import enLang from 'element-ui/lib/locale/lang/en'// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖
+// 如果使用中文语言包请默认支持,无需额外引入,请删除该依赖
import '@/styles/index.scss' // global css
@@ -34,8 +34,7 @@
}
Vue.use(Element, {
- size: Cookies.get('size') || 'medium', // set element-ui default size
- locale: enLang // 如果使用中文,无需设置,请删除
+ size: Cookies.get('size') || 'medium' // set element-ui default size
})
// register global utility filters
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index 2be959d..bce74c5 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -7,10 +7,6 @@
import Layout from '@/layout'
/* Router Modules */
-import componentsRouter from './modules/components'
-import chartsRouter from './modules/charts'
-import tableRouter from './modules/table'
-import nestedRouter from './modules/nested'
/**
* Note: sub-menu only appear when route children.length >= 1
@@ -72,55 +68,7 @@
},
{
path: '/',
- component: Layout,
- redirect: '/dashboard',
- children: [
- {
- path: 'dashboard',
- component: () => import('@/views/dashboard/index'),
- name: 'Dashboard',
- meta: { title: 'Dashboard', icon: 'dashboard', affix: true }
- }
- ]
- },
- {
- path: '/documentation',
- component: Layout,
- children: [
- {
- path: 'index',
- component: () => import('@/views/documentation/index'),
- name: 'Documentation',
- meta: { title: 'Documentation', icon: 'documentation', affix: true }
- }
- ]
- },
- {
- path: '/guide',
- component: Layout,
- redirect: '/guide/index',
- children: [
- {
- path: 'index',
- component: () => import('@/views/guide/index'),
- name: 'Guide',
- meta: { title: 'Guide', icon: 'guide', noCache: true }
- }
- ]
- },
- {
- path: '/profile',
- component: Layout,
- redirect: '/profile/index',
- hidden: true,
- children: [
- {
- path: 'index',
- component: () => import('@/views/profile/index'),
- name: 'Profile',
- meta: { title: 'Profile', icon: 'user', noCache: true }
- }
- ]
+ component: Layout
}
]
@@ -128,261 +76,7 @@
* asyncRoutes
* the routes that need to be dynamically loaded based on user roles
*/
-export const asyncRoutes = [
- {
- path: '/permission',
- component: Layout,
- redirect: '/permission/page',
- alwaysShow: true, // will always show the root menu
- name: 'Permission',
- meta: {
- title: 'Permission',
- icon: 'lock',
- roles: ['admin', 'editor'] // you can set roles in root nav
- },
- children: [
- {
- path: 'page',
- component: () => import('@/views/permission/page'),
- name: 'PagePermission',
- meta: {
- title: 'Page Permission',
- roles: ['admin'] // or you can only set roles in sub nav
- }
- },
- {
- path: 'directive',
- component: () => import('@/views/permission/directive'),
- name: 'DirectivePermission',
- meta: {
- title: 'Directive Permission'
- // if do not set roles, means: this page does not require permission
- }
- },
- {
- path: 'role',
- component: () => import('@/views/permission/role'),
- name: 'RolePermission',
- meta: {
- title: 'Role Permission',
- roles: ['admin']
- }
- }
- ]
- },
-
- {
- path: '/icon',
- component: Layout,
- children: [
- {
- path: 'index',
- component: () => import('@/views/icons/index'),
- name: 'Icons',
- meta: { title: 'Icons', icon: 'icon', noCache: true }
- }
- ]
- },
-
- /** when your routing map is too long, you can split it into small modules **/
- componentsRouter,
- chartsRouter,
- nestedRouter,
- tableRouter,
-
- {
- path: '/example',
- component: Layout,
- redirect: '/example/list',
- name: 'Example',
- meta: {
- title: 'Example',
- icon: 'el-icon-s-help'
- },
- children: [
- {
- path: 'create',
- component: () => import('@/views/example/create'),
- name: 'CreateArticle',
- meta: { title: 'Create Article', icon: 'edit' }
- },
- {
- path: 'edit/:id(\\d+)',
- component: () => import('@/views/example/edit'),
- name: 'EditArticle',
- meta: { title: 'Edit Article', noCache: true, activeMenu: '/example/list' },
- hidden: true
- },
- {
- path: 'list',
- component: () => import('@/views/example/list'),
- name: 'ArticleList',
- meta: { title: 'Article List', icon: 'list' }
- }
- ]
- },
-
- {
- path: '/tab',
- component: Layout,
- children: [
- {
- path: 'index',
- component: () => import('@/views/tab/index'),
- name: 'Tab',
- meta: { title: 'Tab', icon: 'tab' }
- }
- ]
- },
-
- {
- path: '/error',
- component: Layout,
- redirect: 'noRedirect',
- name: 'ErrorPages',
- meta: {
- title: 'Error Pages',
- icon: '404'
- },
- children: [
- {
- path: '401',
- component: () => import('@/views/error-page/401'),
- name: 'Page401',
- meta: { title: '401', noCache: true }
- },
- {
- path: '404',
- component: () => import('@/views/error-page/404'),
- name: 'Page404',
- meta: { title: '404', noCache: true }
- }
- ]
- },
-
- {
- path: '/error-log',
- component: Layout,
- children: [
- {
- path: 'log',
- component: () => import('@/views/error-log/index'),
- name: 'ErrorLog',
- meta: { title: 'Error Log', icon: 'bug' }
- }
- ]
- },
-
- {
- path: '/excel',
- component: Layout,
- redirect: '/excel/export-excel',
- name: 'Excel',
- meta: {
- title: 'Excel',
- icon: 'excel'
- },
- children: [
- {
- path: 'export-excel',
- component: () => import('@/views/excel/export-excel'),
- name: 'ExportExcel',
- meta: { title: 'Export Excel' }
- },
- {
- path: 'export-selected-excel',
- component: () => import('@/views/excel/select-excel'),
- name: 'SelectExcel',
- meta: { title: 'Export Selected' }
- },
- {
- path: 'export-merge-header',
- component: () => import('@/views/excel/merge-header'),
- name: 'MergeHeader',
- meta: { title: 'Merge Header' }
- },
- {
- path: 'upload-excel',
- component: () => import('@/views/excel/upload-excel'),
- name: 'UploadExcel',
- meta: { title: 'Upload Excel' }
- }
- ]
- },
-
- {
- path: '/zip',
- component: Layout,
- redirect: '/zip/download',
- alwaysShow: true,
- name: 'Zip',
- meta: { title: 'Zip', icon: 'zip' },
- children: [
- {
- path: 'download',
- component: () => import('@/views/zip/index'),
- name: 'ExportZip',
- meta: { title: 'Export Zip' }
- }
- ]
- },
-
- {
- path: '/pdf',
- component: Layout,
- redirect: '/pdf/index',
- children: [
- {
- path: 'index',
- component: () => import('@/views/pdf/index'),
- name: 'PDF',
- meta: { title: 'PDF', icon: 'pdf' }
- }
- ]
- },
- {
- path: '/pdf/download',
- component: () => import('@/views/pdf/download'),
- hidden: true
- },
-
- {
- path: '/theme',
- component: Layout,
- children: [
- {
- path: 'index',
- component: () => import('@/views/theme/index'),
- name: 'Theme',
- meta: { title: 'Theme', icon: 'theme' }
- }
- ]
- },
-
- {
- path: '/clipboard',
- component: Layout,
- children: [
- {
- path: 'index',
- component: () => import('@/views/clipboard/index'),
- name: 'ClipboardDemo',
- meta: { title: 'Clipboard', icon: 'clipboard' }
- }
- ]
- },
-
- {
- path: 'external-link',
- component: Layout,
- children: [
- {
- path: 'https://github.com/PanJiaChen/vue-element-admin',
- meta: { title: 'External Link', icon: 'link' }
- }
- ]
- },
-
+export let asyncRoutes = [
// 404 page must be placed at the end !!!
{ path: '*', redirect: '/404', hidden: true }
]
@@ -398,6 +92,7 @@
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
const newRouter = createRouter()
+ asyncRoutes = []
router.matcher = newRouter.matcher // reset router
}
diff --git a/frontend/src/settings.js b/frontend/src/settings.js
index 1ebc7f2..0f32b7f 100644
--- a/frontend/src/settings.js
+++ b/frontend/src/settings.js
@@ -1,5 +1,5 @@
module.exports = {
- title: 'Vue Element Admin',
+ title: '门户系统',
/**
* @type {boolean} true | false
@@ -23,7 +23,7 @@
* @type {boolean} true | false
* @description Whether show the logo in sidebar
*/
- sidebarLogo: false,
+ sidebarLogo: true,
/**
* @type {string | array} 'production' | ['production', 'development']
diff --git a/frontend/src/store/modules/permission.js b/frontend/src/store/modules/permission.js
index aeb5ee5..f1d5583 100644
--- a/frontend/src/store/modules/permission.js
+++ b/frontend/src/store/modules/permission.js
@@ -1,4 +1,6 @@
import { asyncRoutes, constantRoutes } from '@/router'
+import { getAuthMenu } from '@/api/user'
+import Layout from '@/layout'
/**
* Use meta.role to determine if the current user has permission
@@ -14,6 +16,28 @@
}
/**
+ * 后台查询的菜单数据拼装成路由格式的数据
+ * @param routes
+ */
+export function generaMenu(routes, data) {
+ data.forEach(item => {
+ // alert(JSON.stringify(item))
+ const menu = {
+ path: item.respath === '#' ? item.resid + '_key' : item.respath,
+ component: item.respath === '#' ? Layout : (resolve) => require([`@/views${item.respath}/index`], resolve),
+ // hidden: true,
+ children: [],
+ name: 'menu_' + item.resid,
+ meta: { title: item.resname, id: item.resid, roles: ['admin'], icon: item.icon }
+ }
+ if (item.children) {
+ generaMenu(menu.children, item.children)
+ }
+ routes.push(menu)
+ })
+}
+
+/**
* Filter asynchronous routing tables by recursion
* @param routes asyncRoutes
* @param roles
@@ -49,14 +73,26 @@
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
- let accessedRoutes
- if (roles.includes('admin')) {
- accessedRoutes = asyncRoutes || []
- } else {
- accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
- }
- commit('SET_ROUTES', accessedRoutes)
- resolve(accessedRoutes)
+ const loadMenuData = []
+ // 先查询后台并返回左侧菜单数据并把数据添加到路由
+ getAuthMenu(state.token).then(response => {
+ 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)
+ }
+ commit('SET_ROUTES', accessedRoutes)
+ resolve(accessedRoutes)
+
+ // generaMenu(asyncRoutes, data)
+ }).catch(error => {
+ console.log(error)
+ })
})
}
}
diff --git a/frontend/src/store/modules/user.js b/frontend/src/store/modules/user.js
index 7800941..b8348bf 100644
--- a/frontend/src/store/modules/user.js
+++ b/frontend/src/store/modules/user.js
@@ -7,7 +7,8 @@
name: '',
avatar: '',
introduction: '',
- roles: []
+ roles: [],
+ url: ''
}
const mutations = {
@@ -25,6 +26,9 @@
},
SET_ROLES: (state, roles) => {
state.roles = roles
+ },
+ SET_URL: (state, url) => {
+ state.url = url
}
}
@@ -33,8 +37,7 @@
login({ commit }, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
- login({ username: username.trim(), password: password }).then(response => {
- const { data } = response
+ login({ username: username.trim(), password: password }).then(data => {
commit('SET_TOKEN', data.token)
setToken(data.token)
resolve()
@@ -51,20 +54,13 @@
const { data } = response
if (!data) {
- reject('Verification failed, please Login again.')
+ reject('认证失败,请稍后重试')
}
- const { roles, name, avatar, introduction } = data
-
- // roles must be a non-empty array
- if (!roles || roles.length <= 0) {
- reject('getInfo: roles must be a non-null array!')
- }
-
+ const { name, roles, url } = data
commit('SET_ROLES', roles)
commit('SET_NAME', name)
- commit('SET_AVATAR', avatar)
- commit('SET_INTRODUCTION', introduction)
+ commit('SET_URL', url + '/')
resolve(data)
}).catch(error => {
reject(error)
@@ -78,6 +74,7 @@
logout(state.token).then(() => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
+ commit('SET_URL', '')
removeToken()
resetRouter()
@@ -97,6 +94,7 @@
return new Promise(resolve => {
commit('SET_TOKEN', '')
commit('SET_ROLES', [])
+ commit('SET_URL', '')
removeToken()
resolve()
})
diff --git a/frontend/src/utils/request.js b/frontend/src/utils/request.js
index 2fb95ac..7288f82 100644
--- a/frontend/src/utils/request.js
+++ b/frontend/src/utils/request.js
@@ -1,5 +1,6 @@
import axios from 'axios'
-import { MessageBox, Message } from 'element-ui'
+import { Message } from 'element-ui'
+import router from '@/router'
import store from '@/store'
import { getToken } from '@/utils/auth'
@@ -19,7 +20,7 @@
// let each request carry token
// ['X-Token'] is a custom headers key
// please modify it according to the actual situation
- config.headers['X-Token'] = getToken()
+ config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
},
@@ -44,41 +45,24 @@
*/
response => {
const res = response.data
-
// if the custom code is not 20000, it is judged as an error.
- if (res.code !== 20000) {
- Message({
- message: res.message || 'Error',
- type: 'error',
- duration: 5 * 1000
- })
-
- // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
- if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
- // to re-login
- MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {
- confirmButtonText: 'Re-Login',
- cancelButtonText: 'Cancel',
- type: 'warning'
- }).then(() => {
- store.dispatch('user/resetToken').then(() => {
- location.reload()
- })
- })
- }
- return Promise.reject(new Error(res.message || 'Error'))
- } else {
+ if (res.code === 200) {
return res
+ } else {
+ return Promise.reject(res || 'Error')
}
},
error => {
- console.log('err' + error) // for debug
- Message({
- message: error.message,
- type: 'error',
- duration: 5 * 1000
- })
- return Promise.reject(error)
+ if (error.response.status === 401) {
+ Message({
+ message: '当前登录信息已过期,请重新登录',
+ type: 'error',
+ duration: 5 * 1000
+ })
+ router.push(`/login`)
+ } else {
+ return Promise.reject(error)
+ }
}
)
diff --git a/frontend/src/views/feedback/index.vue b/frontend/src/views/feedback/index.vue
new file mode 100644
index 0000000..125e87f
--- /dev/null
+++ b/frontend/src/views/feedback/index.vue
@@ -0,0 +1,451 @@
+<template>
+ <div class="app-container">
+ <div class="filter-container">
+ <div class="filter-item" style="margin-right:15px">留言用户</div>
+ <el-input
+ v-model="formData.username"
+ placeholder="用户名"
+ style="width: 350px;margin-right:50px"
+ class="filter-item"
+ />
+ <div class="filter-item" style="margin-right:15px">留言内容</div>
+ <el-input
+ v-model="formData.content"
+ placeholder="留言关键字"
+ style="width: 300px;margin-right:50px"
+ class="filter-item"
+ />
+ </div>
+ <div class="filter-container">
+ <div class="filter-item" style="margin-right:15px">留言日期</div>
+ <el-date-picker
+ v-model="queryDate"
+ type="daterange"
+ align="left"
+ style="width:350px;margin-right:50px"
+ unlink-panels
+ range-separator="至"
+ start-placeholder="开始日期"
+ end-placeholder="结束日期"
+ value-format="yyyyMMdd"
+ :picker-options="pickerOptions"
+ />
+ <div class="filter-item" style="margin-right:15px">留言状态</div>
+ <el-select
+ v-model="formData.replystatus"
+ style="width:200px;margin-right:100px"
+ >
+ <el-option
+ v-for="item in statusOptions"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ <el-button
+ class="filter-item"
+ type="primary"
+ icon="el-icon-search"
+ @click="handleFilter()"
+ >
+ 搜索
+ </el-button>
+ <el-button class="filter-item" type="info" @click="clearFilter">
+ 清空
+ </el-button>
+ </div>
+ <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.username }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="留言内容" align="center">
+ <template slot-scope="{row}">
+ <span>{{ row.content }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="状态" align="center" width="100">
+ <template slot-scope="{row}">
+ <el-tag v-if="row.replystatus==='0'" size="medium">待回复</el-tag>
+ <el-tag v-else type="success" size="medium">已回复</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column label="留言时间" align="center" width="160">
+ <template slot-scope="{row}">
+ <span>{{ dateFormat(row.fbtime) }}</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 icon="el-icon-search" circle size="mini" @click="openDetailDialog(row)" />
+ </el-tooltip>
+ <el-tooltip class="item" effect="dark" content="回复" placement="bottom">
+ <el-button type="primary" icon="el-icon-edit" circle size="mini" @click="openReplyDialog(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="getFeedbackList"
+ />
+
+ <el-dialog
+ title="留言详情"
+ :visible.sync="detailDialogVisible"
+ width="60%"
+ top="5vh"
+ >
+ <el-table
+ :data="detailContent"
+ border
+ fit
+ :span-method="mergeCells"
+ style="width: 100%"
+ :header-cell-style="{background:'white'}"
+ >
+ <el-table-column align="center">
+ <template slot="header" slot-scope="{}">
+ <span>当前留言状态:
+ <span v-if="currentFeedback.replystatus === '0'" style="color:#409EFF">待回复</span>
+ <span v-else style="color:#67C23A">已回复</span>
+ </span>
+ </template>
+ <el-table-column label="留言用户" align="center" width="120px">
+ <template slot-scope="{row}">
+ <span style="font-weight:bold;color:#909399">{{ row.title }}</span>
+ </template>
+ </el-table-column>
+ <el-table-column>
+ <template slot="header" slot-scope="{}">
+ <span style="font-weight: normal;color:#606266">{{ currentFeedback.username }}</span>
+ </template>
+ <template slot-scope="{row}">
+ <div style="position:relative">
+ <div style="height:120px">{{ row.content }}</div>
+ <el-divider
+ v-if="row.pictures && row.pictures.length!==0"
+ style="margin:10px 0"
+ />
+ <div>
+ <el-image
+ v-for="(picture) in row.pictures"
+ :key="picture.annexid"
+ style="width: 100px; height: 100px;margin-left:10px"
+ :src="picture.path"
+ :preview-src-list="picture.previewList"
+ fit="cover"
+ >
+ <div
+ slot="error"
+ style="text-align:center;
+ vertical-align:middle;
+ font-size:20px;
+ padding-top:37px;
+ width:100%;height:100%;background-color:#f4f7fa"
+ >
+ <i size="medium" class="el-icon-picture-outline" />
+ </div>
+ </el-image>
+ </div>
+ <div style="color:#909399;position:absolute;right:0;bottom:0;">{{ row.time }}</div>
+ </div>
+ </template>
+ </el-table-column>
+ <el-table-column label="提交IP" align="center" />
+ <el-table-column>
+ <template slot="header" slot-scope="{}">
+ <span style="font-weight: normal;color:#606266">{{ currentFeedback.fbip }}</span>
+ </template>
+
+ </el-table-column>
+ </el-table-column>
+ </el-table>
+ </el-dialog>
+
+ <el-dialog
+ title="留言回复"
+ :visible.sync="replyDialogVisible"
+ width="45%"
+ >
+ <div>
+ <div class="filter-container">
+ <div class="filter-item" style="margin:10px 15px 0 0;vertical-align:top">回复内容</div>
+ <el-input
+ v-model="currentreply.replycontent"
+ :placeholder="'回复'+currentFeedback.username+':'"
+ :rows="7"
+ class="filter-item"
+ style="width:80%;"
+ type="textarea"
+ maxlength="180"
+ show-word-limit
+ />
+ </div>
+ <div style="text-align:center">
+ <el-button type="primary" @click="saveReply">保存</el-button>
+ <el-button @click="replyDialogVisible=false">取消</el-button>
+ </div>
+
+ </div>
+ </el-dialog>
+ </div>
+</template>
+<script>
+import {
+ getFeedbackList,
+ getFeedbackReply,
+ saveFeedbackReply
+} from '@/api/feedback'
+import moment from 'moment'
+import user from '@/store/modules/user'
+import Pagination from '@/components/Pagination'
+
+export default {
+ name: 'Feedback',
+ components: {
+ Pagination
+ },
+ data() {
+ return {
+ imageUrl: '',
+ imageList: [],
+ textarea: '',
+ listLoading: false,
+ tableKey: 0,
+ list: null,
+ currentFeedback: { username: '' },
+ detailContent: [
+ {
+ title: '留言内容',
+ content: '',
+ time: '',
+ pictures: []
+ },
+ {
+ title: '回复内容',
+ content: '',
+ time: ''
+ }
+ ],
+ total: 0,
+ detailDialogVisible: false,
+ replyDialogVisible: false,
+ queryDate: null,
+ formData: {
+ username: '',
+ content: '',
+ replystatus: '',
+ startdate: '',
+ enddate: '',
+ pageno: 1,
+ pagesize: 10
+ },
+ currentreply: {
+ replycontent: ''
+ },
+ statusOptions: [{
+ value: '',
+ label: '所有'
+ },
+ {
+ value: '0',
+ label: '待回复'
+ }, {
+ value: '1',
+ label: '已回复'
+ }],
+ pickerOptions: {
+ shortcuts: [{
+ text: '今天',
+ onClick(picker) {
+ const end = new Date()
+ const start = new Date()
+ picker.$emit('pick', [start, end])
+ }
+ }, {
+ text: '最近三天',
+ onClick(picker) {
+ const end = new Date()
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 3)
+ picker.$emit('pick', [start, end])
+ }
+ }, {
+ text: '最近一周',
+ onClick(picker) {
+ const end = new Date()
+ const start = new Date()
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+ picker.$emit('pick', [start, end])
+ }
+ }]
+ }
+ }
+ },
+ created() {
+ this.imageUrl = user.state.url
+ this.getFeedbackList()
+ },
+ methods: {
+ getFeedbackList() {
+ this.listLoading = true
+ const date = this.queryDate
+ if (date != null) {
+ this.formData.startdate = date[0]
+ this.formData.enddate = date[1]
+ } else {
+ this.formData.startdate = ''
+ this.formData.enddate = ''
+ }
+ getFeedbackList(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
+ })
+ },
+ handleFilter() {
+ this.formData.pageno = 1
+ this.getFeedbackList()
+ },
+ clearFilter() {
+ this.formData.username = ''
+ this.formData.content = ''
+ this.formData.replystatus = ''
+ this.queryDate = null
+ },
+ dateFormat(date) {
+ if (date === null) {
+ return ''
+ }
+ return moment(date, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss')
+ },
+ openDetailDialog(row) {
+ this.currentFeedback = row
+ const list = []
+ const previewList = []
+ for (let i = 0; i < row.pictures.length; i++) {
+ const item = {}
+ item.path = this.imageUrl + row.pictures[i].minpicid
+ list.push(item)
+ previewList.push(this.imageUrl + row.pictures[i].picid)
+ }
+ // 根据图片顺序(index)更改每张图片绑定的list的图片顺序
+ for (let i = 0; i < row.pictures.length; i++) {
+ const container = previewList
+ const frontArr = container.slice(0, i)
+ const behindArr = container.slice(i, row.pictures.length)
+ const concatList = behindArr.concat(frontArr)
+ list[i].previewList = concatList
+ }
+ const feedbackContent = {
+ title: '留言内容',
+ content: row.content,
+ time: row.fbtime === null ? '' : moment(row.fbtime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss'),
+ pictures: list
+ }
+
+ this.$set(this.detailContent, 0, feedbackContent)
+
+ getFeedbackReply(row.fbid).then(response => {
+ let reply = {
+ replycontent: '',
+ updatetime: null
+ }
+ if (response.list) {
+ reply = response.list[0]
+ }
+ const replyContent = {
+ title: '回复内容',
+ content: reply.replycontent,
+ time: reply.updatetime === null ? '' : moment(reply.updatetime, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss')
+ }
+ this.$set(this.detailContent, 1, replyContent)
+ this.detailDialogVisible = true
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ },
+ openReplyDialog(row) {
+ this.currentFeedback = row
+ this.currentreply = {
+ replycontent: '',
+ fbid: row.fbid,
+ replyid: null
+ }
+ getFeedbackReply(row.fbid).then(response => {
+ if (response.list) {
+ this.currentreply = response.list[0]
+ }
+ this.replyDialogVisible = true
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ },
+ saveReply() {
+ if (this.currentreply.replycontent === '') {
+ this.$message('请输入回复内容')
+ return
+ }
+ saveFeedbackReply(this.currentreply).then(response => {
+ this.$notify({
+ title: '成功',
+ message: '回复留言成功!',
+ type: 'success',
+ duration: 2000
+ })
+ this.replyDialogVisible = false
+ this.getFeedbackList()
+ }).catch(error => {
+ this.$message({
+ message: error.msg || '请求异常',
+ type: 'error'
+ })
+ })
+ },
+ mergeCells({ row, column, rowIndex, columnIndex }) {
+ if (columnIndex === 1) {
+ if (rowIndex === 0) {
+ return [1, 3]
+ } else {
+ return [2, 3]
+ }
+ }
+ }
+ }
+}
+
+</script>
+
diff --git a/frontend/src/views/login/index.vue b/frontend/src/views/login/index.vue
index 2590640..2abcff9 100644
--- a/frontend/src/views/login/index.vue
+++ b/frontend/src/views/login/index.vue
@@ -45,7 +45,7 @@
</el-form-item>
</el-tooltip>
- <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click.native.prevent="handleLogin">Login</el-button>
+ <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">
@@ -74,7 +74,6 @@
</template>
<script>
-import { validUsername } from '@/utils/validate'
import SocialSign from './components/SocialSignin'
export default {
@@ -82,11 +81,7 @@
components: { SocialSign },
data() {
const validateUsername = (rule, value, callback) => {
- if (!validUsername(value)) {
- callback(new Error('Please enter the correct user name'))
- } else {
- callback()
- }
+ callback()
}
const validatePassword = (rule, value, callback) => {
if (value.length < 6) {
@@ -97,8 +92,8 @@
}
return {
loginForm: {
- username: 'admin',
- password: '111111'
+ username: 'system',
+ password: '123456'
},
loginRules: {
username: [{ required: true, trigger: 'blur', validator: validateUsername }],
@@ -156,12 +151,16 @@
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
- this.$store.dispatch('user/login', this.loginForm)
+ this.$store.dispatch('user/login', { 'username': this.loginForm.username, 'password': this.loginForm.password })
.then(() => {
this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
this.loading = false
})
- .catch(() => {
+ .catch((response) => {
+ this.$message({
+ message: response.msg || '请求异常',
+ type: 'error'
+ })
this.loading = false
})
} else {
diff --git a/frontend/src/views/operator/index.vue b/frontend/src/views/operator/index.vue
new file mode 100644
index 0000000..5956c3f
--- /dev/null
+++ b/frontend/src/views/operator/index.vue
@@ -0,0 +1,9 @@
+
+<template>
+ <div class="app-container" /></template>
+<script>
+export default {
+ name: 'Operator'
+}
+</script>
+
diff --git a/frontend/src/views/pushmsg/index.vue b/frontend/src/views/pushmsg/index.vue
new file mode 100644
index 0000000..cd8e058
--- /dev/null
+++ b/frontend/src/views/pushmsg/index.vue
@@ -0,0 +1,8 @@
+<template>
+ <div>消息推送</div>
+</template>
+<script>
+export default {
+ name: 'PushMsg'
+}
+</script>
diff --git a/frontend/vue.config.js b/frontend/vue.config.js
index 33a6348..dfe2483 100644
--- a/frontend/vue.config.js
+++ b/frontend/vue.config.js
@@ -24,7 +24,7 @@
* In most cases please use '/' !!!
* Detail: https://cli.vuejs.org/config/#publicpath
*/
- publicPath: '/',
+ publicPath: '/portal',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
@@ -36,7 +36,15 @@
warnings: false,
errors: true
},
- before: require('./mock/mock-server.js')
+ proxy: {
+ [process.env.VUE_APP_BASE_API]: {
+ target: process.env.VUE_APP_BASE_API,
+ changeOrigin: true, // 配置跨域
+ pathRewrite: {
+ ['^' + process.env.VUE_APP_BASE_API]: ''
+ }
+ }
+ }
},
configureWebpack: {
// provide the app's title in webpack's name field, so that