增加问答功能
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
index 6386838..d48d9ef 100644
--- 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
@@ -34,7 +34,7 @@
 		setTotalCount(totalCount);
 		setPageSize(pageSize);
 		setPageNo(pageNo);
-		adjustPageNo();
+//		adjustPageNo();
 	}
 
 	/**
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/AdvisoryRepositoryImpl.java b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/AdvisoryRepositoryImpl.java
new file mode 100644
index 0000000..c16ab64
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/AdvisoryRepositoryImpl.java
@@ -0,0 +1,46 @@
+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.AdvisorySearchBean;
+import com.supwisdom.dlpay.portal.dao.AdvisoryRepository;
+import com.supwisdom.dlpay.portal.domain.TBAdvisory;
+import org.hibernate.transform.Transformers;
+import org.jetbrains.annotations.NotNull;
+
+public class AdvisoryRepositoryImpl extends BaseRepository implements AdvisoryRepository {
+  @NotNull
+  @Override
+  public Pagination getAdvisoryList(@NotNull AdvisorySearchBean bean) {
+    String title = bean.getTitle();
+    String content = bean.getContent();
+    int pageno = bean.getPageno();
+    int pagesize = bean.getPagesize();
+    StringBuilder sql = new StringBuilder("select * from tb_advisory where 1=1");
+    if (!StringUtil.isEmpty(title)) {
+      sql.append(" and title like :title");
+    }
+    if (!StringUtil.isEmpty(content)) {
+      sql.append(" and content like :content");
+    }
+    sql.append(" order by ordernum");
+    Finder f = Finder.create(sql.toString());
+    if (!StringUtil.isEmpty(title)) {
+      f.setParameter("title", "%" + title.trim() + "%");
+    }
+    if (!StringUtil.isEmpty(content)) {
+      f.setParameter("content", "%" + content.trim() + "%");
+    }
+    return findNative(f, Transformers.aliasToBean(TBAdvisory.class), pageno, pagesize);
+  }
+
+  @NotNull
+  @Override
+  public Pagination getMobileAdvisoryList(int pageno, int pagesize) {
+    String sql = "select * from tb_advisory where isdisplay='1' order by ordernum ";
+    Finder f = Finder.create(sql);
+    return findNative(f, Transformers.aliasToBean(TBAdvisory.class), pageno, pagesize);
+  }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/ArticleRepositoryImpl.java b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/ArticleRepositoryImpl.java
index 1fc7264..8d46a80 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/ArticleRepositoryImpl.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/dao/impl/ArticleRepositoryImpl.java
@@ -78,10 +78,10 @@
   @NotNull
   @Override
   @SuppressWarnings("unchecked")
-  public List<TBArticle> getArticleListByColumnid(@NotNull String columnid,int pageno, int pagesize) {
+  public Pagination getArticleListByColumnid(@NotNull String columnid,int pageno, int pagesize) {
     String sql = "select * from tb_article where isdelete='0' and isdisplay='1' and status='released' and columnid =:columnid order by releasetime desc";
     Finder f = Finder.create(sql);
     f.setParameter("columnid", columnid);
-    return (List<TBArticle>) findNative(f, Transformers.aliasToBean(TBArticle.class), pageno, pagesize).getList();
+    return findNative(f, Transformers.aliasToBean(TBArticle.class), pageno, pagesize);
   }
 }
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAdvisory.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAdvisory.java
new file mode 100644
index 0000000..7bae93d
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBAdvisory.java
@@ -0,0 +1,86 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_advisory", indexes = {
+    @Index(name = "advisory_idx", columnList = "title")
+})
+public class TBAdvisory {
+  @Id
+  @GenericGenerator(name = "idGenerator", strategy = "uuid")
+  @GeneratedValue(generator = "idGenerator")
+  @Column(name = "advisoryid", nullable = false, length = 32)
+  private String advisoryid;
+  @Column(name = "title", length = 30)
+  private String title;
+  @Column(name = "content", length = 250)
+  private String content;
+  @Column(name = "operid", length = 32)
+  private String operid;
+  @Column(name = "updatetime", length = 14)
+  private String updatetime;
+  @Column(name = "ordernum")
+  private Integer ordernum;
+  @Column(name = "isdisplay", length = 1)
+  private String isdisplay;
+
+
+  public String getAdvisoryid() {
+    return advisoryid;
+  }
+
+  public void setAdvisoryid(String advisoryid) {
+    this.advisoryid = advisoryid;
+  }
+
+  public String getTitle() {
+    return title;
+  }
+
+  public void setTitle(String title) {
+    this.title = title;
+  }
+
+  public String getContent() {
+    return content;
+  }
+
+  public void setContent(String content) {
+    this.content = content;
+  }
+
+  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 Integer getOrdernum() {
+    return ordernum;
+  }
+
+  public void setOrdernum(Integer ordernum) {
+    this.ordernum = ordernum;
+  }
+
+  public String getIsdisplay() {
+    return isdisplay;
+  }
+
+  public void setIsdisplay(String isdisplay) {
+    this.isdisplay = isdisplay;
+  }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBColumn.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBColumn.java
index 2e9d3ae..5171ce5 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBColumn.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBColumn.java
@@ -1,5 +1,6 @@
 package com.supwisdom.dlpay.portal.domain;
 
+import com.supwisdom.dlpay.framework.jpa.page.Pagination;
 import org.hibernate.annotations.GenericGenerator;
 
 import javax.persistence.*;
@@ -51,7 +52,7 @@
   private String parentname;
 
   @Transient
-  private List<TBArticle> articles;
+  private Pagination articles;
 
   public String getColumnid() {
     return columnid;
@@ -133,11 +134,11 @@
     this.ordernum = ordernum;
   }
 
-  public List<TBArticle> getArticles() {
+  public Pagination getArticles() {
     return articles;
   }
 
-  public void setArticles(List<TBArticle> articles) {
+  public void setArticles(Pagination articles) {
     this.articles = articles;
   }
 }
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
index 64665f8..8f0983b 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/mobile/MobileApi.kt
@@ -22,6 +22,7 @@
 import com.supwisdom.dlpay.paysdk.proxy.UserProxy
 import com.supwisdom.dlpay.portal.bean.FeedbackSearchBean
 import com.supwisdom.dlpay.portal.domain.TBFeedback
+import com.supwisdom.dlpay.portal.service.AdvisoryService
 import com.supwisdom.dlpay.portal.service.ArticleService
 import com.supwisdom.dlpay.portal.service.ColumnService
 import com.supwisdom.dlpay.portal.service.FeedbackService
@@ -69,6 +70,8 @@
     lateinit var articleService: ArticleService
     @Autowired
     lateinit var userProxy: UserProxy
+    @Autowired
+    lateinit var advisoryService: AdvisoryService
     val logger = KotlinLogging.logger { }
 
     @RequestMapping("/time")
@@ -315,6 +318,24 @@
         }
     }
 
+    /**
+     * 获取咨询问答
+     */
+    @RequestMapping("/advisory/list")
+    fun getActivity(@RequestHeader("Authorization") auth: String?,
+                   pageno:Int,pagesize:Int): JsonResult? {
+        try {
+            val page = advisoryService.getMobileAdvisoryList(pageno, pagesize)
+            return JsonResult.ok().put("data", page)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            if (e is PortalBusinessException) {
+                return JsonResult.error(e.message)
+            }
+            return JsonResult.error("服务器繁忙,请稍后重试")
+        }
+    }
+
     fun judgeLoginMode(auth: String?): String {
         var mode = "tourist"
         if (auth != null) {
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 a7ef28b..eaa5fe7 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
@@ -10,14 +10,8 @@
 import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.mobile.exception.PortalBusinessException
 import com.supwisdom.dlpay.portal.bean.*
-import com.supwisdom.dlpay.portal.domain.TBArticle
-import com.supwisdom.dlpay.portal.domain.TBColumn
-import com.supwisdom.dlpay.portal.domain.TBMsgTemplate
-import com.supwisdom.dlpay.portal.domain.TBReply
-import com.supwisdom.dlpay.portal.service.ArticleService
-import com.supwisdom.dlpay.portal.service.ColumnService
-import com.supwisdom.dlpay.portal.service.FeedbackService
-import com.supwisdom.dlpay.portal.service.MsgService
+import com.supwisdom.dlpay.portal.domain.*
+import com.supwisdom.dlpay.portal.service.*
 import com.supwisdom.dlpay.portal.util.PortalConstant
 import mu.KotlinLogging
 import org.jose4j.jwt.ReservedClaimNames
@@ -50,6 +44,8 @@
     lateinit var columnService: ColumnService
     @Autowired
     lateinit var uploadPicService: UploadPicService
+    @Autowired
+    lateinit var advisoryService: AdvisoryService
     val logger = KotlinLogging.logger { }
 
     @RequestMapping("/test")
@@ -189,7 +185,10 @@
     @RequestMapping(value = ["/article/uploadpic"], method = [RequestMethod.POST])
     fun uploadPic(request: MultipartHttpServletRequest): JsonResult? {
         val map = uploadPicService.uploadPic(request)
-        return JsonResult.ok()
+        if (map["retcode"] == "1") {
+            return JsonResult.error("图片上传失败!")
+        }
+        return JsonResult.ok().put("data",map)
     }
 
     @RequestMapping("/column/all")
@@ -255,18 +254,18 @@
 
     @RequestMapping(value = ["/article/release"], method = [RequestMethod.POST])
     fun releaseArticle(@RequestBody article: TBArticle): JsonResult? {
-         try {
+        try {
             val p = SecurityContextHolder.getContext().authentication
             val oper = operatorDetailService.findByOperid(p.name)
             article.operid = oper.operid
             articleService.releaseArticle(article)
-             return JsonResult.ok()
+            return JsonResult.ok()
         } catch (e: Exception) {
             logger.error { e.message }
             if (e is PortalBusinessException) {
                 return JsonResult.error(e.message)
             }
-             return JsonResult.error("发布文章异常")
+            return JsonResult.error("发布文章异常")
         }
     }
 
@@ -276,7 +275,7 @@
             val p = SecurityContextHolder.getContext().authentication
             val oper = operatorDetailService.findByOperid(p.name)
             article.operid = oper.operid
-            articleService.reviewArticle(article,oper.opername)
+            articleService.reviewArticle(article, oper.opername)
             JsonResult.ok()
         } catch (e: Exception) {
             logger.error { e.message }
@@ -331,4 +330,55 @@
             JsonResult.error("切换文章是否显示异常")
         }
     }
+
+    @RequestMapping(value = ["/advisory/save"], method = [RequestMethod.POST])
+    fun saveAdvisory(@RequestBody advisory: TBAdvisory): JsonResult? {
+        return try {
+            val p = SecurityContextHolder.getContext().authentication
+            val oper = operatorDetailService.findByOperid(p.name)
+            advisory.operid = oper.operid
+            advisoryService.saveAdvisory(advisory)
+            JsonResult.ok()
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("保存问答异常")
+        }
+    }
+
+    @RequestMapping(value = ["/advisory/list"], method = [RequestMethod.GET])
+    fun getAdvisoryList(bean: AdvisorySearchBean): JsonResult? {
+        return try {
+            val page = advisoryService.getAdvisoryList(bean)
+            if (page.list == null || page.list.size == 0) {
+                return JsonResult.ok().put("msg", "无数据")
+            }
+            return JsonResult.ok().put("page", page)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("查询咨询问答列表异常")
+        }
+    }
+
+    @RequestMapping(value = ["/advisory/switchdisplay/{advisoryid}"], method = [RequestMethod.POST])
+    fun switchAdvisoryDisplay(@PathVariable(value = "advisoryid") advisoryid: String,
+                      @RequestParam(value = "value") value: String): JsonResult? {
+        return try {
+            val result = advisoryService.switchDisplay(advisoryid, value)
+            JsonResult.ok().put("result", result)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("切换问答是否显示异常")
+        }
+    }
+
+    @RequestMapping(value = ["/advisory/delete/{advisoryid}"], method = [RequestMethod.POST])
+    fun deleteAdvisory(@PathVariable(value = "advisoryid") advisoryid: String): JsonResult? {
+        return try {
+            advisoryService.deleteAdvisory(advisoryid)
+            JsonResult.ok()
+        } 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/AdvisorySearchBean.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/AdvisorySearchBean.kt
new file mode 100644
index 0000000..6432370
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/bean/AdvisorySearchBean.kt
@@ -0,0 +1,8 @@
+package com.supwisdom.dlpay.portal.bean
+
+class AdvisorySearchBean {
+    var title: String = ""
+    var content: String = ""
+    var pageno: Int = 1
+    var pagesize: Int = 10
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryDao.kt
new file mode 100644
index 0000000..a1c0c9a
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryDao.kt
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBAdvisory
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface AdvisoryDao : JpaRepository<TBAdvisory, String>,AdvisoryRepository{
+
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryRepository.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryRepository.kt
new file mode 100644
index 0000000..cfd40a2
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/AdvisoryRepository.kt
@@ -0,0 +1,9 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.portal.bean.AdvisorySearchBean
+
+interface AdvisoryRepository {
+    fun getAdvisoryList(bean: AdvisorySearchBean): Pagination
+    fun getMobileAdvisoryList(pageno: Int, pagesize: Int): Pagination
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleRepository.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleRepository.kt
index a1379da..f7cf0b6 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleRepository.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleRepository.kt
@@ -9,5 +9,5 @@
     @Throws(ParseException::class)
     fun getArticleList(bean: ArticleSearchBean): Pagination
 
-    fun getArticleListByColumnid(columnid: String, pageno: Int, pagesize: Int): List<TBArticle>
+    fun getArticleListByColumnid(columnid: String, pageno: Int, pagesize: Int): Pagination
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/AdvisoryService.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/AdvisoryService.kt
new file mode 100644
index 0000000..832a6ba
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/AdvisoryService.kt
@@ -0,0 +1,19 @@
+package com.supwisdom.dlpay.portal.service
+
+import com.supwisdom.dlpay.framework.jpa.page.Pagination
+import com.supwisdom.dlpay.portal.bean.AdvisorySearchBean
+import com.supwisdom.dlpay.portal.domain.TBAdvisory
+import org.springframework.transaction.annotation.Transactional
+
+interface AdvisoryService {
+    @Transactional
+    fun saveAdvisory(advisory:TBAdvisory)
+    @Transactional
+    fun getAdvisoryList(bean: AdvisorySearchBean): Pagination
+    @Transactional
+    fun switchDisplay(advisoryid:String,value:String):String
+    @Transactional
+    fun deleteAdvisory(advisoryid:String)
+    @Transactional
+    fun getMobileAdvisoryList(pageno:Int,pagesize:Int): Pagination
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/AdvisoryServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/AdvisoryServiceImpl.kt
new file mode 100644
index 0000000..2e72d93
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/AdvisoryServiceImpl.kt
@@ -0,0 +1,54 @@
+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.portal.bean.AdvisorySearchBean
+import com.supwisdom.dlpay.portal.dao.AdvisoryDao
+import com.supwisdom.dlpay.portal.domain.TBAdvisory
+import com.supwisdom.dlpay.portal.service.AdvisoryService
+import com.supwisdom.dlpay.portal.util.PortalConstant
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.stereotype.Service
+
+@Service
+class AdvisoryServiceImpl : AdvisoryService{
+    @Autowired
+    lateinit var systemUtilService: SystemUtilService
+    @Autowired
+    lateinit var advisoryDao: AdvisoryDao
+
+    override fun saveAdvisory(advisory: TBAdvisory) {
+        advisory.updatetime = systemUtilService.sysdatetime.hostdatetime
+        advisory.isdisplay = PortalConstant.YES
+        advisoryDao.save(advisory)
+    }
+
+    override fun getAdvisoryList(bean: AdvisorySearchBean): Pagination {
+        return advisoryDao.getAdvisoryList(bean)
+    }
+
+    override fun switchDisplay(advisoryid: String, value: String): String {
+        val optional = advisoryDao.findById(advisoryid)
+        if (optional.isPresent) {
+            val advisory = optional.get()
+            advisory.isdisplay = value
+            advisoryDao.save(advisory)
+            return advisory.isdisplay
+        }else{
+            throw RuntimeException("ID为:[${advisoryid}]的问答未找到")
+        }
+    }
+
+    override fun deleteAdvisory(advisoryid: String) {
+        val optional = advisoryDao.findById(advisoryid)
+        if (optional.isPresent) {
+            advisoryDao.delete(optional.get())
+        }else{
+            throw RuntimeException("ID为:[${advisoryid}]的问答未找到")
+        }
+    }
+
+    override fun getMobileAdvisoryList(pageno: Int, pagesize: Int): Pagination {
+        return advisoryDao.getMobileAdvisoryList(pageno,pagesize)
+    }
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/MsgServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/MsgServiceImpl.kt
index 0c59f94..50af7e3 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/MsgServiceImpl.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/MsgServiceImpl.kt
@@ -3,7 +3,6 @@
 import com.supwisdom.dlpay.api.service.KafkaSendMsgService
 import com.supwisdom.dlpay.framework.jpa.page.Pagination
 import com.supwisdom.dlpay.framework.service.SystemUtilService
-import com.supwisdom.dlpay.mobile.dao.MsgDao
 import com.supwisdom.dlpay.portal.bean.MsgTemplateSearchBean
 import com.supwisdom.dlpay.portal.bean.SendMsgBean
 import com.supwisdom.dlpay.portal.dao.MsgTemplateDao
@@ -11,7 +10,6 @@
 import com.supwisdom.dlpay.portal.service.MsgService
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
-import java.lang.RuntimeException
 import java.util.regex.Pattern
 
 @Service
@@ -19,8 +17,6 @@
     @Autowired
     lateinit var msgTemplateDao: MsgTemplateDao
     @Autowired
-    lateinit var msgDao: MsgDao
-    @Autowired
     lateinit var systemUtilService: SystemUtilService
     @Autowired
     lateinit var kafkaSendMsgService: KafkaSendMsgService
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
index e1d5a1f..b993822 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/security.kt
@@ -7,6 +7,7 @@
 import com.supwisdom.dlpay.framework.service.OperatorDetailService
 import com.supwisdom.dlpay.framework.tenant.TenantContext
 import com.supwisdom.dlpay.framework.util.Constants
+import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.framework.util.TradeDict
 import com.supwisdom.dlpay.mobile.AuthLoginFailHandler
 import com.supwisdom.dlpay.mobile.AuthLoginSuccessHandler
@@ -156,7 +157,8 @@
             url = url.replace(context, "")
         }
         logger.info(url)
-        request.getHeader(jwtConfig.header)?.let { authHeader ->
+        val authHeader:String? = request.getHeader(jwtConfig.header)
+        if (!authHeader.isNullOrEmpty()) {
             try {
                 val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
                     authHeader.substring(jwtConfig.tokenHeader.length)
@@ -250,7 +252,8 @@
             url = url.replace(context, "")
         }
         logger.info(url)
-        request.getHeader(jwtConfig.header)?.let { authHeader ->
+        val authHeader:String? = request.getHeader(jwtConfig.header)
+        if(!authHeader.isNullOrEmpty()) {
             try {
                 val jwt = if (authHeader.startsWith(jwtConfig.tokenHeader)) {
                     authHeader.substring(jwtConfig.tokenHeader.length)
diff --git a/backend/src/main/resources/data-postgresql.sql b/backend/src/main/resources/data-postgresql.sql
index 1a98333..bc0b484 100644
--- a/backend/src/main/resources/data-postgresql.sql
+++ b/backend/src/main/resources/data-postgresql.sql
@@ -14,8 +14,11 @@
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('sms.url', 'http://112.35.4.197:15000', '{tenantid}');
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('sms.pwd', 'kingstar#2019', '{tenantid}');
 INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('article.currentno', '1', '{tenentid}');
-INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.appid', '700001', '{tenentid}');
-INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.secret', '5f788ce433ec44f299351cdf7f137e81', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.appid', '800001', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('portal.secret', '1a8905a272364ef592e61f4a1288f07d', '{tenentid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('aes.cfb.totp.offset', '20', '{tenantid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('aes.cfb.rootkey', 'Vbb1syh8U1+CdLmTVGdtDiVvKBQ81n4GmgBEO/ohSbU=', '{tenantid}');
+INSERT INTO "tb_businesspara"("parakey", "paraval", "tenantid") VALUES ('aes.cfb.iv', '55b6f5b3287c535f8274b99354676d0e', '{tenantid}');
 
 INSERT INTO "tb_column"("columnid", "isleaf", "name", "needreview", "parentid", "code", "ispublic", "publishable", "ordernum") VALUES ('2c9cab947451988c017451a737b10000', '0', '线上活动', '0', '', 'OnlineActivities', '1', '1', 12);
 INSERT INTO "tb_column"("columnid", "isleaf", "name", "needreview", "parentid", "code", "ispublic", "publishable", "ordernum") VALUES ('2c9cab947451988c017451b280870001', '0', '线下活动', '0', '', 'OfflineActivities', '1', '1', 13);
@@ -28,6 +31,8 @@
 INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('81d3556981c34633adadb0fc4dc8d1f3', '1', 4, 'f066939ecbf64da3a54fa93d56e4391b', '栏目管理', '/column/index', '1', NULL);
 INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('99604b8d18b34417befe051a3720cbed', '1', 6, 'f066939ecbf64da3a54fa93d56e4391b', '创建文章', '/article/create', '1', NULL);
 INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('4665765bf07d455486f2a5215dd97380', '1', 5, 'f066939ecbf64da3a54fa93d56e4391b', '文章管理', '/article/list', '1', NULL);
+INSERT INTO "tb_resource"("resid", "isleaf", "ordernum", "parentid", "resname", "respath", "showflag", "icon") VALUES ('80e0326446a643069bc8d26c132d45ea', '1', 7, 'f066939ecbf64da3a54fa93d56e4391b', '咨询问答管理', '/advisory/index', '1', NULL);
+
 
 INSERT INTO "tb_operator"("operid", "closedate", "email", "mobile", "opendate", "opercode", "opername", "operpwd", "opertype", "sex", "status", "tenantid", "thirdadmin", "jti", "roleid") VALUES ('LOR2IwRkbOjp+sVG9KR2BpHZbwGKepS4', '20500101', NULL, NULL, '20190101', 'system', '系统管理员', '$2a$10$Ex9xp11.vCaD8D0a7ahiUOKqDij1TcCUBwRAmrqXeDvAkmzLibn4.', 'oper', NULL, 'normal', '{tenantid}', 'no', 'QwC1ln7rReYmBOhq57op6Q', '20497f2fa27a44f7841492288ab75d88');
 
@@ -40,6 +45,8 @@
 INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('fd4a4e21231e4844b1310f95afc40f9a', '20200825152358', '81d3556981c34633adadb0fc4dc8d1f3', '20497f2fa27a44f7841492288ab75d88');
 INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('fc8f90bb3b6d41f8b7e1b840b1a0d590', '20200827110834', '4665765bf07d455486f2a5215dd97380', '20497f2fa27a44f7841492288ab75d88');
 INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('460d7f0b57eb4dcfb73fb1b51ad37f4f', '20200827142245', '99604b8d18b34417befe051a3720cbed', '20497f2fa27a44f7841492288ab75d88');
+INSERT INTO "tb_role_resource"("id", "addtime", "resid", "roleid") VALUES ('49cb562956534d7dbf54b762b2b6af0d', '20200921162433', '80e0326446a643069bc8d26c132d45ea', '20497f2fa27a44f7841492288ab75d88');
+
 
 
 ---------  end of script
diff --git a/frontend/src/api/advisory.js b/frontend/src/api/advisory.js
new file mode 100644
index 0000000..db9ed14
--- /dev/null
+++ b/frontend/src/api/advisory.js
@@ -0,0 +1,32 @@
+import request from '@/utils/request'
+
+export function saveAdvisory(data) {
+  return request({
+    url: '/advisory/save',
+    method: 'post',
+    data
+  })
+}
+
+export function getAdvisoryList(query) {
+  return request({
+    url: '/advisory/list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function deleteAdvisory(advisoryid) {
+  return request({
+    url: '/advisory/delete/' + advisoryid,
+    method: 'post'
+  })
+}
+
+export function switchDisplay(advisoryid, value) {
+  return request({
+    url: '/advisory/switchdisplay/' + advisoryid,
+    method: 'post',
+    params: value
+  })
+}
diff --git a/frontend/src/components/Tinymce/components/EditorImage.vue b/frontend/src/components/Tinymce/components/EditorImage.vue
index 366bb4f..ac1be17 100644
--- a/frontend/src/components/Tinymce/components/EditorImage.vue
+++ b/frontend/src/components/Tinymce/components/EditorImage.vue
@@ -33,6 +33,7 @@
 <script>
 // import { getToken } from 'api/qiniu'
 import { uploadImage } from '@/api/article'
+import user from '@/store/modules/user'
 
 export default {
   name: 'EditorSlideUpload',
@@ -47,21 +48,24 @@
       dialogVisible: false,
       listObj: {},
       fileList: [],
-      url: ''
+      url: '',
+      imageUrl: ''
     }
   },
   created() {
+    this.imageUrl = user.state.url
     this.url = process.env.VUE_APP_BASE_API
   },
   methods: {
     checkAllSuccess() {
       return Object.keys(this.listObj).every(item => this.listObj[item].hasSuccess)
     },
-    uploadImage(file) {
+    uploadImage(uploader) {
       const params = new FormData()
-      params.append('file', file.file)
+      params.append('file', uploader.file)
       uploadImage(params).then(response => {
-        console.log(response)
+        uploader.onSuccess(response)
+        this.handleSuccess(response, uploader.file)
       }).catch(error => {
         this.$message({
           message: error.msg || '图片上传异常',
@@ -82,12 +86,11 @@
       this.dialogVisible = false
     },
     handleSuccess(response, file) {
-      console.log(response)
       const uid = file.uid
       const objKeyArr = Object.keys(this.listObj)
       for (let i = 0, len = objKeyArr.length; i < len; i++) {
         if (this.listObj[objKeyArr[i]].uid === uid) {
-          this.listObj[objKeyArr[i]].url = response.files.file
+          this.listObj[objKeyArr[i]].url = this.imageUrl + response.data.picid
           this.listObj[objKeyArr[i]].hasSuccess = true
           return
         }
diff --git a/frontend/src/layout/components/TagsView/index.vue b/frontend/src/layout/components/TagsView/index.vue
index edbef59..72b9ffd 100644
--- a/frontend/src/layout/components/TagsView/index.vue
+++ b/frontend/src/layout/components/TagsView/index.vue
@@ -17,7 +17,7 @@
       </router-link>
     </scroll-pane>
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)">刷新</li>
+      <li @click="refreshSelectedTag(selectedTag)">重新加载</li>
       <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前标签页</li>
       <li @click="closeOthersTags">关闭其他标签页</li>
       <li @click="closeAllTags(selectedTag)">关闭所有标签页</li>
diff --git a/frontend/src/views/advisory/index.vue b/frontend/src/views/advisory/index.vue
new file mode 100644
index 0000000..7b24d62
--- /dev/null
+++ b/frontend/src/views/advisory/index.vue
@@ -0,0 +1,292 @@
+<template>
+  <div class="app-container">
+    <div class="filter-container">
+      <div class="filter-item" style="margin-right:15px">问答标题</div>
+      <el-input
+        v-model="formData.title"
+        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: 350px;margin-right:50px"
+        class="filter-item"
+      />
+      <el-button
+        class="filter-item"
+        type="primary"
+        icon="el-icon-search"
+        @click="handleFilter()"
+      >
+        搜索
+      </el-button>
+    </div>
+    <el-button type="primary" icon="el-icon-circle-plus-outline" @click="addAdvisory()">
+      新增问答
+    </el-button>
+    <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" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.title }}</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="160">
+        <template slot-scope="{row}">
+          <span>{{ dateFormat(row.updatetime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="排序" width="80" align="center">
+        <template slot-scope="{row}">
+          <span>{{ row.ordernum }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column width="100px" label="是否展示" align="center">
+        <template slot-scope="{row}">
+          <el-switch
+            :value="row.isdisplay === '1'"
+            active-color="#13ce66"
+            inactive-color="#a7a7a7"
+            @click.native.prevent="switchDisplay(row)"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" width="100">
+        <template slot-scope="{row}">
+          <el-tooltip class="item" effect="dark" content="修改" placement="bottom">
+            <el-button type="primary" icon="el-icon-edit" circle size="mini" @click="updateAdvisory(row)" />
+          </el-tooltip>
+          <el-tooltip class="item" effect="dark" content="删除" placement="bottom">
+            <el-button type="danger" icon="el-icon-delete" circle size="mini" @click="deleteAdvisory(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="getAdvisoryList"
+    />
+    <el-dialog
+      :title="title"
+      :visible.sync="advisoryDialogVisible"
+      width="45%"
+    >
+      <div>
+        <el-form ref="advisoryForm" :model="advisoryForm" :rules="rules" label-width="100px">
+          <el-form-item label="问答标题" prop="title" class="form-input-item">
+            <el-input
+              v-model="advisoryForm.title"
+              maxlength="30"
+              show-word-limit
+              style="width:80%"
+            />
+          </el-form-item>
+          <el-form-item label="问答排序" prop="ordernum">
+            <el-input-number v-model="advisoryForm.ordernum" :min="1" style="width:40%" />
+          </el-form-item>
+          <el-form-item label="问答内容" prop="content">
+            <el-input
+              v-model="advisoryForm.content"
+              type="textarea"
+              maxlength="230"
+              :rows="8"
+              placeholder=""
+              show-word-limit
+              style="width:80%"
+            />
+          </el-form-item>
+        </el-form>
+      </div>
+      <div style="text-align:center">
+        <el-button
+          type="primary"
+          @click="saveAdvisory('advisoryForm')"
+        >保存
+        </el-button>
+        <el-button @click="advisoryDialogVisible = false">取消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import {
+  saveAdvisory,
+  getAdvisoryList,
+  switchDisplay,
+  deleteAdvisory
+} from '@/api/advisory'
+import moment from 'moment'
+import Pagination from '@/components/Pagination'
+export default {
+  name: 'Advisory',
+  components: {
+    Pagination
+  },
+  data() {
+    return {
+      advisoryDialogVisible: false,
+      formData: {
+        title: '',
+        content: '',
+        pageno: 1,
+        pagesize: 10
+      },
+      listLoading: false,
+      tableKey: 0,
+      list: null,
+      total: 0,
+      title: '',
+      advisoryForm: {
+        advisoryid: '',
+        title: '',
+        content: '',
+        ordernum: 1
+      },
+      rules: {
+        title: [
+          { required: true, message: '请输入问答标题', trigger: 'blur' }
+        ],
+        content: [
+          { required: true, message: '请输入问答内容', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+    this.getAdvisoryList()
+  },
+  methods: {
+    addAdvisory() {
+      this.title = '新增问答'
+      this.resetForm('advisoryForm')
+      this.advisoryDialogVisible = true
+    },
+    saveAdvisory(formName) {
+      this.$refs[formName].validate((valid) => {
+        if (valid) {
+          saveAdvisory(this.advisoryForm).then(response => {
+            this.$notify({
+              title: '成功',
+              message: '保存成功!',
+              type: 'success',
+              duration: 2000
+            })
+            this.advisoryDialogVisible = false
+            this.getAdvisoryList()
+          }).catch(error => {
+            this.$message({
+              message: error.msg || '请求异常',
+              type: 'error'
+            })
+          })
+        } else {
+          return false
+        }
+      })
+    },
+    getAdvisoryList() {
+      this.listLoading = true
+      getAdvisoryList(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.getAdvisoryList()
+    },
+    resetForm(formName) {
+      this.advisoryForm = {
+        advisoryid: '',
+        title: '',
+        content: '',
+        ordernum: null
+      }
+      this.$nextTick(() => {
+        this.$refs[formName].clearValidate()
+      })
+    },
+    updateAdvisory(row) {
+      this.title = '修改问答'
+      this.resetForm('advisoryForm')
+      this.advisoryForm = Object.assign({}, row)
+      this.advisoryDialogVisible = true
+    },
+    dateFormat(date) {
+      if (date === null) {
+        return ''
+      }
+      return moment(date, 'YYYYMMDDHHmmss').format('YYYY-MM-DD HH:mm:ss')
+    },
+    switchDisplay(row) {
+      switchDisplay(row.advisoryid, { value: row.isdisplay === '1' ? '0' : '1' }).then(response => {
+        this.$message({
+          type: 'success',
+          message: '操作成功!'
+        })
+        row.isdisplay = response.result
+      }).catch(error => {
+        this.$message({
+          message: error.msg || '请求异常',
+          type: 'error'
+        })
+        this.listLoading = false
+      })
+    },
+    deleteAdvisory(row) {
+      this.$confirm('是否确认删除该问答?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteAdvisory(row.advisoryid).then(response => {
+          this.$message({
+            type: 'success',
+            message: '删除成功!'
+          })
+          this.handleFilter()
+        }).catch(error => {
+          this.$message({
+            message: error.msg || '请求异常',
+            type: 'error'
+          })
+          this.listLoading = false
+        })
+      }).catch(() => {
+      })
+    }
+  }
+}
+</script>
diff --git a/frontend/src/views/article/list.vue b/frontend/src/views/article/list.vue
index 084f69e..7e481f7 100644
--- a/frontend/src/views/article/list.vue
+++ b/frontend/src/views/article/list.vue
@@ -121,7 +121,7 @@
           </el-tooltip>
 
           <el-tooltip class="item" effect="dark" content="删除" placement="bottom">
-            <el-button type="primary" icon="el-icon-delete" circle size="mini" @click="deleteArticle(row)" />
+            <el-button type="danger" icon="el-icon-delete" circle size="mini" @click="deleteArticle(row)" />
           </el-tooltip>
           <!-- <el-tooltip v-if="row.status!=='save' && row.status!=='released'" class="item" effect="dark" content="撤回" placement="bottom">
             <el-button type="primary" size="mini" circle>
diff --git a/frontend/src/views/feedback/index.vue b/frontend/src/views/feedback/index.vue
index 8ca94da..eb0723b 100644
--- a/frontend/src/views/feedback/index.vue
+++ b/frontend/src/views/feedback/index.vue
@@ -381,6 +381,7 @@
         if (response.list) {
           reply = response.list[0]
         }
+        console.log(reply.replycontent)
         const replyContent = {
           title: '回复内容',
           content: reply.replycontent,