搜索功能完善

This commit is contained in:
2023-07-06 13:58:57 +08:00
parent d8e6771cfe
commit 9017864f82
13 changed files with 736 additions and 83 deletions

View File

@@ -15,19 +15,52 @@
<el-menu-item class="menu-item" index="/paper"><i class="el-icon-s-management" style="color: #5b6bc9"></i> </el-menu-item>
</el-menu>
<SearchInput class="HeaderInput"></SearchInput>
<el-button v-if="this.$route.path!=='/paper'" class="HeaderSubmitBtn" type="success" round icon="el-icon-thumb">提交项目</el-button>
<el-button v-if="this.$route.path ==='/paper'" class="HeaderSubmitBtn" type="primary" round icon="el-icon-edit">发布文章</el-button>
<el-button v-if="this.$route.path!=='/paper'" class="HeaderSubmitBtn" type="success" round icon="el-icon-thumb">提交项目</el-button>
<el-button @click="openPublishDialog" v-if="this.$route.path ==='/paper'" class="HeaderSubmitBtn" type="primary" round icon="el-icon-edit">发布文章</el-button>
<el-dialog
:visible.sync="openPublishArticle"
width="55vw"
append-to-body
:close-on-click-modal="false"
>
<div slot="title" class="dialog-title" style="display: flex;flex-direction: row;flex-wrap: nowrap;justify-content: space-between;align-items: center">
<span class="title-text" style="font-size: 18px;font-weight: bold;">发布文章</span>
</div>
<div>
<PublishArticle></PublishArticle>
</div>
</el-dialog>
</div>
</template>
<script>
import SearchInput from "@/components/Home/SearchInput.vue";
import PublishArticle from "@/components/Paper/PublishArticle.vue";
import Vue from "vue";
export default {
name: "HeaderComponent",
components: {SearchInput},
components: {PublishArticle, SearchInput},
data() {
return {}
return {
openPublishArticle:false,
}
},
methods:{
openPublishDialog(){
if(this.$cookie.get('username')){
this.openPublishArticle=true;
}else{
Vue.prototype.$notify.error({
title: '错误',
message: "请先登录!",
offset: 50
});
}
},
}
}
</script>

View File

@@ -1,7 +1,7 @@
<template>
<el-container style="display: flex;flex-direction: row;">
<el-aside width="22vw"
style=" height: calc(80vh - 60px); display: flex;flex-direction: row;justify-content: flex-end;margin-top: 5vh;">
style=" height: calc(80vh - 60px); display: flex;flex-direction: row;justify-content: flex-end;margin-top: 7vh;">
<template>
<el-card class="box-card"
style="position: fixed;width: 10vw;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)">
@@ -31,7 +31,7 @@
<el-main style="display: flex;flex-direction: row;flex-wrap: nowrap;">
<template>
<div class="main">
<el-tabs v-model="activeName" type="border-card" style="width: 45vw;" @tab-click="tabChange">
<el-tabs v-model="activeName" type="border-card" style=";margin-top:2.5vh;width: 45vw;" @tab-click="tabChange">
<el-tab-pane label="最新" name="first">
<ul
class="list"
@@ -68,7 +68,7 @@
</el-tab-pane>
</el-tabs>
</div>
<div style="margin-left: 20px;display: flex;flex-direction: column;flex-wrap: nowrap;">
<div style="margin-top: 2.5vh;margin-left: 20px;display: flex;flex-direction: column;flex-wrap: nowrap;">
<el-card class="box-card" style="width: 15vw">
<el-button type="info" plain @click="openLogin" v-show="this.$cookie.get('username')==null"> </el-button>
<UserInfo></UserInfo>
@@ -196,7 +196,6 @@ export default {
num: "0",
}
}).then((res)=>{
// console.log(res.data);
that.projectLists=res.data;
});
},
@@ -212,7 +211,6 @@ export default {
name:name
}
}).then((res)=>{
// console.log(res.data);
that.projectLists=res.data;
});
},

View File

@@ -206,7 +206,7 @@ export default {
_this.$emit('update:loginDialogVisible', false);
setTimeout(()=>{
window.location.reload();
},1000)
},800)
} else {
Vue.prototype.$notify.error({

View File

@@ -37,18 +37,37 @@
</div>
</div>
<div style="margin-top: 10px">
<div style="display: flex;flex-direction: row;justify-content: space-between">
<span class="title">搜索结果</span>
<span class="clear" @click="clearSearchResults"><i class="el-icon-circle-close"></i>清空</span>
</div>
<div>
<el-scrollbar style="height: 50vh" v-show="JSON.parse(JSON.stringify(searchResults)).length!==0">
<div v-for="(item,index) in JSON.parse(JSON.stringify(searchResults))" :key="index">
<SearchResultsList :search-result="item"></SearchResultsList>
</div>
</el-scrollbar>
<el-empty v-show="JSON.parse(JSON.stringify(searchResults)).length===0" description="暂无搜索结果" :image-size="50"></el-empty>
</div>
</div>
</div>
</el-popover>
<el-input
size="medium"
:placeholder="tipsWord"
style="width: 20vw"
clearable
v-popover:popover
@keyup.enter.native="searchRequest"
@keyup.enter.native="searchByInput"
v-model="search">
<i slot="suffix" class="el-input__icon el-icon-search" style="cursor: pointer" @click="searchRequest"></i>
<i slot="suffix" class="el-input__icon el-icon-search" style="cursor: pointer" @click="searchByInput"></i>
</el-input>
</div>
</template>
@@ -57,8 +76,10 @@
<script>
import axios from "axios";
import Vue from "vue";
import SearchResultsList from "@/components/Home/SearchResultsList.vue";
export default {
components: {SearchResultsList},
data() {
return {
@@ -67,14 +88,18 @@ export default {
search: '',
tipsWord: '',
historySearch: null,
items: [
]
searchResults:[],
update:true,
}
},
methods: {
handleSearch(word) {
this.search = word
this.searchRequest()
this.searchByInput()
},
clearSearchResults(){
this.searchResults=[];
},
clearHistory() {
axios({
@@ -101,14 +126,14 @@ export default {
}
});
},
searchRequest() {
const params = {
word: this.search || this.tipsWord
}
const queryString = new URLSearchParams(params).toString();
const url = `${window.location.origin}/video/search?${queryString}`;
window.open(url, '_blank');
},
// searchRequest() {
// const params = {
// word: this.search || this.tipsWord
// }
// const queryString = new URLSearchParams(params).toString();
// const url = `${window.location.origin}/video/search?${queryString}`;
// window.open(url, '_blank');
// },
gethistorySearch(){
var that=this;
axios({
@@ -148,12 +173,69 @@ export default {
});
}
});
},
searchByInput(){
var that=this;
if(this.search!==''){
axios({
method: 'post',
// 请求的地址
url: 'http://localhost:8082/helloGithub_war_exploded/selectByInput',
// URL 中的查询参数
params: {
content:this.search,
}
}).then((res)=>{
// JSON.parse(JSON.stringify(res.data));
that.searchResults= JSON.parse(JSON.stringify(res.data));
if(res.data.code===500){
Vue.prototype.$notify.error({
title: '错误',
message: res.data.msg,
offset: 50
});
that.searchResults=[];
that.reload();
}else{
Vue.prototype.$notify({
title: '成功',
message: ('i', {style: 'color: teal'}, "查询成功"),
type:"success",
offset: 50
});
}
});
}else{
Vue.prototype.$notify.error({
title: '错误',
message: '请输入搜索内容',
offset: 50
});
}
},
reload() {
// 移除组件
this.update = false
// 在组件移除后,重新渲染组件
// this.$nextTick可实现在DOM 状态更新后,执行传入的方法。
this.$nextTick(() => {
this.update = true
})
}
},
mounted() {
this.tipsWord = "搜索开源项目";
this.gethistorySearch();
}
},
created() {
setTimeout(() => {
this.visible = true;
this.gethistorySearch();
}, 200);
},
};
</script>
@@ -174,9 +256,14 @@ export default {
}
.search-content .search-his span.clear:hover {
color: #00aeec;
color: #ec0014;
}
.clear{
cursor: pointer;
}
.clear:hover{
color: #ec0014;
}
.search-content .mt {
margin-top: 10px;
}

View File

@@ -0,0 +1,85 @@
<template>
<div class="SearchResult" @click="goToProjectDeatil" style=";align-items:center;cursor: pointer;margin-top: 5px;display: flex;flex-direction: row;flex-wrap: nowrap">
<div style="width: 50px;height: 50px;">
<el-avatar :size="50" :src="searchResult.projectIco"></el-avatar>
</div>
<div style="display: flex;flex-direction: column;flex-wrap: nowrap">
<div style="margin-left:10px;display: flex;flex-direction: row;flex-wrap: nowrap">
<span style="font-size: 14px;font-weight: bold">{{briefTitle}}</span>
</div>
<div style="margin-left:10px;">
<span style="font-size: 12px">{{briefContent}}</span>
</div>
<div style=";margin-left:10px;margin-top: 5px;display: flex;flex-direction: row;justify-content: space-between;flex-wrap: nowrap">
<div style="align-items: center;font-size: 12px;color: #9ca3af">
<span>{{formatTime}}</span>
</div>
<div style="align-items: center;font-size: 12px;color: #9ca3af">
<i class="el-icon-view"></i> <span>{{formatNumber(searchResult.lookCount)}}</span>
</div>
<div style="align-items: center;font-size: 12px;color: #9ca3af">
<i class="el-icon-star-on"></i> <span>{{formatNumber(searchResult.startNum)}}</span>
</div>
<div style="margin-left: 10px;justify-content: space-between;display: flex;flex-direction:row;flex-wrap: nowrap;align-items: center;font-size: 12px;color: #9ca3af">
<div style="width: 8px;height: 8px;background-color: #ffba00;border-radius: 50px"></div>
<span style="margin-left: 5px">{{searchResult.categoryName}}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SearchResultsList",
props:{
searchResult:Object
},
data(){
return{
}
},
methods:{
formatNumber(num) {
return num >= 1e3 && num < 1e4 ? (num / 1e3).toFixed(1) + 'k' : num >= 1e4 ? (num / 1e4).toFixed(1) + 'w' : num
},
goToProjectDeatil(){
this.$router.push({
path:'/ProjectDetail',
query: {
id: this.searchResult.projectId,
refresh: true
}})
// console.log(this.$route.query.id)
},
},
computed: {
// 对时间进行格式化
formatTime: function() {
if (this.searchResult) {
const dt = new Date(this.searchResult.submitTime)
const year=dt.getFullYear()
const month = dt.getMonth()
const date = dt.getDate()
return `${year}-${month}-${date}`
}
return '';
},
// 截取文章内容的前 35 个字,并加上省略号
briefContent: function() {
return this.searchResult.projectDescription.substr(0, 17) + '...';
},
briefTitle: function() {
return this.searchResult.projectTitle.substr(0, 10) + '...';
},
},
}
</script>
<style scoped>
.SearchResult:hover{
background-color: #eeeeee;
border-radius: 10px;
}
</style>

View File

@@ -3,15 +3,15 @@
<div style="display: flex;flex-direction:column;flex-wrap: nowrap">
<div class="PageHeader">
<br/>
<el-page-header @back="goBack" style="justify-content: center;">
<el-page-header @back="goBack" style="margin-left: 20px">
<div slot="title" style="font-size:23px;font-weight: 600;"></div>
<div slot="content" style="font-size:23px;font-weight: 600;">
<div slot="content" style=";display: flex;flex-direction:row;justify-content: flex-start;font-size:23px;font-weight: 600;">
{{ArticleTitle}}
</div>
</el-page-header>
</div>
<div class="PageContent" style="display: flex;flex-direction: column;flex-wrap: nowrap;align-items: center">
<el-image fit="cover" style="width: 50vw; height: 35vh" :src="articleico">
<el-image fit="cover" style="width: 50vw; height: 35vh;margin-top: 20px" :src="articleico">
<div slot="placeholder" class="image-slot">
加载中<span class="dot">...</span>
</div>
@@ -19,7 +19,10 @@
<i class="el-icon-picture-outline"></i>
</div>
</el-image>
<el-tiptap style="margin-top: 20px" v-model="ArticleContent" :readonly="true" :showMenubar="false" :extensions="extensions" />
<el-card style="border: none;width: 50vw;box-shadow: none;">
<el-tiptap style="margin-top: 20px;text-align: left" v-html="ArticleContent" :readonly="true" :showMenubar="false" :extensions="extensions" />
</el-card>
</div>
</div>
<RightTools></RightTools>

View File

@@ -1,10 +1,201 @@
<template>
<div style="display: flex;flex-direction: column;flex-wrap: nowrap;">
<el-card style="border: none" shadow="always">
<el-form :model="form" :rules="rules" ref="ruleForm" style="display: flex;flex-direction: column">
<el-form-item prop="title">
<el-input placeholder="请输入文章标题" v-model="form.title"></el-input>
</el-form-item>
<el-form-item prop="icon">
<el-input placeholder="请输入文章缩略图" v-model="form.icon"></el-input>
</el-form-item>
<el-form-item>
<el-tiptap style="margin-top: 20px" v-model="form.content" :readonly="false" :showMenubar="true"
:extensions="extensions"/>
</el-form-item >
<el-form-item style="display: flex;flex-direction: row;justify-content: center;" prop="content">
<el-button @click="publishArticle('ruleForm')" type="success" icon="el-icon-check" circle></el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
import {
Doc,
Text,
Paragraph,
Heading,
Bold,
Italic,
Strike,
Underline,
Link,
Image,
Iframe,
CodeBlock,
Blockquote,
ListItem,
BulletList,
OrderedList,
TodoItem,
TodoList,
TextAlign,
Indent,
LineHeight,
HorizontalRule,
HardBreak,
TrailingNode,
History,
Table,
TableHeader,
TableCell,
TableRow,
FormatClear,
TextColor,
TextHighlight,
Preview,
Print,
SelectAll,
FontType,
FontSize,
CodeView,
} from "element-tiptap";
import axios from "axios";
import Vue from "vue";
export default {
name: "PublishArticle"
name: "PublishArticle",
props: {
openPublishDialog: Boolean
},
data() {
return {
extensions: [
new Link,
new Image({
uploadRequest:(file) => {
const data = new FormData();
data.append('file', file);
axios({
method: 'post',
headers:{
"Access-Control-Allow-Origin": "*",
'crossOrigin':'anonymous'
},
// 请求的地址
url: 'http://localhost:8082/helloGithub_war_exploded/upload',
// URL 中的查询参数
params: {
name:file.name,
file:data
}
}).then(function (res) {
return res.data.url;
});
}
}),
new Iframe,
new CodeBlock,
new Blockquote,
new Doc(),
new Text(),
new Paragraph(),
new Heading({level: 5}), // 支持多级标题设置为5级
new Bold({bubble: true}), // 在气泡菜单中渲染菜单按钮
new Underline({bubble: true, menubar: true}), // 在气泡菜单而不在菜单栏中渲染菜单按钮
new Italic(),
new Strike(),
new ListItem(),
new BulletList(),
new OrderedList(),
new TodoItem,
new TodoList,
new TextAlign({alignments: ['left', 'center', 'right', 'justify'],}),
new Indent({
minIndent: 0,
maxIndent: 7,
}),
new LineHeight({lineHeights: ['100%', '200%', '300%']}),
new HorizontalRule,
new HardBreak,
new TrailingNode,
new History,
new Table({resizable: true}),
new TableHeader,
new TableCell,
new TableRow,
new FormatClear,
new TextColor({bubble: true}),
new TextHighlight,
new Preview,
new Print,
new SelectAll,
new FontType,
new FontSize,
new CodeView,
],
// openPublishDialog:false,
closePublishArticle: false,
form: {
title: null,
icon: null,
content: null,
},
rules: {
title: [
// required规则o失去焦点触发
{required: true, message: "请输入标题", trigger: "blur"},
],
icon: [{required: true, message: "请输入缩略图", trigger: "blur"}],
content: [{required: true, message: "请输入内容", trigger: "blur"}],
},
}
},
methods: {
modalClose() {
this.$emit('update:openPublishDialog', false); // 直接修改父组件的属性
},
publishArticle(formName){
// var that=this;
this.$refs[formName].validate((valid) => {
if (valid) {
axios({
method: 'post',
// 请求的地址
url: 'http://localhost:8082/helloGithub_war_exploded/articlepublish',
// URL 中的查询参数
params: {
username:this.$cookie.get('username'),
articleTitle:this.form.title,
articleIco:this.form.icon,
articleContent:this.form.content,
}
}).then( (res)=> {
if(res.data.code===200){
Vue.prototype.$notify({
title: '成功',
message: ('i', {style: 'color: teal'}, res.data.msg),
type: 'success',
offset: 50
});
window.location.reload();
}else{
Vue.prototype.$notify.error({
title: '错误',
message: res.data.msg,
offset: 50
});
}
});
}});
}
}
}
</script>

View File

@@ -211,7 +211,7 @@
<span style="font-size: 14px;color: #9ca3af">{{item.commentTime}}</span>
<div style="display: flex;align-items: center">
<span style="margin-right: 5px;font-size: 14px; color: rgb(156, 163, 175);">{{ formatNumber(item.likeNum) }}</span>
<el-link @click="addLike(item.commentId)" icon="el-icon-star-off" :underline="false">点赞</el-link>
<el-link @click.once="addLike(item.commentId)" icon="el-icon-star-off" :underline="false">点赞</el-link>
</div>
</div>
@@ -250,7 +250,7 @@
<span style="font-size: 14px;color: #9ca3af">{{item.commentTime}}</span>
<div style="display: flex;align-items: center">
<span style="margin-right: 5px;font-size: 14px; color: rgb(156, 163, 175);">{{ formatNumber(item.likeNum) }}</span>
<el-link @click="addLike(item.commentId)" icon="el-icon-star-off" :underline="false">点赞</el-link>
<el-link @click.once="addLike(item.commentId)" icon="el-icon-star-off" :underline="false">点赞</el-link>
</div>
</div>
@@ -419,41 +419,48 @@ export default {
publishComment(){
var that=this;
if(this.$cookie.get('username')!=null){
axios({
method: 'post',
// 请求的地址
url: 'http://localhost:8082/helloGithub_war_exploded/comment',
// URL 中的查询参数
params: {
id:that.$route.query.id,
star:that.startValue,
content:that.textarea,
isUsed: that.radio,
}
}).then(function (res) {
if (res.data.code === 200) {
Vue.prototype.$notify({
title: '成功',
message: ('i', {style: 'color: teal'}, res.data.msg),
type: 'success',
offset: 50
});
that.getLastComment();
that.reload();
} else {
Vue.prototype.$notify.error({
title: '错误',
message: res.data.msg,
offset: 50
});
}
});
if(this.textarea !==''){
axios({
method: 'post',
// 请求的地址
url: 'http://localhost:8082/helloGithub_war_exploded/comment',
// URL 中的查询参数
params: {
id:that.$route.query.id,
star:that.startValue,
content:that.textarea,
isUsed: that.radio,
}
}).then(function (res) {
if (res.data.code === 200) {
Vue.prototype.$notify({
title: '成功',
message: ('i', {style: 'color: teal'}, res.data.msg),
type: 'success',
offset: 50
});
that.getLastComment();
that.reload();
} else {
Vue.prototype.$notify.error({
title: '错误',
message: res.data.msg,
offset: 50
});
}
});
}else{
Vue.prototype.$notify.error({
title: '错误',
message: "请填写评论内容!",
offset: 50
});
}
}else{
Vue.prototype.$notify.error({
title: '错误',
message: "你还未登录!",
offset: 50
});
}

View File

@@ -4,8 +4,9 @@
<img :src="projectLists.projectIco" style="width: 5vw;height: 5vw;margin-left: 10px;border-radius: 10px">
</div>
<div style="height: 12vh;margin-left: 5px;width: auto;display: flex;flex-direction: column;justify-content: space-between">
<div class="ProjectTitle" style="font-size: 16px;font-weight: bold;">
<div class="ProjectTitle" style="font-size: 16px;font-weight: bold;display: flex;flex-direction: row;align-items: center;justify-content: space-between">
<span>{{projectLists.projectTitle}}</span>
<el-tag style="font-size: 14px;height: 20px;text-align: center;display: flex;align-items: center;border-radius: 10px" v-if="projectLists.num>0" type="success">{{projectLists.num}}</el-tag>
</div>
<div class="summary">
<span style="font-size: 1rem">{{brief}}</span>

View File

@@ -1,11 +1,11 @@
<template>
<div style="display: flex;flex-direction: column;flex-wrap: nowrap" v-show="this.$cookie.get('username')!=null">
<div style="display: flex;flex-direction: row;align-items: center;width: 11vw;justify-content: space-between">
<div @click="toUserPage" style="display: flex;flex-direction: row;align-items: center;width: 11vw;justify-content: space-between">
<div style="display: flex;flex-direction: row;align-items: center">
<el-avatar shape="square" style=" background-color: #59A3A4;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)" size="large">{{this.$cookie.get('username')}}</el-avatar>
<el-avatar shape="square" style=" cursor: pointer;background-color: #59A3A4;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)" size="large">{{this.$cookie.get('username')}}</el-avatar>
<div style="margin-left: 5px;display: flex;flex-direction: column;justify-content: space-evenly">
<span style="font-weight: bold">{{this.$cookie.get('username')}}</span>
<span style="font-weight: 800;font-size: 13px;color: #3b82f6">Lv.1</span>
<span style="cursor: pointer;font-weight: bold">{{this.$cookie.get('username')}}</span>
<span style="cursor: pointer;font-weight: 800;font-size: 13px;color: #3b82f6">Lv.1</span>
</div>
</div>
@@ -44,6 +44,7 @@ export default {
},
methods:{
signOut(){
this.$cookie.delete('username');
// deletecookie
var that=this;
axios({
@@ -54,7 +55,6 @@ export default {
params: {
}
});
this.$cookie.delete('username');
if(this.$cookie.get('username')===null){
Vue.prototype.$notify({
title: '成功',
@@ -63,10 +63,17 @@ export default {
offset: 50
});
setTimeout(()=>{
this.$router.push({
path:'/home',
})
},1000)
window.location.reload();
},800)
}else{
Vue.prototype.$notify.error({
title: '错误',
message: ('i', {style: 'color: teal'}, "退出失败!"),
type: 'success',
offset: 50
});
}