完成栏目及文章功能
diff --git a/backend/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java b/backend/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
index c961f32..c103085 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/api/domain/TPersondtl.java
@@ -46,6 +46,9 @@
   @Column(name = "BEFBAL", precision = 9, scale = 2)
   private Double befbal;
 
+  @Column(name = "AFTBAL", precision = 9, scale = 2)
+  private Double aftbal;
+
   @Column(name = "amount", precision = 9, scale = 2)
   @NotNull
   private Double amount; //实际付款金额
@@ -298,4 +301,12 @@
   public void setAnonymous(Boolean anonymous) {
     this.anonymous = anonymous;
   }
+
+  public Double getAftbal() {
+    return aftbal;
+  }
+
+  public void setAftbal(Double aftbal) {
+    this.aftbal = aftbal;
+  }
 }
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 a4bafe4..3d77024 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
@@ -19,7 +19,7 @@
   @Override
   public Pagination getArticleList(@NotNull ArticleSearchBean bean) throws ParseException {
     SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
-    StringBuilder sql = new StringBuilder("select a.*,c.name columnname from tb_article a left join tb_column c on a.columnid = c.columnid where 1=1 ");
+    StringBuilder sql = new StringBuilder("select a.*,c.name columnname from tb_article a left join tb_column c on a.columnid = c.columnid where a.isdelete = '0' ");
     String title = bean.getTitle();
     String status = bean.getStatus();
     String savestartdate = bean.getSavestartdate();
@@ -46,7 +46,7 @@
     if (!StringUtil.isEmpty(saveenddate)) {
       sql.append(" and a.createtime <=:saveenddate");
     }
-    sql.append(" order by a.releasetime");
+    sql.append(" order by a.articleno desc");
     Finder f = Finder.create(sql.toString());
     if (!StringUtil.isEmpty(title)) {
       f.setParameter("title", "%" + title.trim() + "%");
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticle.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticle.java
index e03bf41..9c743eb 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticle.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticle.java
@@ -25,7 +25,7 @@
   @Column(name = "articleno", unique = true, nullable = false, length = 20)
   private String articleno;
 
-  @Column(name = "title", nullable = false, length = 30)
+  @Column(name = "title", nullable = false, length = 50)
   private String title;
 
   @Lob
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticleAuth.java b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticleAuth.java
new file mode 100644
index 0000000..faf3183
--- /dev/null
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/domain/TBArticleAuth.java
@@ -0,0 +1,122 @@
+package com.supwisdom.dlpay.portal.domain;
+
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "tb_article_auth")
+public class TBArticleAuth {
+  @Id
+  @GenericGenerator(name = "idGenerator", strategy = "uuid")
+  @GeneratedValue(generator = "idGenerator")
+  @Column(name = "authid", nullable = false, length = 32)
+  private String authid;
+
+  @Column(name = "articleno", nullable = false, length = 8)
+  private String articleno;
+
+  @Column(name = "status",nullable = false,length = 20)
+  private String status;
+
+  @Column(name = "reason",length = 200)
+  private String reason;
+
+  @Column(name = "authdate",length = 14)
+  private String authdate;
+
+  @Column(name = "authoperid",length = 32)
+  private String authoperid;
+
+  @Column(name = "submitdate",length = 14)
+  private String submitdate;
+
+  @Column(name = "articletitle",length = 50)
+  private String articletitle;
+
+  @Column(name = "columnname", length = 30)
+  private String columnname;
+
+  @Column(name = "articleopername",length = 100)
+  private String articleopername;
+
+  public String getAuthid() {
+    return authid;
+  }
+
+  public void setAuthid(String authid) {
+    this.authid = authid;
+  }
+
+  public String getArticleno() {
+    return articleno;
+  }
+
+  public void setArticleno(String articleno) {
+    this.articleno = articleno;
+  }
+
+  public String getStatus() {
+    return status;
+  }
+
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  public String getReason() {
+    return reason;
+  }
+
+  public void setReason(String reason) {
+    this.reason = reason;
+  }
+
+  public String getAuthdate() {
+    return authdate;
+  }
+
+  public void setAuthdate(String authdate) {
+    this.authdate = authdate;
+  }
+
+  public String getAuthoperid() {
+    return authoperid;
+  }
+
+  public void setAuthoperid(String authoperid) {
+    this.authoperid = authoperid;
+  }
+
+  public String getArticletitle() {
+    return articletitle;
+  }
+
+  public void setArticletitle(String articletitle) {
+    this.articletitle = articletitle;
+  }
+
+  public String getColumnname() {
+    return columnname;
+  }
+
+  public void setColumnname(String columnname) {
+    this.columnname = columnname;
+  }
+
+  public String getArticleopername() {
+    return articleopername;
+  }
+
+  public void setArticleopername(String articleopername) {
+    this.articleopername = articleopername;
+  }
+
+  public String getSubmitdate() {
+    return submitdate;
+  }
+
+  public void setSubmitdate(String submitdate) {
+    this.submitdate = submitdate;
+  }
+}
diff --git a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
index fe195fd..4a6de31 100644
--- a/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
+++ b/backend/src/main/java/com/supwisdom/dlpay/portal/util/PortalConstant.java
@@ -12,6 +12,8 @@
   public static final String SYSPARA_ARTICLE_CURRENTNO = "article.currentno";
 
   public static final String ARTICLE_STATUS_SAVE = "save";
+  public static final String ARTICLE_STATUS_PASS = "pass";
   public static final String ARTICLE_STATUS_RELEASED = "released";
   public static final String ARTICLE_STATUS_REVIEW = "review";
+  public static final String ARTICLE_STATUS_REJECT = "reject";
 }
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 43bc662..3971f40 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/PortalApi.kt
@@ -249,6 +249,34 @@
         }
     }
 
+    @RequestMapping(value = ["/article/release"], method = [RequestMethod.POST])
+    fun releaseArticle(@RequestBody article: TBArticle): JsonResult? {
+        return try {
+            val p = SecurityContextHolder.getContext().authentication
+            val oper = operatorDetailService.findByOperid(p.name)
+            article.operid = oper.operid
+            articleService.releaseArticle(article)
+            JsonResult.ok()
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("发布文章异常")
+        }
+    }
+
+    @RequestMapping(value = ["/article/review"], method = [RequestMethod.POST])
+    fun reviewArticle(@RequestBody article: TBArticle): JsonResult? {
+        return try {
+            val p = SecurityContextHolder.getContext().authentication
+            val oper = operatorDetailService.findByOperid(p.name)
+            article.operid = oper.operid
+            articleService.reviewArticle(article,oper.opername)
+            JsonResult.ok()
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("提交文章审核异常")
+        }
+    }
+
     @RequestMapping("/article/list")
     fun getArticleList(bean: ArticleSearchBean): JsonResult? {
         return try {
@@ -263,4 +291,37 @@
         }
     }
 
+    @RequestMapping(value = ["/article/delete/{articleno}"], method = [RequestMethod.POST])
+    fun deleteArticle(@PathVariable(value = "articleno") articleno: String): JsonResult? {
+        return try {
+            articleService.deleteArticle(articleno)
+            JsonResult.ok()
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("删除文章异常")
+        }
+    }
+
+    @RequestMapping(value = ["/article/get/{articleno}"], method = [RequestMethod.GET])
+    fun getArticle(@PathVariable(value = "articleno") articleno: String): JsonResult? {
+        return try {
+            val article = articleService.getArticle(articleno)
+            JsonResult.ok().put("article", article)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("获取文章详情文章异常")
+        }
+    }
+
+    @RequestMapping(value = ["/article/switchdisplay/{articleno}"], method = [RequestMethod.POST])
+    fun switchDisplay(@PathVariable(value = "articleno") articleno: String,
+                      @RequestParam(value = "value") value: String): JsonResult? {
+        return try {
+            val result = articleService.switchDisplay(articleno, value)
+            JsonResult.ok().put("result", result)
+        } catch (e: Exception) {
+            logger.error { e.message }
+            JsonResult.error("切换文章是否显示异常")
+        }
+    }
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleAuthDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleAuthDao.kt
new file mode 100644
index 0000000..e7f72fb
--- /dev/null
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleAuthDao.kt
@@ -0,0 +1,10 @@
+package com.supwisdom.dlpay.portal.dao
+
+import com.supwisdom.dlpay.portal.domain.TBArticleAuth
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+
+@Repository
+interface ArticleAuthDao : JpaRepository<TBArticleAuth, String> {
+    fun findByArticlenoAndStatus(articleno: String, status: String):TBArticleAuth?
+}
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleDao.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleDao.kt
index 6f89cc4..3e4ca6b 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleDao.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/dao/ArticleDao.kt
@@ -5,6 +5,6 @@
 import org.springframework.stereotype.Repository
 
 @Repository
-interface ArticleDao:JpaRepository<TBArticle,String>,ArticleRepository{
-
+interface ArticleDao : JpaRepository<TBArticle, String>, ArticleRepository {
+    fun findByArticlenoAndIsdelete(articleno: String,isdelete:String): TBArticle?
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/ArticleService.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/ArticleService.kt
index 3488b2f..7eaa432 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/ArticleService.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/ArticleService.kt
@@ -12,5 +12,15 @@
     @Transactional
     fun saveArticle(article: TBArticle)
     @Transactional
+    fun releaseArticle(article: TBArticle)
+    @Transactional
+    fun reviewArticle(article: TBArticle,opername:String)
+    @Transactional
     fun getArticleList(bean:ArticleSearchBean): Pagination
+    @Transactional
+    fun deleteArticle(articleno:String)
+    @Transactional
+    fun switchDisplay(articleno:String,value:String):String
+    @Transactional
+    fun getArticle(articleno:String):TBArticle
 }
\ No newline at end of file
diff --git a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/ArticleServiceImpl.kt b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/ArticleServiceImpl.kt
index 986639b..2d45cb6 100644
--- a/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/ArticleServiceImpl.kt
+++ b/backend/src/main/kotlin/com/supwisdom/dlpay/portal/service/Impl/ArticleServiceImpl.kt
@@ -5,8 +5,11 @@
 import com.supwisdom.dlpay.framework.service.SystemUtilService
 import com.supwisdom.dlpay.framework.util.StringUtil
 import com.supwisdom.dlpay.portal.bean.ArticleSearchBean
+import com.supwisdom.dlpay.portal.dao.ArticleAuthDao
 import com.supwisdom.dlpay.portal.dao.ArticleDao
+import com.supwisdom.dlpay.portal.dao.ColumnDao
 import com.supwisdom.dlpay.portal.domain.TBArticle
+import com.supwisdom.dlpay.portal.domain.TBArticleAuth
 import com.supwisdom.dlpay.portal.service.ArticleService
 import com.supwisdom.dlpay.portal.util.PortalConstant
 import com.supwisdom.dlpay.portal.util.PutImageToServer
@@ -19,7 +22,7 @@
 import java.io.File
 import java.io.FileInputStream
 import java.io.IOException
-import java.lang.RuntimeException
+import java.sql.Timestamp
 import java.util.*
 import kotlin.math.sqrt
 
@@ -31,33 +34,110 @@
     lateinit var articleDao: ArticleDao
     @Autowired
     lateinit var businessparaDao: BusinessparaDao
+    @Autowired
+    lateinit var articleAuthDao: ArticleAuthDao
+    @Autowired
+    lateinit var columnDao: ColumnDao
 
     val logger = KotlinLogging.logger { }
 
     override fun saveArticle(article: TBArticle) {
+        if (article.status != null && article.status != PortalConstant.ARTICLE_STATUS_SAVE) {
+            throw RuntimeException("文章状态异常")
+        }
         val timestamp = systemUtilService.sysdatetime.sysdate
-        val currentNoBusiness = businessparaDao.findByParakey(PortalConstant.SYSPARA_ARTICLE_CURRENTNO)
-                ?: throw RuntimeException("文章编号参数未配置")
-        val currentNo = currentNoBusiness.paraval.toInt()
-        currentNoBusiness.paraval = (currentNo + 1).toString()
-        businessparaDao.save(currentNoBusiness)
+        article.status = PortalConstant.ARTICLE_STATUS_SAVE
+        saveArticle(article,timestamp)
+    }
+
+    fun saveArticle(article: TBArticle,timestamp:Timestamp): TBArticle {
         if (StringUtil.isEmpty(article.articleid)) {
+            val currentNoBusiness = businessparaDao.findByParakey(PortalConstant.SYSPARA_ARTICLE_CURRENTNO)
+                    ?: throw RuntimeException("文章编号参数未配置")
+            val currentNo = currentNoBusiness.paraval.toInt()
+            currentNoBusiness.paraval = (currentNo + 1).toString()
+            businessparaDao.save(currentNoBusiness)
             article.createtime = timestamp
             article.articleno = String.format("%08d", currentNo)
             article.hits = 0
             article.isdisplay = PortalConstant.YES
             article.isdelete = PortalConstant.NO
-            article.status = PortalConstant.ARTICLE_STATUS_SAVE
-        }else{
+        } else {
             article.updatetime = timestamp
         }
-        articleDao.save(article)
+        return articleDao.save(article)
+    }
+
+    override fun releaseArticle(article: TBArticle) {
+        if (article.status != null &&
+                article.status != PortalConstant.ARTICLE_STATUS_SAVE &&
+                article.status != PortalConstant.ARTICLE_STATUS_PASS) {
+            throw RuntimeException("文章状态异常")
+        }
+        val timestamp = systemUtilService.sysdatetime.sysdate
+        article.releasetime = timestamp
+        article.status = PortalConstant.ARTICLE_STATUS_RELEASED
+        val savedArticle = saveArticle(article,timestamp)
+        val optional = columnDao.findById(savedArticle.columnid)
+        if (!optional.isPresent) {
+            throw RuntimeException("文章栏目未找到")
+        }
+        val column = optional.get()
+        if (column.needreview == PortalConstant.YES) {
+            articleAuthDao.findByArticlenoAndStatus(savedArticle.articleno,
+                    PortalConstant.ARTICLE_STATUS_PASS)
+                    ?: throw RuntimeException("文章未通过审核,不能发布")
+        }
+    }
+
+
+    override fun reviewArticle(article: TBArticle, opername: String) {
+        if (article.status != null && article.status != PortalConstant.ARTICLE_STATUS_SAVE) {
+            throw RuntimeException("文章状态异常")
+        }
+        val timestamp = systemUtilService.sysdatetime.sysdate
+        article.status = PortalConstant.ARTICLE_STATUS_REVIEW
+        val savedArticle = saveArticle(article,timestamp)
+        val optional = columnDao.findById(savedArticle.columnid)
+        if (!optional.isPresent) {
+            throw RuntimeException("文章栏目未找到")
+        }
+        val column = optional.get()
+        val articleAuth = TBArticleAuth().apply {
+            this.articleno = savedArticle.articleno
+            this.status = PortalConstant.ARTICLE_STATUS_REVIEW
+            this.articleopername = opername
+            this.articletitle = savedArticle.title
+            this.columnname = column.name
+            this.submitdate = systemUtilService.sysdatetime.hostdatetime
+        }
+        articleAuthDao.save(articleAuth)
     }
 
     override fun getArticleList(bean: ArticleSearchBean): Pagination {
         return articleDao.getArticleList(bean)
     }
 
+    override fun deleteArticle(articleno: String) {
+        val article = articleDao.findByArticlenoAndIsdelete(articleno, PortalConstant.NO)
+                ?: throw RuntimeException("编号为:[${articleno}]的文章未找到")
+        article.isdelete = PortalConstant.YES
+        articleDao.save(article)
+    }
+
+    override fun switchDisplay(articleno: String, value: String): String {
+        val article = articleDao.findByArticlenoAndIsdelete(articleno, PortalConstant.NO)
+                ?: throw RuntimeException("编号为:[${articleno}]的文章未找到")
+        article.isdisplay = value
+        articleDao.save(article)
+        return article.isdisplay
+    }
+
+    override fun getArticle(articleno: String): TBArticle {
+        return articleDao.findByArticlenoAndIsdelete(articleno, PortalConstant.NO)
+                ?: throw RuntimeException("编号为:[${articleno}]的文章未找到")
+    }
+
     override fun uploadPic(request: MultipartHttpServletRequest): Map<String, String> {
         val map: MutableMap<String, String> = HashMap()
         try {
diff --git a/frontend/src/api/article.js b/frontend/src/api/article.js
index a05932e..6b3d41a 100644
--- a/frontend/src/api/article.js
+++ b/frontend/src/api/article.js
@@ -27,6 +27,44 @@
   })
 }
 
+export function getArticle(articleno) {
+  return request({
+    url: '/article/get/' + articleno,
+    method: 'get'
+  })
+}
+
+export function releaseArticle(data) {
+  return request({
+    url: '/article/release',
+    method: 'post',
+    data
+  })
+}
+
+export function reviewArticle(data) {
+  return request({
+    url: '/article/review',
+    method: 'post',
+    data
+  })
+}
+
+export function deleteArticle(articleno) {
+  return request({
+    url: '/article/delete/' + articleno,
+    method: 'post'
+  })
+}
+
+export function switchDisplay(articleno, value) {
+  return request({
+    url: '/article/switchdisplay/' + articleno,
+    method: 'post',
+    params: value
+  })
+}
+
 export function fetchList(query) {
   return request({
     url: '/vue-element-admin/article/list',
diff --git a/frontend/src/layout/components/TagsView/index.vue b/frontend/src/layout/components/TagsView/index.vue
index d2a56e7..edbef59 100644
--- a/frontend/src/layout/components/TagsView/index.vue
+++ b/frontend/src/layout/components/TagsView/index.vue
@@ -17,10 +17,10 @@
       </router-link>
     </scroll-pane>
     <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
-      <li @click="refreshSelectedTag(selectedTag)">Refresh</li>
-      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">Close</li>
-      <li @click="closeOthersTags">Close Others</li>
-      <li @click="closeAllTags(selectedTag)">Close All</li>
+      <li @click="refreshSelectedTag(selectedTag)">刷新</li>
+      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前标签页</li>
+      <li @click="closeOthersTags">关闭其他标签页</li>
+      <li @click="closeAllTags(selectedTag)">关闭所有标签页</li>
     </ul>
   </div>
 </template>
diff --git a/frontend/src/store/modules/permission.js b/frontend/src/store/modules/permission.js
index 9e2aa4e..a35f884 100644
--- a/frontend/src/store/modules/permission.js
+++ b/frontend/src/store/modules/permission.js
@@ -30,7 +30,15 @@
         meta: { title: '编辑文章', id: '1c039c677ded4f1dab63a4fa9c0a27ca', noCache: true, roles: ['admin'] },
         hidden: true
       }
+      const examineArticle = {
+        path: '/article/examine/:id(\\d+)',
+        component: (resolve) => require([`@/views/article/examine`], resolve),
+        name: 'ExamineArticle',
+        meta: { title: '文章详情', id: '28d382221fdb44f49397f618c6cae3f7', noCache: true, roles: ['admin'] },
+        hidden: true
+      }
       routes.push(editArticle)
+      routes.push(examineArticle)
     }
     const menu = {
       path: item.respath === '#' ? item.resid + '_key' : item.respath,
diff --git a/frontend/src/views/article/components/ArticleDetail.vue b/frontend/src/views/article/components/ArticleDetail.vue
index f634220..ec84f4b 100644
--- a/frontend/src/views/article/components/ArticleDetail.vue
+++ b/frontend/src/views/article/components/ArticleDetail.vue
@@ -1,8 +1,23 @@
 <template>
   <div class="createPost-container">
     <el-form ref="postForm" :model="postForm" :rules="rules" class="form-container">
-      <sticky :z-index="10" :class-name="'sub-navbar '+postForm.status">
-        <el-button v-loading="loading" style="margin-left: 10px;" type="primary" @click="submitForm">
+      <sticky v-if="action==='create'||action==='edit'" :z-index="10" :class-name="'sub-navbar draft'">
+        <el-button
+          v-if="currentcolumn && currentcolumn.needreview === '1'"
+          v-loading="loading"
+          style="margin-left: 10px;"
+          type="primary"
+          @click="reviewForm"
+        >
+          提交审核
+        </el-button>
+        <el-button
+          v-if="currentcolumn && currentcolumn.needreview === '0'"
+          v-loading="loading"
+          style="margin-left: 10px;"
+          type="primary"
+          @click="submitForm"
+        >
           发布
         </el-button>
         <el-button v-loading="loading" type="primary" @click="draftForm">
@@ -12,7 +27,6 @@
 
       <div class="createPost-main-container">
         <el-row>
-
           <el-col :span="24">
             <el-form-item style="margin-bottom: 40px;" prop="title">
               <MDinput v-model="postForm.title" :maxlength="30" name="name" required>
@@ -30,6 +44,7 @@
                       filterable
                       default-first-option
                       placeholder="搜索栏目"
+                      @change="selectColumn"
                     >
                       <el-option
                         v-for="(item,index) in columnList"
@@ -57,11 +72,10 @@
 import Tinymce from '@/components/Tinymce'
 import MDinput from '@/components/MDinput'
 import Sticky from '@/components/Sticky' // 粘性header组件
-import { saveArticle } from '@/api/article'
+import { saveArticle, getArticle, releaseArticle, reviewArticle } from '@/api/article'
 import { getAllColumn } from '@/api/column'
 
 const defaultForm = {
-  status: 'draft',
   title: '', // 文章题目
   content: '', // 文章内容
   columnid: '',
@@ -74,9 +88,9 @@
   name: 'ArticleDetail',
   components: { Tinymce, MDinput, Sticky },
   props: {
-    isEdit: {
-      type: Boolean,
-      default: false
+    action: {
+      type: String,
+      default: 'create'
     }
   },
   data() {
@@ -84,6 +98,7 @@
       postForm: Object.assign({}, defaultForm),
       loading: false,
       columnList: [],
+      currentcolumn: null,
       rules: {
         title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
         columnid: [{ required: true, message: '请选择文章栏目', trigger: 'blur' }],
@@ -113,82 +128,138 @@
     }
   },
   created() {
-    if (this.isEdit) {
+    if (this.action !== 'create') {
       const id = this.$route.params && this.$route.params.id
       this.fetchData(id)
+    } else {
+      getAllColumn().then(response => {
+        if (response.list) {
+          this.columnList = response.list
+        } else {
+          this.columnList = []
+        }
+      }).catch(error => {
+        this.$message({
+          message: error.msg || '请求异常',
+          type: 'error'
+        })
+      })
     }
 
     // Why need to make a copy of this.$route here?
     // Because if you enter this page and quickly switch tag, may be in the execution of the setTagsViewTitle function, this.$route is no longer pointing to the current page
     // https://github.com/PanJiaChen/vue-element-admin/issues/1221
     this.tempRoute = Object.assign({}, this.$route)
-    getAllColumn().then(response => {
-      if (response.list) {
-        this.columnList = response.list
-      } else {
-        this.columnList = []
-      }
-    }).catch(error => {
-      this.$message({
-        message: error.msg || '请求异常',
-        type: 'error'
-      })
-    })
   },
   methods: {
     fetchData(id) {
-      // fetchArticle(id).then(response => {
-      //   this.postForm = response.data
+      getArticle(id).then(response => {
+        this.postForm = response.article
 
-      //   // just for test
-      //   this.postForm.title += `   Article Id:${this.postForm.id}`
-      //   this.postForm.content_short += `   Article Id:${this.postForm.id}`
+        // set tagsview title
+        this.setTagsViewTitle()
 
-      //   // set tagsview title
-      //   this.setTagsViewTitle()
-
-      //   // set page title
-      //   this.setPageTitle()
-      // }).catch(err => {
-      //   console.log(err)
-      // })
+        // set page title
+        this.setPageTitle()
+        getAllColumn().then(response => {
+          if (response.list) {
+            this.columnList = response.list
+            if (this.action === 'edit') {
+              this.selectColumn(this.postForm.columnid)
+            }
+          } else {
+            this.columnList = []
+          }
+        }).catch(error => {
+          this.$message({
+            message: error.msg || '请求异常',
+            type: 'error'
+          })
+        })
+      }).catch(err => {
+        console.log(err)
+        this.$router.push({ path: '/error-page/404' })
+      })
     },
     setTagsViewTitle() {
-      const title = this.lang === 'zh' ? '编辑文章' : 'Edit Article'
-      const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.id}` })
+      let title = '编辑文章'
+      if (this.action === 'edit') {
+        title = '编辑文章'
+      } else if (this.action === 'examine') {
+        title = '文章详情'
+      } else if (this.action === 'review') {
+        title = '文章审核'
+      }
+
+      const route = Object.assign({}, this.tempRoute, { title: `${title}-${this.postForm.articleno}` })
       this.$store.dispatch('tagsView/updateVisitedView', route)
     },
     setPageTitle() {
-      const title = 'Edit Article'
-      document.title = `${title} - ${this.postForm.id}`
+      let title = '编辑文章'
+      if (this.action === 'edit') {
+        title = '编辑文章'
+      } else if (this.action === 'examine') {
+        title = '文章详情'
+      } else if (this.action === 'review') {
+        title = '文章审核'
+      }
+      document.title = `${title} - ${this.postForm.articleno}`
     },
-    submitForm() {
-      this.$refs.postForm.validate(valid => {
-        if (valid) {
-          this.loading = true
-          this.$notify({
-            title: '成功',
-            message: '发布文章成功',
-            type: 'success',
-            duration: 2000
-          })
-          this.postForm.status = 'published'
-          this.loading = false
-        } else {
-          console.log('error submit!!')
-          return false
+    selectColumn(columnid) {
+      this.columnList.forEach(value => {
+        if (value.columnid === columnid) {
+          this.currentcolumn = value
         }
       })
     },
-    draftForm() {
-      if (this.postForm.content.length === 0 || this.postForm.title.length === 0) {
-        this.$message({
-          message: '请填写必要的标题和内容',
-          type: 'warning'
-        })
+    submitForm() {
+      if (!this.submitCheck()) {
         return
       }
-      this.postForm.islink = '0'
+      this.loading = true
+      releaseArticle(this.postForm).then(response => {
+        this.$notify({
+          title: '成功',
+          message: '发布文章成功',
+          type: 'success',
+          duration: 2000
+        })
+        this.$store.dispatch('tagsView/delView', this.$route)
+        this.$router.go(-1)
+      }).catch(error => {
+        this.$message({
+          message: error.msg || '请求异常',
+          type: 'error'
+        })
+      })
+      this.loading = false
+    },
+    reviewForm() {
+      if (!this.submitCheck()) {
+        return
+      }
+      this.loading = true
+      reviewArticle(this.postForm).then(response => {
+        this.$notify({
+          title: '成功',
+          message: '提交审核成功',
+          type: 'success',
+          duration: 2000
+        })
+        this.$store.dispatch('tagsView/delView', this.$route)
+        this.$router.go(-1)
+      }).catch(error => {
+        this.$message({
+          message: error.msg || '请求异常',
+          type: 'error'
+        })
+      })
+      this.loading = false
+    },
+    draftForm() {
+      if (!this.submitCheck()) {
+        return
+      }
       saveArticle(this.postForm).then(response => {
         this.$message({
           message: '保存成功',
@@ -202,7 +273,19 @@
           type: 'error'
         })
       })
-      this.postForm.status = 'draft'
+    },
+    submitCheck() {
+      if (this.postForm.content.length === 0 ||
+      this.postForm.title.length === 0 ||
+      this.postForm.columnid.length === 0) {
+        this.$message({
+          message: '请填写必要的标题和内容,栏目不能为空',
+          type: 'warning'
+        })
+        return false
+      }
+      this.postForm.islink = '0'
+      return true
     }
   }
 }
diff --git a/frontend/src/views/article/create.vue b/frontend/src/views/article/create.vue
index f28ce28..362ab17 100644
--- a/frontend/src/views/article/create.vue
+++ b/frontend/src/views/article/create.vue
@@ -1,5 +1,5 @@
 <template>
-  <article-detail :is-edit="false" />
+  <article-detail action="create" />
 </template>
 
 <script>
diff --git a/frontend/src/views/article/edit.vue b/frontend/src/views/article/edit.vue
index 87b6126..2c0d833 100644
--- a/frontend/src/views/article/edit.vue
+++ b/frontend/src/views/article/edit.vue
@@ -1,5 +1,5 @@
 <template>
-  <article-detail :is-edit="true" />
+  <article-detail action="edit" />
 </template>
 
 <script>
diff --git a/frontend/src/views/article/examine.vue b/frontend/src/views/article/examine.vue
new file mode 100644
index 0000000..0f7f3ed
--- /dev/null
+++ b/frontend/src/views/article/examine.vue
@@ -0,0 +1,12 @@
+<template>
+  <article-detail action="examine" />
+</template>
+
+<script>
+import ArticleDetail from './components/ArticleDetail'
+
+export default {
+  name: 'ExamineArticle',
+  components: { ArticleDetail }
+}
+</script>
diff --git a/frontend/src/views/article/list.vue b/frontend/src/views/article/list.vue
index 1ae114d..5fb208d 100644
--- a/frontend/src/views/article/list.vue
+++ b/frontend/src/views/article/list.vue
@@ -82,9 +82,9 @@
 
       <el-table-column width="100px" label="状态" align="center">
         <template slot-scope="{row}">
-          <el-tag v-if="row.status==='save'" effect="dark" size="medium">已保存</el-tag>
-          <el-tag v-if="row.status==='released'" effect="dark" type="success" size="medium">已发布</el-tag>
-          <el-tag v-if="row.status==='review'" effect="dark" type="warning" size="medium">审核中</el-tag>
+          <el-tag v-if="row.status==='save'" size="medium">已保存</el-tag>
+          <el-tag v-if="row.status==='released'" type="success" size="medium">已发布</el-tag>
+          <el-tag v-if="row.status==='review'" type="warning" size="medium">审核中</el-tag>
         </template>
       </el-table-column>
       <el-table-column width="100px" label="保存时间">
@@ -97,24 +97,52 @@
           <span>{{ dateFormat(row.releasetime) }}</span>
         </template>
       </el-table-column>
-      <el-table-column width="100px" label="是否展示">
+      <el-table-column width="100px" label="是否展示" align="center">
         <template slot-scope="{row}">
-          <span>{{ row.isdisplay }}</span>
+          <el-switch
+            :value="row.isdisplay === '1'"
+            active-color="#13ce66"
+            inactive-color="#a7a7a7"
+            @click.native.prevent="switchDisplay(row)"
+          />
         </template>
       </el-table-column>
-      <el-table-column width="100px" label="操作">
-        <template slot-scope="{}">
-          <span>删除</span>
-        </template>
-      </el-table-column>
+      <el-table-column width="120px" label="操作" align="center">
+        <template slot-scope="{row}">
+          <el-tooltip v-if="row.status==='save'" class="item" effect="dark" content="编辑" placement="bottom">
+            <router-link :to="'/article/edit/'+row.articleno">
+              <el-button type="primary" style="margin-right:10px" icon="el-icon-edit" circle size="mini" />
+            </router-link>
+          </el-tooltip>
+          <el-tooltip v-else class="item" effect="dark" content="查看" placement="bottom">
+            <router-link :to="'/article/examine/'+row.articleno">
+              <el-button type="primary" style="margin-right:10px" icon="el-icon-search" circle size="mini" />
+            </router-link>
+          </el-tooltip>
 
-      <pagination v-show="total>0" :total="total" :page.sync="formData.page" :limit.sync="formData.limit" @pagination="getArticleList" />
-    </el-table></div>
+          <el-tooltip class="item" effect="dark" content="删除" placement="bottom">
+            <el-button type="primary" icon="el-icon-delete" circle size="mini" @click="deleteArticle(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="getArticleList"
+    />
+  </div>
 </template>
 
 <script>
 import moment from 'moment'
-import { getArticleList } from '@/api/article'
+import {
+  getArticleList,
+  deleteArticle,
+  switchDisplay } from '@/api/article'
 import Pagination from '@/components/Pagination' // Secondary package based on el-pagination
 
 export default {
@@ -143,7 +171,7 @@
         releasestartdate: '',
         releaseenddate: '',
         pageno: 1,
-        pagesize: 20
+        pagesize: 10
       },
       saveDate: null,
       releaseDate: null,
@@ -160,6 +188,12 @@
       }, {
         value: 'review',
         label: '审核中'
+      }, {
+        value: 'pass',
+        label: '已通过'
+      }, {
+        value: 'reject',
+        label: '已驳回'
       }],
       pickerOptions: {
         shortcuts: [{
@@ -212,7 +246,6 @@
         this.formData.releaseenddate = ''
       }
       getArticleList(this.formData).then(response => {
-        console.log(response)
         if (response.page) {
           this.list = response.page.list
           this.total = response.page.totalCount
@@ -244,6 +277,43 @@
         return ''
       }
       return moment(date).format('YYYY-MM-DD HH:mm:ss')
+    },
+    switchDisplay(row) {
+      switchDisplay(row.articleno, { 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
+      })
+    },
+    deleteArticle(row) {
+      this.$confirm('是否确认删除该文章?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        deleteArticle(row.articleno).then(response => {
+          this.$message({
+            type: 'success',
+            message: '删除成功!'
+          })
+          this.handleFilter()
+        }).catch(error => {
+          this.$message({
+            message: error.msg || '请求异常',
+            type: 'error'
+          })
+          this.listLoading = false
+        })
+      }).catch(() => {
+      })
     }
   }
 }