springboot+vue实现文章公告通知管理
分类: springboot vue 专栏: springboot vue 常用功能 标签: springboot+vue实现文章公告通知管理
2025-02-19 22:20:15 250浏览
springboot+vue实现文章公告通知管理
sql
-- ---------------------------- DROP TABLE IF EXISTS `xl_article`; CREATE TABLE `xl_article` ( `id` int(0) NOT NULL AUTO_INCREMENT, `cts` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `atitle` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `acont` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `adesc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `uid` int(0) DEFAULT NULL, `aimg` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `sh` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `msg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, `tid` int(0) DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; SET FOREIGN_KEY_CHECKS = 1;
bean
package com.jff.xinli.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.List;
/*文章
*/
@Data
@TableName("xl_article")
public class XlArticle {
@TableId(type = IdType.AUTO)
Integer id;
Integer uid;
Integer tid;
String cts;
String atitle;
String acont;
String adesc;
String aimg;
String sh;
String msg;
String tags;
@TableField(exist = false)
String tname;
@TableField(exist = false)
String timg;
@TableField(exist = false)
String nickname;
@TableField(exist = false)
String faceimg;
@TableField(exist = false)
String keywords;
@TableField(exist = false)
private List<String> tagsli;
}
xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jff.xinli.dao.XlArticleMapper">
<select id="getListJoin" resultType="com.jff.xinli.bean.XlArticle" parameterType="com.jff.xinli.bean.XlArticle">
select a.*,u.nickname,u.faceimg,t.tname,t.timg
from xl_article a
left join xl_users u on u.id=a.uid
left join xl_type t on t.id=a.tid
WHERE 1=1
<if test=" sh != null and sh != ''">
and a.sh = #{sh}
</if>
<if test=" keywords != null and keywords != ''">
and(
a.atitle like concat('%',#{keywords},'%')
or a.acont like concat('%',#{keywords},'%')
or a.tags like concat('%',#{keywords},'%')
or u.nickname like concat('%',#{keywords},'%')
or t.tname like concat('%',#{keywords},'%')
)
</if>
<if test=" uid != null ">
and u.id = #{uid}
</if>
<if test=" tid != null ">
and t.id = #{tid}
</if>
</select>
<select id="getIdJoin" resultType="com.jff.xinli.bean.XlArticle" parameterType="java.lang.Integer">
select a.*,u.nickname,u.faceimg,t.tname,t.timg
from xl_article a
left join xl_users u on u.id=a.uid
left join xl_type t on t.id=a.tid
WHERE a.id = #{id}
</select>
</mapper>
dao
package com.jff.xinli.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jff.xinli.bean.XlArticle;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Mapper
public interface XlArticleMapper extends BaseMapper<XlArticle> {
List<XlArticle> getListJoin(XlArticle o);
XlArticle getIdJoin(Integer id);
}
service
package com.jff.xinli.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jff.xinli.bean.XlArticle;
import com.jff.xinli.dao.XlArticleMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class XlArticleService extends ServiceImpl<XlArticleMapper, XlArticle> {
@Autowired
XlArticleMapper articleMapper;
public List<XlArticle> getListJoin(XlArticle o){
return articleMapper.getListJoin(o);
}
public XlArticle getIdJoin(Integer id) {
return articleMapper.getIdJoin(id);
}
}
controller
package com.jff.xinli.control.api;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jff.xinli.bean.XlArticle;
import com.jff.xinli.bean.XlForum;
import com.jff.xinli.bean.XlPsyer;
import com.jff.xinli.service.XlArticleService;
import com.jff.xinli.util.DateUtils;
import com.jff.xinli.util.MessUntil;
import com.jff.xinli.util.DocumentUntil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@CrossOrigin
@RestController
@RequestMapping("/article")
public class XlArticleController {
@Autowired
XlArticleService articleService;
@RequestMapping("/page")
public MessUntil page(@RequestParam(value="pageNo",defaultValue="1")int pageNo,
@RequestParam(value="pageSize",defaultValue="10")int pageSize, XlArticle u ) {
MessUntil mess=new MessUntil();
PageHelper.startPage(pageNo,pageSize," id desc ");
List<XlArticle> li=articleService.getListJoin(u);
PageInfo<XlArticle> pageInfo = new PageInfo(li,pageSize);
return mess.succ(pageInfo);
}
@RequestMapping("/save")
public MessUntil save(XlArticle o) {
MessUntil mess=new MessUntil();
if(o.getId()==null){
o.setCts(DateUtils.getNowDateTsString());
}
o.setSh("0");
if(o.getAcont()!=null&&o.getAcont().trim().length()>0){
o.setAdesc(DocumentUntil.getP(o.getAcont(),200));
o.setAimg(DocumentUntil.getFirstImg(o.getAcont()));
}
articleService.saveOrUpdate(o);
return mess.succ();
}
@RequestMapping("/update")
public MessUntil update(XlArticle o) {
MessUntil mess=new MessUntil();
articleService.updateById(o);
return mess.succ();
}
@RequestMapping("detail")
public MessUntil detail(Integer id ) {
MessUntil mess=new MessUntil();
if(id==null )return mess.error( "参数错误");
XlArticle o=articleService.getIdJoin(id);
if(o!=null && o.getSh()!=null&& o.getSh().equals("1")) {
o.setTagsli(getTagsli(o));
return mess.succ(o) ;
}
return mess.error("该数据不存在或待审核");
}
@RequestMapping("del")
public MessUntil del(Integer id ) {
MessUntil mess=new MessUntil();
if(id==null )return mess.error( "参数错误");
try{
articleService.removeById(id);
}catch (Exception e){
return mess.error( "删除失败,请先删除关联数据");
}
return mess.succ( );
}
private List<String> getTagsli(XlArticle o){
List<String> s=new ArrayList<>();
if(o==null)return s;
String tags=o.getTags();
if(tags!=null&&tags.trim().length()>0){
tags= tags.replace(",","@#@").replaceAll(",","@#@");
String[] arr=tags.split("@#@");
for(String ss:arr){
if(ss!=null&&ss.trim().length()>0)s.add(ss);
}
}
return s;
}
}
vue
admin
<template>
<div class="about">
<v-header />
<v-sidebar />
<div class="content-box" >
<div class="content">
<div>
<div class="crumbs">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<i class="el-icon-s-home"></i>
文章管理
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="container">
<div class="handle-box">
<el-input placeholder="标题,内容,标签,作者昵称" style="width:250px;" v-model="query.keywords"></el-input>
<el-select placeholder="请选择分类" v-model="query.tid" filterable>
<el-option label="请选择分类" value=""></el-option>
<el-option v-for="(t,i) in typeli" :label="t.tname" :value="t.id"></el-option>
</el-select>
<el-select v-model="query.sh" placeholder="请选择状态" >
<el-option label="请选择状态" value=""></el-option>
<el-option label="待审核" value="0"></el-option>
<el-option label="审核通过" value="1"></el-option>
<el-option label="审核不通过" value="-1"></el-option>
</el-select>
<el-button type="primary" @click="searchHandle">查找</el-button>
<el-button type="danger" @click="addHandle">发布文章</el-button>
</div>
<el-card style="margin-bottom: 10px;" class="box-card" v-for="(t,i) in tableData" >
<div slot="header" class="clearfix">
<span>{{t.atitle}}</span>
<el-tag type="info" v-if="t.sh=='0'">待审核</el-tag>
<el-tag type="danger" v-if="t.sh=='-1'">不通过</el-tag>
<el-tag type="success" v-if="t.sh=='1'">审核通过</el-tag>
<span v-if="t.sh=='-1'" style="color: red">({{t.msg}})</span>
<el-button v-if="lander.id==t.uid" style="float: right;" size="mini" type="danger" @click="delHandle(t)">删除</el-button>
<el-button v-if="lander.id==t.uid" style="float: right;" size="mini" type="success" @click="editHandle(t)">编辑</el-button>
<el-button v-if="lander.role=='admin'" style="float: right;" size="mini" type="warning" @click="seeinfoHandle(t)">审核</el-button>
</div>
<div class="hh">
<el-row>
<el-col :span="4">
<div style="width: 90%;height: 100px;overflow: hidden;">
<img :src="t.aimg" style="width: 100px; ">
</div>
</el-col>
<el-col :span="20">
{{t.adesc}}..<span @click="seeinfoHandle(t)" style="color:blue;font-size: 12px;">【查看详情】</span>
<br>
<br>
<p style="font-size: 13px;color: #666;">标签:{{t.tags}}</p>
<br>
<div >
<img :src="FILE_URL+t.faceimg" style="width: 30px;height:30px;border-radius: 50%;float: left;">
<span style="font-size: 13px;color: #666;line-height: 30px;margin-left: 5px;">{{t.nickname}} {{t.cts}}发布 , 分类:{{t.tname}}</span>
</div>
</el-col>
</el-row>
</div>
</el-card>
<div v-if="tableData.length==0" style="text-align:center;">
<br>
<br>
<img src="../../assets/img/nosj.png">
<br>
<br>
暂无数据
<br>
<br>
</div>
<el-pagination v-else
:page-sizes="[10,20,50,100,500]"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="query.pageNo"
:page-size="query.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</div>
</div>
<el-dialog title="查看 " fullscreen :visible.sync="infoVisible" >
<h1 style="text-align: center;">{{infoObj.atitle}}</h1>
<div class="hh" style="padding: 50px 10%;">
<br>
<div>
<img :src="FILE_URL+infoObj.faceimg" style="width: 30px;height:30px;border-radius: 50%;float: left;">
<span style="font-size: 13px;color: #666;line-height: 30px;margin-left: 5px;">{{infoObj.nickname}} {{infoObj.cts}}发布 , 分类:{{infoObj.tname}}</span>
</div>
<el-divider></el-divider>
<br>
<div v-html="infoObj.acont"></div>
<br>
<br>
<p style="font-size: 13px;color: #666;">标签:{{infoObj.tags}}</p>
<br>
<div style="text-align: center;" v-if="lander.role=='admin'">
<el-divider></el-divider>
<el-button type="danger" @click="savestate(-1)">审核不通过</el-button>
<el-button type="primary" @click="savestate(1)">审核通过</el-button>
</div>
</div>
</el-dialog>
<el-dialog :title="(ruleForm.id?'编辑':'添加') " fullscreen :visible.sync="addVisible" >
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="120px" class="demo-ruleForm">
<el-form-item label="标题" prop="atitle">
<el-input v-model="ruleForm.atitle"></el-input>
</el-form-item>
<el-form-item label="分类" prop="tid">
<el-select v-model="ruleForm.tid" filterable>
<el-option v-for="(t,i) in typeli" :label="t.tname" :value="t.id"></el-option>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tags">
<el-input v-model="ruleForm.tags" type="textarea"></el-input>
<p>逗号分隔</p>
</el-form-item>
<el-form-item label="内容" >
<quill-editor ref="myQuillEditor" v-model="ruleForm.acont" :options="editorOption" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addVisible = false">取 消</el-button>
<el-button type="primary" @click="submitForm">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { quillEditor,Quill} from 'vue-quill-editor'
import {container, ImageExtend, QuillWatch} from 'quill-image-extend-module'
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
Quill.register('modules/ImageExtend', ImageExtend)
import '../../api/image-paste.min.js';
let CON_ACTION=process.env.VUE_APP_API_ROOT+'/common/upimg?type=article_detail';
import vHeader from "./Header.vue";
import vSidebar from "./Sidebar.vue";
import {
article_page,
article_add,
article_del, type_list, article_update,
} from '../../api/index'
export default {
name: "users",
components: {
vHeader,
vSidebar,
quillEditor
},
data() {
return {
FILE_URL:'',
typeli:[],
infoVisible:false,
infoObj:{},
lander:{},
query:{
pageNo:1,
pageSize:10,
keywords:'',
sh:'',
},
total:0,
tableData:[],
addVisible: false,
ruleForm: {
atitle: '',
tid: '',
acont: '',
tags:'',
},
rules: {
atitle: [ {required: true, message: '请输入', trigger: 'blur'}, ],
tid: [ {required: true, message: '请输入', trigger: 'blur'}, ],
tags: [ {required: true, message: '请输入', trigger: 'blur'}, ],
acont: [ {required: true, message: '请输入', trigger: 'blur'}, ],
},
editorOption: {
modules: {
/* 还有一些其他的模块*/
imagePaste: {
addImageBlob: function (blob, callback) {
var formData = new FormData()
formData.append('file', blob)
// your upload function, get the uploaded image url, add then
let config = {
headers: {
"Content-Type": "multipart/form-data",
"Accept": "*/*"
}
}
// 上传接口
axios.post(CON_ACTION, formData, config).then(res => {
console.log(res);
let imgUrl = res.data.obj // 服务器返回的图片url
callback(imgUrl)
})
}
},
ImageExtend: { // 如果不作设置,即{} 则依然开启复制粘贴功能且以base64插入
loading: true,//可选参数 是否显示上传进度和提示语
name: 'file', // 图片参数名
size: 3, // 可选参数 图片大小,单位为M,1M = 1024kb
action: CON_ACTION, // 服务器地址, 如果action为空,则采用base64插入图片
// response 为一个函数用来获取服务器返回的具体图片地址
// 例如服务器返回{code: 200; data:{ url: 'baidu.com'}}
// 则 return res.data.url
response: res => {
return res.obj;
},
// headers: xhr => {
// 上传图片请求需要携带token的 在xhr.setRequestHeader中设置
// xhr.setRequestHeader(
// "Authorization",
// this.getCookie("useatitle")
// ? this.getCookie("useatitle").token_type +
// this.getCookie("useatitle").access_token
// : "Basic emh4eTp6aHh5"
// );
// }, // 可选参数 设置请求头部
sizeError: () => {
}, // 图片超过大小的回调
start: () => {
}, // 可选参数 自定义开始上传触发事件
end: () => {
}, // 可选参数 自定义上传结束触发的事件,无论成功或者失败
error: () => {
}, // 可选参数 上传失败触发的事件
success: () => {
}, // 可选参数 上传成功触发的事件
// change: (xhr, formData) => {
// xhr.setRequestHeader('myHeader','myValue')
// formData.append('token', 'myToken')
// } // 可选参数 每次选择图片触发,也可用来设置头部,但比headers多了一个参数,可设置formData
},
toolbar: {
container: container,
handlers: {
'image': function () {
QuillWatch.emit(this.quill.id)
}
}
}
},
//主题
theme: "snow",
placeholder: "请输入正文"
},
};
},
methods:{
savestate( sh){
if(sh=='1'){
article_update({id: this.infoObj.id,sh:sh,msg:''}).then((res) => {
let data = res.data;
if(data.status==1){
this.$message.success(data.msg);
this.getPage();
this.infoVisible=false;
}else{
this.$message.error(data.msg);
}
})
}else{
this.$prompt('请输入审核不通过 的原因', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
}).then(({ value }) => {
article_update( { id:this.infoObj.id,sh:sh,msg:value } ).then((res)=>{
this.getPage();
this.infoVisible=false;
})
}).catch((e) => {
console.log(e)
this.$message({
type: 'info',
message: '取消输入'
});
});
}
},
seeinfoHandle(t) {
this.infoVisible=true;
this.infoObj=t;
if( this.infoObj.acont!=null){
this.infoObj.acont= this.infoObj.acont.replace(/<img/g,"<img style='max-width:100%;height:auto;'");;
}
},
searchHandle(){
this.query.pageNo=1;
this.getPage();
},
handleSizeChange(val) {
this.query.pageSize=val;
this.query.pageNo=1;
this.getPage();
},
handleCurrentChange(val) {
this.query.pageNo=val;
this.getPage();
},
getPage(){
article_page( this.query ).then((res)=>{
let data=res.data;
this.tableData=data.obj.list;
this.total=data.obj.total;
})
},
addHandle(){
this.ruleForm={};
this.addVisible=true;
this.ruleForm.uid=this.lander.id;
this.ruleForm.ntype =this.query.ntype;
},
editHandle(row){
this.ruleForm.id=row.id;
this.ruleForm.atitle=row.atitle;
this.ruleForm.tid=row.tid;
this.ruleForm.tags=row.tags;
if(row.acont!=null){
this.ruleForm.acont= row.acont.replace(/<img/g,"<img style='max-width:100%;height:auto;'");;
}
this.addVisible=true;
},
delHandle(row) {
this.$confirm('确定删除?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
article_del({id: row.id}).then((res) => {
let data = res.data;
if(data.status==1){
this.getPage();
}else{
this.$message.error(data.msg);
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
submitForm() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
article_add(this.ruleForm).then((res)=>{
let data=res.data;
if(data.status==1){
this.addVisible=false;
this.getPage();
}else{
this.$message.error(data.msg);
}
})
} else {
this.$message.info("请按要求输入")
return false;
}
});
},
gettypeli(){
type_list( {ttype:'article'} ).then((res)=>{
let data=res.data;
this.typeli=data.obj ;
})
},
},
mounted() {
this.lander=JSON.parse(localStorage.loginUser)
this.FILE_URL=process.env.VUE_APP_API_ROOT
if(this.lander.role=='psy')this.query.uid=this.lander.id;
this.getPage();
this.gettypeli();
},
}
</script>
<style scoped>
.handle-box {
margin-bottom: 20px;
}
.hh{ word-wrap: break-word; word-break:break-all }
</style>
qt
<template>
<div>
<!-- section begin -->
<section id="de-subheader" class="mt-sm-60 pt20 pb20 bg-gradient-45-deg text-light">
<div class="container relative z-index-1000">
<div class="row align-items-center">
<div class="col-lg-6">
<h3 class="mb-0"></h3>
</div>
<div class="col-lg-6 text-lg-end">
<ul class="crumb">
<li><router-link to="/Index">首页</router-link></li>
<li class="active">知识</li>
</ul>
</div>
</div>
</div>
</section>
<!-- section close -->
<section>
<div class="container">
<div style="text-align: right;">
<el-input placeholder="标题" style="width: 200px;" v-model="query.keywords"></el-input>
<el-button type="success" icon="el-icon-search" @click="searchHandle">搜索</el-button>
</div>
<div class="row">
<div class="col-lg-2 col-md-2 ">
<ul id="filters" class="s2">
<li><a @click="seltype('')" :class="query.tid==''?'selected':''">全部分类</a></li>
<li v-for="(t,i) in typeli"><a @click="seltype(t.id)" :class="query.tid==t.id?'selected':''" >{{t.tname}}</a></li>
</ul>
</div>
<div class="col-lg-8 col-md-8 ">
<div class="mb10" v-for="(t,i) in tableData">
<div class="rounded-20px">
<el-row>
<el-col :span="8">
<div class="post-image rounded-10px">
<div class="d-tagline">
<span>{{t.tname}}</span>
</div>
<img alt="" :src="t.aimg" class="lazy">
</div>
</el-col>
<el-col :span="15" :offset="1">
<div class="pt-2 h-100">
<h4><router-link :to="'QtArticleDetail?id='+t.id" class="text-dark" target="_blank">{{t.atitle}}</router-link></h4>
<p class="mb-3">{{t.adesc}}... <router-link :to="'QtArticleDetail?id='+t.id" style="color: green;font-size: 12px;" target="_blank">【查看详情】</router-link></p>
<div class="relative bg-grey p-1 px-3 rounded-10px">
<img :src="FILE_URL+t.faceimg" class="w-20px me-2 circle" alt="">
<div class="d-inline fs-14 fw-bold me-3">{{t.nickname}}</div>
<div class="d-inline fs-14 fw-600"><i class="icofont-ui-calendar id-color me-2"></i>{{t.cts}}</div>
</div>
</div>
<el-divider></el-divider>
</el-col>
</el-row>
</div>
</div>
<el-pagination
v-if="tableData.length>0"
:page-sizes="[10,20,50,100,500]"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="query.pageNo"
:page-size="query.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
<div v-if="tableData.length==0" style="line-height: 200px;text-align: center;">
<img src="../../assets/img/nosj.png">
<br>
没搜索到数据哦</div>
<br>
<br>
<br>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
import {article_page, type_list} from '../../api';
export default {
name:'Uinfo',
components: {
},
data() {
return {
typeli:[],
islogin:0,
FILE_URL : '',
lander :{},
query:{
pageNo:1,
pageSize:10,
keywords:'',
sh:1,
tid:'',
},
total:0,
tableData:[],
};
},
methods:{
seltype(tid){
this.query.tid=tid;
this.query.keywords='';
this.query.pageNo=1;
this.getPage();
},
gettypeli(){
type_list( {ttype:'article'} ).then((res)=>{
let data=res.data;
this.typeli=data.obj ;
})
},
handleSizeChange(val) {
this.query.pageSize=val;
this.query.pageNo=1;
this.getPage();
},
handleCurrentChange(val) {
this.query.pageNo=val;
this.getPage();
},
getPage(){
article_page( this.query ).then((res)=>{
let data=res.data;
this.tableData=data.obj.list;
this.total=data.obj.total;
})
},
searchHandle(){
this.query.pageNo=1;
this.getPage();
},
},mounted() {
this.query.keywords = this.$route.query.keywords;
try{
this.islogin=1;
this.lander=JSON.parse(localStorage.loginUser);
}catch(err){
this.islogin=0;
}
this.FILE_URL=process.env.VUE_APP_API_ROOT;
this.query.pageNo=1;
this.getPage();
this. gettypeli();
},
watch:{
$route:function(value){
this.query.keywords =value.query.keywords;
this.query.pageNo=1;
this.getPage();
}
}
};
</script>
<style scoped>
/deep/ .el-input__icon {
height:auto;}
</style>
详情:
<template>
<div>
<!-- section begin -->
<section id="de-subheader" class="mt-sm-60 pt20 pb20 bg-gradient-45-deg text-light">
<div class="container relative z-index-1000">
<div class="row align-items-center">
<div class="col-lg-6">
<h3 class="mb-0"></h3>
</div>
<div class="col-lg-6 text-lg-end">
<ul class="crumb">
<li><router-link to="/Index">首页</router-link></li>
<li class="active">{{obj.atitle}}</li>
</ul>
</div>
</div>
</div>
</section>
<!-- section close -->
<section style="background-size: cover; background-repeat: no-repeat;">
<div class="container" style="background-size: cover; background-repeat: no-repeat;">
<div class="row gx-5" style="background-size: cover; background-repeat: no-repeat;">
<div class="col-lg-8" style="background-size: cover; background-repeat: no-repeat;">
<div style="background-size: cover; background-repeat: no-repeat;">
<h2>{{obj.atitle}}</h2>
<div class="relative bg-grey p-1 px-3 rounded-10px">
<img :src="FILE_URL+obj.faceimg" class="w-20px me-2 circle" alt="">
<div class="d-inline fs-14 fw-bold me-3">{{obj.nickname}}</div>
<div class="d-inline fs-14 fw-600"><i class="icofont-ui-calendar id-color me-2"></i>{{obj.cts}}</div>
</div>
<div v-html="obj.acont"> </div>
</div>
<div id="blog-comment" style="background-size: cover; background-repeat: no-repeat;">
<h4>评论 ({{pageTotal}})</h4>
<div class="spacer-half" style="background-size: cover; background-repeat: no-repeat;"></div>
<ol>
<li v-for="(t,i) in tableData">
<div class="avatar" style="background-size: cover; background-repeat: no-repeat;">
<img :src="FILE_URL+t.faceimg" alt=""></div>
<div class="comment-info" style="background-size: cover; background-repeat: no-repeat;">
<span class="c_name">{{t.userNickname}}</span>
<span class="c_date id-color">{{t.cts}}</span>
<span class="c_reply"><a style="color: red;" @click="delC(t,i)" v-if="islogin==1&&t.uid==lander.id" >删除该评论</a></span>
<div class="clearfix" style="background-size: cover; background-repeat: no-repeat;"></div>
</div>
<div class="comment" style="background-size: cover; background-repeat: no-repeat;"> {{t.context}}</div>
</li>
</ol>
<div v-if="tableData.length==0" style="line-height: 200px;text-align: center;">
<img src="../../assets/img/nopl.png">
<br>
暂时没人评论哦</div>
<div class="pagination" v-if="tableData.length>0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handlePageChange"
:current-page="query.pageNo"
:page-sizes="[10,20,50,100, 200, 300, 400,500]"
:page-size="query.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageTotal">
</el-pagination>
</div>
<div class="spacer-single" style="background-size: cover; background-repeat: no-repeat;"></div>
<div id="comment-form-wrapper" style="background-size: cover; background-repeat: no-repeat;">
<h4>说两句吧</h4>
<div class="comment_form_holder" style="background-size: cover; background-repeat: no-repeat;">
<textarea cols="10" v-model="acont" rows="10" name="message" placeholder="请输入评论" class="form-control"></textarea>
<br>
<br>
<p id="btnsubmit">
<input type="button" @click="saveC" value="发布评论" class="btn-main"></p>
</div>
</div>
</div>
</div>
<div class="col-lg-4" style="background-size: cover; background-repeat: no-repeat;">
<div class="widget widget-post" style="background-size: cover; background-repeat: no-repeat;">
<h4>最新知识</h4>
<ul class="de-bloglist-type-1">
<li v-for="(t,i) in lastArticleli">
<div class="d-image" style="background-size: cover; background-repeat: no-repeat;">
<img :src="t.aimg" alt="">
</div>
<div class="d-content" style="background-size: cover; background-repeat: no-repeat;">
<router-link :to="'/QtArticleDetail?id='+t.id" href="#"><h4>{{t.atitle}}</h4></router-link>
<div class="d-date" style="background-size: cover; background-repeat: no-repeat;">{{t.cts}}</div>
</div>
</li>
</ul>
<p class="zwsj" v-if="lastArticleli.length==0">
<br>
<img style="width: 50%" src="../../assets/img/nod.png">
<br>
暂无数据
<br>
</p>
</div>
<div class="widget widget_tags" style="background-size: cover; background-repeat: no-repeat;">
<h4>标签</h4>
<ul>
<li v-for="(t,i) in obj.tagsli"><router-link :to="'/QtArticle?keywords='+t">{{t}}</router-link></li>
</ul>
</div>
</div>
</div>
</div>
</section>
</div>
</template>
<script>
import {article_detail, comment_page, comment_del, comment_save, article_page} from '../../api';
export default {
name: "Detail",
components: {
},
data() {
return {
islogin:0,
lastArticleli:[],
lander:{},
id:'',
obj:{},
acont:'',
FILE_URL:'',
query: {
fid: '',
pageNo: 1,
pageSize: 10,
ctype:'article',
},
tableData: [],
pageTotal: 0,
};
},
methods:{
// 分页导航
handlePageChange(val) {
this.query.pageNo = val;
this.getPage();
},
handleSizeChange(val){
this.query.pageNo = 1;
this.query.pageSize=val;
this.getPage();
},
saveC() {
if(this.islogin==0){
this.$message.info("请登录");return;
}
if ( this.acont.trim().length==0) {
this.$message.error('请输入内容');
return ;
}
let o={uid:this.lander.id,fid:this.id,context: this.acont, ctype:this.query.ctype };
comment_save(o).then((res) => {
if(res.data.status==1){
this.acont='';
this.$message.success("评论成功");
this.query.pageNo=1;
this.getPage();
}else{
this.$message.info(res.data.msg);
}
})
},
delC(t,index){
// 二次确认删除
this.$confirm("确定要删除吗?", "提示", {
type: "warning",
})
.then(() => {
comment_del({id:t.id}).then((res) => {
if(res.data.status==1){
this.$message.success("删除成功");
this.obj.commentNum=res.data.obj;
this.getPage();
}else{
this.$notify({
title: '提示',
message: res.data.msg,
duration: 0
});
}
})
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消'
});
});
},
getPage() {
this.query.fid=this.id;
comment_page(this.query).then((res) => {
this.tableData =res.data.obj.list;
this.pageTotal = res.data.obj.total//该页总共多少条记录
})
},
getObj(){
article_detail({id:this.id}).then((res) => {
if(res.data.status==1){
this.obj = res.data.obj ;
if(this.obj.acont!=null){
this.obj.acont= this.obj.acont.replace(/<img/g,"<img style='max-width:100%;height:auto;'");;
}
this.getlastarticle();
}else{
this.$message.error(res.data.msg)
localStorage.systip=res.data.msg
this.$router.replace("/Tip")
}
})
},
getlastarticle(){
article_page( {tid:this.obj.tid,sh:1} ).then((res)=>{
let data=res.data;
this.lastArticleli=data.obj.list;
})
},
},
mounted() {
this.FILE_URL=process.env.VUE_APP_API_ROOT;
this.id = this.$route.query.id;
localStorage.tol='/QtArticleDetail?id='+this.id;
try{
this.lander=JSON.parse(localStorage.loginUser);
this.islogin=1;
}catch (e) {
this.islogin=0;
}
this.getObj();
this.getPage();
},
watch:{
$route:function(value){
this.id =value.query.id;
this.getObj();
this.getPage();
}
}
}
</script>
<style scoped>
.zwsj{text-align: center;}
</style>
好博客就要一起分享哦!分享海报
此处可发布评论
评论(0)展开评论
暂无评论,快来写一下吧
展开评论
他的专栏
他感兴趣的技术






java
vue
springboot
Mysql
ssm
小程序
uniapp
js和jquery