feat:完善discuss主题相关功能及界面
@@ -6,6 +6,23 @@ export function getList(data){
|
|||||||
params:data
|
params:data
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
export function getTopList(data){
|
||||||
|
|
||||||
|
if(data==undefined)
|
||||||
|
{
|
||||||
|
data={isTop:true}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data["isTop"]=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return myaxios({
|
||||||
|
url: '/discuss',
|
||||||
|
method: 'get',
|
||||||
|
params:data
|
||||||
|
})
|
||||||
|
};
|
||||||
export function get(id){
|
export function get(id){
|
||||||
return myaxios({
|
return myaxios({
|
||||||
url: `/discuss/${id}`,
|
url: `/discuss/${id}`,
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
<template >
|
<template >
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
|
<div class="avatar-left">
|
||||||
|
<el-avatar :size="props.size" :src="iconUrl" />
|
||||||
|
|
||||||
<div class="avatar-left" >
|
<div v-if="props.isSelf">
|
||||||
<el-avatar :size="props.size" :src="userInfo.icon ?? '/src/assets/logo.ico'" />
|
<div class="nick"> {{ userInfo.nick }}</div>
|
||||||
|
</div>
|
||||||
<div v-if="props.isSelf">
|
|
||||||
<div class="nick" > {{userInfo.name}}</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!props.isSelf">
|
<div v-if="!props.isSelf">
|
||||||
<div class="nick" :class="{mt_1: props.time!='undefined'}"> {{userInfo.name}}</div>
|
|
||||||
<div class="remarks" v-if="props.time"> {{props.time}}</div>
|
<div class="nick" :class="{ mt_1: props.time != 'undefined' }"> {{ userInfo.nick }}</div>
|
||||||
<div class="remarks"> <slot name="bottom" /></div>
|
<div class="remarks" v-if="props.time"> {{ props.time }}</div>
|
||||||
|
<div class="remarks">
|
||||||
|
<slot name="bottom" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info" v-if="!props.isSelf">
|
<div class="info" v-if="!props.isSelf">
|
||||||
<el-tag class="ml-2" type="warning">V6</el-tag>
|
<el-tag class="ml-2" type="warning">V8</el-tag>
|
||||||
<el-tag class="ml-2" type="danger">管理员</el-tag>
|
<el-tag class="ml-2" type="danger">会员</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<el-button v-if="props.showWatching" type="primary" size="default" icon="Plus">关注</el-button>
|
<el-button v-if="props.showWatching" type="primary" size="default" icon="Plus">关注</el-button>
|
||||||
|
|
||||||
@@ -26,57 +28,84 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import useUserStore from '@/stores/user'
|
import useUserStore from '@/stores/user'
|
||||||
import { reactive, watch ,onMounted } from 'vue';
|
import { reactive, watch, onMounted, computed } from 'vue';
|
||||||
//userInfo
|
//userInfo
|
||||||
//{icon,name,role,id},根据判断userInfo是否等于未定义,来觉得是当前登录用户信息,还是其他人信息
|
//{icon,name,role,id},根据判断userInfo是否等于未定义,来觉得是当前登录用户信息,还是其他人信息
|
||||||
const props = defineProps(['size','showWatching','time','userInfo','isSelf'])
|
const props = defineProps(['size', 'showWatching', 'time', 'userInfo', 'isSelf'])
|
||||||
const userStore=useUserStore();
|
const userStore = useUserStore();
|
||||||
const userInfo=reactive({
|
const userInfo = reactive({
|
||||||
icon:"",
|
icon: "",
|
||||||
name:"",
|
nick: "",
|
||||||
role:[],
|
role: [],
|
||||||
id:""
|
id: ""
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const iconUrl = computed(() => {
|
||||||
|
if (userInfo.icon == null || userInfo.icon == undefined || userInfo.icon == '') {
|
||||||
|
|
||||||
|
return '/src/assets/logo.ico';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInfo.icon.includes(import.meta.env.VITE_APP_BASEAPI)) {
|
||||||
|
return userInfo.icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return `${import.meta.env.VITE_APP_BASEAPI}/file/${userInfo.icon}`;
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(userStore, (n) => {
|
||||||
|
if (props.userInfo == undefined) {
|
||||||
|
userInfo.nick = n.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props, (n) => {
|
||||||
|
Init();
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
Init();
|
||||||
|
})
|
||||||
|
|
||||||
|
const Init = () => {
|
||||||
//使用传入值
|
//使用传入值
|
||||||
if(props.userInfo!= undefined)
|
if (props.userInfo != undefined) {
|
||||||
{
|
userInfo.icon = props.userInfo.icon;
|
||||||
userInfo.icon=props.userInfo.icon;
|
userInfo.nick = props.userInfo.nick;
|
||||||
userInfo.name=props.userInfo.name;
|
userInfo.role = props.userInfo.role;
|
||||||
userInfo.role=props.userInfo.role;
|
userInfo.id = props.userInfo.id;
|
||||||
userInfo.id=props.userInfo.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//使用当前登录用户
|
//使用当前登录用户
|
||||||
else
|
else {
|
||||||
{
|
userInfo.icon = userStore.icon;
|
||||||
userInfo.icon=userStore.icon;
|
userInfo.nick = userStore.name;
|
||||||
userInfo.name=userStore.name;
|
userInfo.role = userStore.role;
|
||||||
userInfo.role=userStore.role;
|
userInfo.id = userStore.id;
|
||||||
userInfo.id=userStore.id;
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.mt_1
|
.mt_1 {
|
||||||
{
|
margin-top: 0.5rem;
|
||||||
margin-top: 0.5rem;
|
|
||||||
}
|
}
|
||||||
.nick
|
|
||||||
{
|
.nick {
|
||||||
font-weight:bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.info
|
|
||||||
{
|
.info {
|
||||||
margin-top: 0.6rem;
|
margin-top: 0.6rem;
|
||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
}
|
}
|
||||||
.info .el-tag
|
|
||||||
{
|
.info .el-tag {
|
||||||
margin-right:1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card class="box-card" shadow="never">
|
|
||||||
|
<el-badge :value="props.badge??''" class="box-card" >
|
||||||
|
<el-card shadow="never" :style="{'border-color':props.color}" >
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<AvatarInfo src="asdsadas" :userInfo="{name:'大白子'}" />
|
<AvatarInfo :userInfo="props.user" :time="props.creationTime"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +15,7 @@
|
|||||||
<div class=" item item-bottom">
|
<div class=" item item-bottom">
|
||||||
<el-space :size="10" :spacer="spacer">
|
<el-space :size="10" :spacer="spacer">
|
||||||
<div class="item-description">
|
<div class="item-description">
|
||||||
{{ props.createTime }}
|
{{ props.creationTime }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -21,21 +23,22 @@
|
|||||||
点赞</el-button>
|
点赞</el-button>
|
||||||
<el-button icon="Star" text>
|
<el-button icon="Star" text>
|
||||||
收藏</el-button>
|
收藏</el-button>
|
||||||
|
|
||||||
<el-button icon="ChatDotRound" text>
|
<el-button icon="View" text>
|
||||||
评论</el-button>
|
浏览数:{{ props.seeNum??0 }}</el-button>
|
||||||
|
|
||||||
|
|
||||||
</el-space>
|
</el-space>
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</el-badge>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { h, ref } from 'vue'
|
import { h, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import AvatarInfo from './AvatarInfo.vue';
|
import AvatarInfo from './AvatarInfo.vue';
|
||||||
|
|
||||||
const props = defineProps(['title','introduction','createTime','id'])
|
const props = defineProps(['title','introduction','creationTime','id','user','badge',"color","seeNum"])
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const spacer = h(ElDivider, { direction: 'vertical' })
|
const spacer = h(ElDivider, { direction: 'vertical' })
|
||||||
@@ -44,6 +47,9 @@ const enterDiscuss = (id) => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.el-card{
|
||||||
|
border: 2px solid white
|
||||||
|
}
|
||||||
|
|
||||||
.item-bottom .el-icon {
|
.item-bottom .el-icon {
|
||||||
margin-right: 0.4rem;
|
margin-right: 0.4rem;
|
||||||
@@ -63,6 +69,9 @@ const enterDiscuss = (id) => {
|
|||||||
.box-card {
|
.box-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 15rem;
|
min-height: 15rem;
|
||||||
|
/* right: calc(1px + var(--el-badge-size)/ 2) !important; */
|
||||||
|
/* top: 0 !important; */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
@@ -86,4 +95,5 @@ const enterDiscuss = (id) => {
|
|||||||
font-size: initial;
|
font-size: initial;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<mavon-editor ref='md' v-model="text" :subfield="true" :codeStyle="props.codeStyle" :ishljs="true"
|
<mavon-editor ref='md' v-model="text" :subfield="true" :codeStyle="props.codeStyle" :ishljs="true"
|
||||||
:style="{ minHeight: props.height, maxHeight: '100%' }" class="edit" @imgAdd="imgAdd">
|
:style="{ minHeight: props.height, maxHeight: '100%' }" class="edit" @imgAdd="imgAdd">
|
||||||
|
|
||||||
<!-- 引用视频链接的自定义按钮 -->
|
<!-- 引用视频链接的自定义按钮 -->
|
||||||
<template v-slot:left-toolbar-after>
|
<template v-slot:left-toolbar-after>
|
||||||
<!--点击按钮触发的事件是打开表单对话框-->
|
<!--点击按钮触发的事件是打开表单对话框-->
|
||||||
|
|
||||||
|
|
||||||
|
<el-button @click="fileDialogVisible=true" aria-hidden="true" class="op-icon fa" title="上传文件">
|
||||||
|
<el-icon ><FolderChecked /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
|
||||||
|
|
||||||
<el-dropdown :hide-on-click='false'>
|
<el-dropdown :hide-on-click='false'>
|
||||||
<el-button aria-hidden="true" class="op-icon fa" title="表情包">
|
<el-button aria-hidden="true" class="op-icon fa" title="表情包">
|
||||||
😊
|
😊
|
||||||
@@ -37,9 +44,45 @@
|
|||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
:modal=false
|
||||||
|
:draggable=true
|
||||||
|
|
||||||
|
v-model="fileDialogVisible"
|
||||||
|
title="文件上传"
|
||||||
|
width="30%"
|
||||||
|
:before-close="fileHandleClose"
|
||||||
|
>
|
||||||
|
<span>选择你的文件:</span>
|
||||||
|
|
||||||
|
<el-upload
|
||||||
|
class="upload-demo"
|
||||||
|
drag
|
||||||
|
:action="fileUploadUrl"
|
||||||
|
multiple
|
||||||
|
:on-success="onSuccess"
|
||||||
|
>
|
||||||
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||||
|
<div class="el-upload__text">
|
||||||
|
可将文件拖拽到这里 <em>点击上传</em>
|
||||||
|
</div>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">
|
||||||
|
文件需小于100MB以内
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<p v-for="(item,i) in fileUrlList" :key="i">{{` ${i+1}: ${getUrl(item)}` }} <el-button></el-button></p>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="fileDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="dialogVisible = false">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</mavon-editor>
|
</mavon-editor>
|
||||||
@@ -51,10 +94,16 @@ import { mavonEditor } from 'mavon-editor'
|
|||||||
import 'mavon-editor/dist/css/index.css'
|
import 'mavon-editor/dist/css/index.css'
|
||||||
import { ref, computed, watch, onMounted } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
import { upload } from '@/apis/fileApi'
|
import { upload } from '@/apis/fileApi'
|
||||||
|
|
||||||
const md = ref(null);
|
const md = ref(null);
|
||||||
const props = defineProps(['height', 'modelValue', "codeStyle"])
|
const props = defineProps(['height', 'modelValue', "codeStyle"])
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const fileDialogVisible=ref(false)
|
||||||
|
|
||||||
|
//已经上传好的文件列表url
|
||||||
|
const fileUrlList=ref([])
|
||||||
|
|
||||||
|
const fileUploadUrl=`${import.meta.env.VITE_APP_BASEAPI}/file`
|
||||||
// //v-model传值出去
|
// //v-model传值出去
|
||||||
const text = computed({
|
const text = computed({
|
||||||
get() {
|
get() {
|
||||||
@@ -65,6 +114,18 @@ const text = computed({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getUrl= (str)=>{
|
||||||
|
return `${import.meta.env.VITE_APP_BASEAPI}/file/${str}`
|
||||||
|
}
|
||||||
|
|
||||||
|
//关闭文件上传弹窗
|
||||||
|
const fileHandleClose=()=>{
|
||||||
|
fileDialogVisible=false;
|
||||||
|
}
|
||||||
|
//文件上传成功后
|
||||||
|
const onSuccess=(response)=>{
|
||||||
|
fileUrlList.value.push(response[0].id)
|
||||||
|
}
|
||||||
//图片上传
|
//图片上传
|
||||||
const imgAdd = async (pos, $file) => {
|
const imgAdd = async (pos, $file) => {
|
||||||
// 第一步.将图片上传到服务器.
|
// 第一步.将图片上传到服务器.
|
||||||
@@ -77,9 +138,13 @@ const imgAdd = async (pos, $file) => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
.edit {
|
.edit {
|
||||||
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tree
|
<el-tree
|
||||||
:data="data"
|
:data="props.data==''?[]:props.data"
|
||||||
:props="props.defaultProps"
|
:props="defaultProps"
|
||||||
@node-click="handleNodeClick"
|
@node-click="handleNodeClick"
|
||||||
:expand-on-click-node="false"
|
:expand-on-click-node="false"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
<el-sub-menu index="6">
|
<el-sub-menu index="6">
|
||||||
<template #title>个人中心</template>
|
<template #title>个人中心</template>
|
||||||
<el-menu-item index="6-1">学习 one</el-menu-item>
|
<el-menu-item index="6-1" @click="enterProfile">进入个人中心</el-menu-item>
|
||||||
<el-menu-item index="6-2">学习 two</el-menu-item>
|
<el-menu-item index="6-2" @click="enterProfile">其他</el-menu-item>
|
||||||
<el-menu-item index="6-3" @click="logout">登出</el-menu-item>
|
<el-menu-item index="6-3" @click="logout">登出</el-menu-item>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ const useUserStore = defineStore('user',
|
|||||||
id:'',
|
id:'',
|
||||||
token: getToken(),
|
token: getToken(),
|
||||||
name: '游客',
|
name: '游客',
|
||||||
|
userName:'',
|
||||||
icon: null,
|
icon: null,
|
||||||
roles: [],
|
roles: [],
|
||||||
permissions: []
|
permissions: []
|
||||||
@@ -36,7 +37,7 @@ const useUserStore = defineStore('user',
|
|||||||
getInfo().then(response => {
|
getInfo().then(response => {
|
||||||
const res=response;
|
const res=response;
|
||||||
const user = res.user
|
const user = res.user
|
||||||
const avatar = (user.icon == "" || user.icon == null) ? "" : import.meta.env.VITE_APP_BASE_API + "/file/"+user.icon;
|
const avatar = (user.icon == "" || user.icon == null) ? "/src/assets/logo.ico" : import.meta.env.VITE_APP_BASEAPI + "/file/"+user.icon;
|
||||||
|
|
||||||
if (res.roleCodes && res.roleCodes.length > 0) { // 验证返回的roles是否是一个非空数组
|
if (res.roleCodes && res.roleCodes.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||||
this.roles = res.roleCodes
|
this.roles = res.roleCodes
|
||||||
@@ -50,7 +51,8 @@ const useUserStore = defineStore('user',
|
|||||||
// this.roles = ["admin"];
|
// this.roles = ["admin"];
|
||||||
// this.permissions=["*:*:*"]
|
// this.permissions=["*:*:*"]
|
||||||
this.name = user.nick
|
this.name = user.nick
|
||||||
this.avatar = avatar;
|
this.icon = avatar;
|
||||||
|
this.userName=user.userName
|
||||||
resolve(res)
|
resolve(res)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
reject(error)
|
reject(error)
|
||||||
|
|||||||
@@ -36,8 +36,9 @@
|
|||||||
<el-col :span="14">
|
<el-col :span="14">
|
||||||
<el-row class="left-div">
|
<el-row class="left-div">
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<AvatarInfo :size="50" :showWatching="true" :time="'2023-03-08 21:09:02'"></AvatarInfo>
|
<!-- {{ discuss.user }} -->
|
||||||
|
<AvatarInfo :size="50" :showWatching="true" :time="discuss.creationTime" :userInfo="discuss.user"></AvatarInfo>
|
||||||
|
<!-- :userInfo="{nick:'qwe'} -->
|
||||||
<el-divider />
|
<el-divider />
|
||||||
<h2>{{ discuss.title }}</h2>
|
<h2>{{ discuss.title }}</h2>
|
||||||
<ArticleContentInfo :code="discuss.content??''"></ArticleContentInfo>
|
<ArticleContentInfo :code="discuss.content??''"></ArticleContentInfo>
|
||||||
@@ -137,6 +138,8 @@ const items = [{ user: "用户1" }, { user: "用户2" }, { user: "用户3" }];
|
|||||||
const articleData = ref([]);
|
const articleData = ref([]);
|
||||||
//主题内容
|
//主题内容
|
||||||
const discuss = ref({});
|
const discuss = ref({});
|
||||||
|
|
||||||
|
|
||||||
//当前默认选择的子文章
|
//当前默认选择的子文章
|
||||||
const currentNodeKey=route.params.articleId;
|
const currentNodeKey=route.params.articleId;
|
||||||
//目录数据
|
//目录数据
|
||||||
|
|||||||
@@ -42,13 +42,30 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
<el-tabs v-model="activeName" @tab-change="handleClick">
|
||||||
<el-tab-pane label="推荐" name="first"> </el-tab-pane>
|
<el-tab-pane label="最新" name="new"> </el-tab-pane>
|
||||||
<el-tab-pane label="最新" name="second"> </el-tab-pane>
|
<el-tab-pane label="推荐" name="suggest"> </el-tab-pane>
|
||||||
<el-tab-pane label="最热" name="third"> </el-tab-pane>
|
<el-tab-pane label="最热" name="host"> </el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
||||||
|
<el-collapse >
|
||||||
|
<el-collapse-item >
|
||||||
|
<template #title>
|
||||||
|
<div class="collapse-top">
|
||||||
|
已置顶主题<el-icon class="header-icon">
|
||||||
|
<info-filled />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="div-item" v-for="i in topDiscussList" >
|
||||||
|
<DisscussCard :title="i.title" :introduction="i.introduction" :creationTime="i.creationTime" :id="i.id" :user="i.user" :color="i.color" :seeNum="i.seeNum" badge="置顶"/>
|
||||||
|
</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
<el-divider v-show="topDiscussList.length>0" />
|
||||||
|
|
||||||
<div class="div-item" v-for="i in discussList" >
|
<div class="div-item" v-for="i in discussList" >
|
||||||
<DisscussCard :title="i.title" :introduction="i.introduction" :createTime="i.createTime" :id="i.id"/>
|
<DisscussCard :title="i.title" :introduction="i.introduction" :creationTime="i.creationTime" :id="i.id" :color="i.color" :seeNum="i.seeNum" :user="i.user"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
@@ -70,25 +87,30 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import DisscussCard from '@/components/DisscussCard.vue'
|
import DisscussCard from '@/components/DisscussCard.vue'
|
||||||
import {getList} from '@/apis/discussApi.js'
|
import {getList,getTopList} from '@/apis/discussApi.js'
|
||||||
import { onMounted, ref,reactive } from 'vue'
|
import { onMounted, ref,reactive } from 'vue'
|
||||||
import { useRoute,useRouter } from 'vue-router'
|
import { useRoute,useRouter } from 'vue-router'
|
||||||
|
|
||||||
//数据定义
|
//数据定义
|
||||||
const route=useRoute()
|
const route=useRoute()
|
||||||
const router=useRouter()
|
const router=useRouter()
|
||||||
const activeName = ref('first')
|
const activeName = ref('new')
|
||||||
|
//主题内容
|
||||||
const discussList=ref([]);
|
const discussList=ref([]);
|
||||||
|
//置顶主题内容
|
||||||
|
const topDiscussList = ref([]);
|
||||||
const total=ref(100)
|
const total=ref(100)
|
||||||
const query=reactive({
|
const query=reactive({
|
||||||
pageNum:1,
|
pageNum:1,
|
||||||
pageSize:10,
|
pageSize:10,
|
||||||
title:'',
|
title:'',
|
||||||
plateId:route.params.plateId
|
plateId:route.params.plateId,
|
||||||
|
type:activeName.value
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleClick = (tab, event) => {
|
const handleClick =async (tab, event) => {
|
||||||
console.log(tab, event)
|
query.type=activeName.value ;
|
||||||
|
await loadDiscussList();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async()=>{
|
onMounted(async()=>{
|
||||||
@@ -100,6 +122,10 @@ const loadDiscussList=async()=>{
|
|||||||
const response= await getList(query);
|
const response= await getList(query);
|
||||||
discussList.value=response.items;
|
discussList.value=response.items;
|
||||||
total.value=Number( response.total);
|
total.value=Number( response.total);
|
||||||
|
|
||||||
|
//全查,无需参数
|
||||||
|
const topResponse=await getTopList();
|
||||||
|
topDiscussList.value=topResponse.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
//进入添加主题页面
|
//进入添加主题页面
|
||||||
@@ -130,6 +156,10 @@ background-color: #FFFFFF;
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin: 1rem 0rem ;
|
margin: 1rem 0rem ;
|
||||||
}
|
}
|
||||||
|
.collapse-top
|
||||||
|
{
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
.header .el-input
|
.header .el-input
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="route.query.artType == 'article'"
|
v-if="route.query.artType == 'article'"
|
||||||
label="名称:"
|
label="子文章名称:"
|
||||||
prop="name"
|
prop="name"
|
||||||
>
|
>
|
||||||
<el-input placeholder="请输入" v-model="editForm.name" />
|
<el-input placeholder="请输入" v-model="editForm.name" />
|
||||||
@@ -100,7 +100,10 @@ const ruleFormRef = ref(null);
|
|||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
title: [
|
title: [
|
||||||
{ required: true, message: "请输入标题", trigger: "blur" },
|
{ required: true, message: "请输入标题", trigger: "blur" },
|
||||||
{ min: 3, max: 20, message: "长度 3 到 20", trigger: "blur" },
|
{ min: 3, max: 40, message: "长度 3 到 20", trigger: "blur" },
|
||||||
|
],
|
||||||
|
name: [
|
||||||
|
{ required: true, message: "请输入子文章名称", trigger: "blur" },
|
||||||
],
|
],
|
||||||
content: [
|
content: [
|
||||||
{ required: true, message: "请输入内容", trigger: "blur" },
|
{ required: true, message: "请输入内容", trigger: "blur" },
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="24" v-for="i in discussList">
|
<el-col :span="24" v-for="i in discussList">
|
||||||
<DisscussCard :title="i.title" :introduction="i.introduction" :createTime="i.createTime" :id="i.id"/>
|
<DisscussCard :title="i.title" :introduction="i.introduction" :creationTime="i.creationTime" :id="i.id" :user="i.user" :seeNum="i.seeNum"/>
|
||||||
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<el-input v-model="loginForm.userName" placeholder="用户名" />
|
<el-input v-model="loginForm.userName" placeholder="用户名" />
|
||||||
<el-input v-model="loginForm.password" placeholder="密码" show-password />
|
<el-input v-model="loginForm.password" placeholder="密码" show-password />
|
||||||
<el-button class="login-btn" type="primary" @click="login" >登录</el-button>
|
<el-button class="login-btn" type="primary" @click="login" >登录</el-button>
|
||||||
|
<br>
|
||||||
|
<el-button class="login-btn" type="primary" @click="guestlogin" >游客临时登录</el-button>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive } from 'vue';
|
import { reactive } from 'vue';
|
||||||
@@ -16,7 +18,12 @@ const loginForm=reactive({
|
|||||||
uuid:"",
|
uuid:"",
|
||||||
code:""
|
code:""
|
||||||
})
|
})
|
||||||
|
const guestlogin=async ()=>{
|
||||||
|
loginForm.userName="guest";
|
||||||
|
loginForm.password="123456"
|
||||||
|
await userStore.login(loginForm);
|
||||||
|
router.push("/index")
|
||||||
|
}
|
||||||
const login=async ()=>{
|
const login=async ()=>{
|
||||||
const response= await userStore.login(loginForm);
|
const response= await userStore.login(loginForm);
|
||||||
if( response.code==undefined)
|
if( response.code==undefined)
|
||||||
@@ -38,5 +45,6 @@ margin:0rem 0 0.5rem 0;
|
|||||||
.login-btn
|
.login-btn
|
||||||
{
|
{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,49 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="user-info-head" @click="editCropper()"><img :src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
|
<div class="user-info-head" @click="editCropper()"><img :src="options.img" title="点击上传头像" class="img-circle img-lg" />
|
||||||
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
|
</div>
|
||||||
|
<el-dialog :title="title" v-model="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :xs="24" :md="12" :style="{height: '350px'}">
|
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||||
<vue-cropper
|
<vue-cropper ref="cropper" :img="options.img" :info="true" :autoCrop="options.autoCrop"
|
||||||
ref="cropper"
|
:autoCropWidth="options.autoCropWidth" :autoCropHeight="options.autoCropHeight" :fixedBox="options.fixedBox"
|
||||||
:img="options.img"
|
@realTime="realTime" v-if="visible" />
|
||||||
:info="true"
|
|
||||||
:autoCrop="options.autoCrop"
|
|
||||||
:autoCropWidth="options.autoCropWidth"
|
|
||||||
:autoCropHeight="options.autoCropHeight"
|
|
||||||
:fixedBox="options.fixedBox"
|
|
||||||
@realTime="realTime"
|
|
||||||
v-if="visible"
|
|
||||||
/>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :xs="24" :md="12" :style="{height: '350px'}">
|
<el-col :xs="24" :md="12" :style="{ height: '350px' }">
|
||||||
<div class="avatar-upload-preview">
|
<div class="avatar-upload-preview">
|
||||||
<img :src="options.previews.url" :style="options.previews.img"/>
|
<img :src="options.previews.url" :style="options.previews.img" />
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<br/>
|
<br />
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :lg="2" :md="2">
|
<el-col :lg="2" :md="2">
|
||||||
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
|
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
|
||||||
<el-button>
|
<el-button>
|
||||||
选择
|
选择
|
||||||
<el-icon class="el-icon--right"><Upload /></el-icon>
|
<el-icon class="el-icon--right">
|
||||||
|
<Upload />
|
||||||
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="{span: 1, offset: 2}" :md="2">
|
<el-col :lg="{ span: 1, offset: 2 }" :md="2">
|
||||||
<el-button icon="Plus" @click="changeScale(1)"></el-button>
|
<el-button icon="Plus" @click="changeScale(1)"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="{span: 1, offset: 1}" :md="2">
|
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||||
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
|
<el-button icon="Minus" @click="changeScale(-1)"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="{span: 1, offset: 1}" :md="2">
|
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||||
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
|
<el-button icon="RefreshLeft" @click="rotateLeft()"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="{span: 1, offset: 1}" :md="2">
|
<el-col :lg="{ span: 1, offset: 1 }" :md="2">
|
||||||
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
|
<el-button icon="RefreshRight" @click="rotateRight()"></el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :lg="{span: 2, offset: 6}" :md="2">
|
<el-col :lg="{ span: 2, offset: 6 }" :md="2">
|
||||||
<el-button type="primary" @click="uploadImg()">上传</el-button>
|
<el-button type="primary" @click="uploadImg()">上传</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -56,11 +51,11 @@ import { VueCropper } from "vue-cropper";
|
|||||||
import { upload } from "@/apis/fileApi";
|
import { upload } from "@/apis/fileApi";
|
||||||
import { updateUserIcon } from "@/apis/userApi";
|
import { updateUserIcon } from "@/apis/userApi";
|
||||||
import useUserStore from '@/stores/user'
|
import useUserStore from '@/stores/user'
|
||||||
import { ref ,reactive } from "vue";
|
import { ref, reactive } from "vue";
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const cropper=ref(null);
|
const cropper = ref(null);
|
||||||
|
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
@@ -89,7 +84,7 @@ function requestUpload() {
|
|||||||
};
|
};
|
||||||
/** 向左旋转 */
|
/** 向左旋转 */
|
||||||
function rotateLeft() {
|
function rotateLeft() {
|
||||||
cropper.value.rotateLeft();
|
cropper.value.rotateLeft();
|
||||||
};
|
};
|
||||||
/** 向右旋转 */
|
/** 向右旋转 */
|
||||||
function rotateRight() {
|
function rotateRight() {
|
||||||
@@ -110,30 +105,20 @@ function beforeUpload(file) {
|
|||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
options.img = reader.result;
|
options.img = reader.result;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/** 上传图片 */
|
/** 上传图片 */
|
||||||
function uploadImg() {
|
async function uploadImg() {
|
||||||
cropper.value.getCropBlob(data => {
|
await cropper.value.getCropBlob(async data => {
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("file", data);
|
formData.append("file", data);
|
||||||
upload(formData).then(response => {
|
const response = await upload(formData)
|
||||||
open.value = false;
|
open.value = false;
|
||||||
options.img = import.meta.env.VITE_APP_BASE_API +"/file/"+response[0].id;
|
options.img = import.meta.env.VITE_APP_BASEAPI + "/file/" + response[0].id;
|
||||||
userStore.icon = options.img;
|
userStore.icon = options.img;
|
||||||
updateUserIcon(response[0].id).then(response2=>{
|
await updateUserIcon(response[0].id);
|
||||||
alert("修改成功");
|
alert("上传成功")
|
||||||
visible.value = false;
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 实时预览 */
|
/** 实时预览 */
|
||||||
@@ -142,11 +127,12 @@ function realTime(data) {
|
|||||||
};
|
};
|
||||||
/** 关闭窗口 */
|
/** 关闭窗口 */
|
||||||
function closeDialog() {
|
function closeDialog() {
|
||||||
options.img = userStore.iocn;
|
options.img = userStore.icon;
|
||||||
options.visible = false;
|
options.visible = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
.user-info-head {
|
.user-info-head {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -171,4 +157,24 @@ function closeDialog() {
|
|||||||
line-height: 110px;
|
line-height: 110px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.img-circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-lg {
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-upload-preview {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(50%, -50%);
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 0 4px #ccc;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="userRef" :model="user" :rules="rules" label-width="80px">
|
<el-form ref="userRef" :model="user" :rules="rules" label-width="80px">
|
||||||
<el-form-item label="用户昵称" prop="nickName">
|
<el-form-item label="账号" prop="userName">
|
||||||
|
<el-input v-model="user.userName" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="用户昵称" prop="nick">
|
||||||
<el-input v-model="user.nick" maxlength="30" />
|
<el-input v-model="user.nick" maxlength="30" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="手机号码" prop="phone">
|
<el-form-item label="手机号码" prop="phone">
|
||||||
@@ -24,8 +27,9 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { updateUserProfile } from "@/apis/userApi";
|
import { updateUserProfile } from "@/apis/userApi";
|
||||||
|
import useUserStore from "@/stores/user"
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
|
const userStore=useUserStore();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
user: {
|
user: {
|
||||||
type: Object
|
type: Object
|
||||||
@@ -45,6 +49,10 @@ function submit() {
|
|||||||
userRef.value.validate(valid => {
|
userRef.value.validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
updateUserProfile(props.user).then(response => {
|
updateUserProfile(props.user).then(response => {
|
||||||
|
console.log(props.user.nick,"props.user.nick")
|
||||||
|
console.log(userStore,"userStore.nick")
|
||||||
|
userStore.name=props.user.nick
|
||||||
|
console.log(userStore.name,"userStore.name");
|
||||||
alert("修改成功");
|
alert("修改成功");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<Compile Include="..\GlobalUsings.cs" Link="Properties\GlobalUsings.cs" />
|
<Compile Include="..\GlobalUsings.cs" Link="Properties\GlobalUsings.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\rbac\Yi.RBAC.Application.Contracts\Yi.RBAC.Application.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj" />
|
<ProjectReference Include="..\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,13 @@
|
|||||||
Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息
|
Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetAsync(System.Int64)">
|
||||||
|
<summary>
|
||||||
|
单查
|
||||||
|
</summary>
|
||||||
|
<param name="id"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetListAsync(Yi.BBS.Application.Contracts.Forum.Dtos.Discuss.DiscussGetListInputVo)">
|
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetListAsync(Yi.BBS.Application.Contracts.Forum.Dtos.Discuss.DiscussGetListInputVo)">
|
||||||
<summary>
|
<summary>
|
||||||
查询
|
查询
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.BBS.Domain.Shared.Forum.EnumClasses
|
||||||
|
{
|
||||||
|
public enum QueryDiscussTypeEnum
|
||||||
|
{
|
||||||
|
New,
|
||||||
|
Suggest,
|
||||||
|
Host
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Yi.BBS.Domain.Shared.Forum.Etos
|
||||||
|
{
|
||||||
|
public class SeeDiscussEventArgs
|
||||||
|
{
|
||||||
|
public long DiscussId { get; set; }
|
||||||
|
public int OldSeeNum { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Cike.EventBus.EventHandlerAbstracts;
|
||||||
|
using Yi.BBS.Domain.Forum.Entities;
|
||||||
|
using Yi.BBS.Domain.Shared.Forum.Etos;
|
||||||
|
using Yi.Framework.Ddd.Repositories;
|
||||||
|
using Yi.RBAC.Domain.Shared.Identity.Etos;
|
||||||
|
|
||||||
|
namespace Yi.BBS.Domain.Forum.Event
|
||||||
|
{
|
||||||
|
public class SeeDiscussEventHandler : IDistributedEventHandler<SeeDiscussEventArgs>
|
||||||
|
{
|
||||||
|
private IRepository<DiscussEntity> _repository;
|
||||||
|
public SeeDiscussEventHandler(IRepository<DiscussEntity> repository)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
}
|
||||||
|
public async Task HandlerAsync(SeeDiscussEventArgs eventData)
|
||||||
|
{
|
||||||
|
var entity= await _repository.GetByIdAsync(eventData.DiscussId);
|
||||||
|
if (entity is not null) {
|
||||||
|
entity.SeeNum += 1;
|
||||||
|
await _repository.UpdateAsync(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 616 KiB |
|
After Width: | Height: | Size: 616 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
@@ -3,6 +3,8 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Yi.BBS.Domain.Shared.Forum.ConstClasses;
|
||||||
|
using Yi.BBS.Domain.Shared.Forum.EnumClasses;
|
||||||
using Yi.Framework.Ddd.Dtos;
|
using Yi.Framework.Ddd.Dtos;
|
||||||
|
|
||||||
namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
||||||
@@ -12,5 +14,11 @@ namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
|||||||
public string? Title { get; set; }
|
public string? Title { get; set; }
|
||||||
|
|
||||||
public long? PlateId { get; set; }
|
public long? PlateId { get; set; }
|
||||||
|
|
||||||
|
//Ĭ<>ϲ<EFBFBD>ѯ<EFBFBD><D1AF><EFBFBD>ö<EFBFBD>
|
||||||
|
public bool IsTop { get; set; } = false;
|
||||||
|
|
||||||
|
//<2F><>ѯ<EFBFBD><D1AF>ʽ
|
||||||
|
public QueryDiscussTypeEnum Type { get; set; } = QueryDiscussTypeEnum.New;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Yi.Framework.Ddd.Dtos;
|
using Yi.Framework.Ddd.Dtos;
|
||||||
|
using Yi.RBAC.Application.Contracts.Identity.Dtos;
|
||||||
|
|
||||||
namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
||||||
{
|
{
|
||||||
@@ -15,12 +16,24 @@ namespace Yi.BBS.Application.Contracts.Forum.Dtos.Discuss
|
|||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Types { get; set; }
|
public string Types { get; set; }
|
||||||
public string? Introduction { get; set; }
|
public string? Introduction { get; set; }
|
||||||
public DateTime? CreateTime { get; set; }
|
|
||||||
public int AgreeNum { get; set; }
|
public int AgreeNum { get; set; }
|
||||||
public int SeeNum { get; set; }
|
public int SeeNum { get; set; }
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
|
|
||||||
public long PlateId { get; set; }
|
public long PlateId { get; set; }
|
||||||
|
|
||||||
|
//<2F>Ƿ<EFBFBD><C7B7>ö<EFBFBD><C3B6><EFBFBD>Ĭ<EFBFBD><C4AC>false
|
||||||
|
public bool IsTop { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
//<2F>Ƿ<EFBFBD>˽<EFBFBD>У<EFBFBD>Ĭ<EFBFBD><C4AC>false
|
||||||
|
public bool IsPrivate { get; set; }
|
||||||
|
|
||||||
|
//˽<><CBBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ж<EFBFBD>codeȨ<65><C8A8>
|
||||||
|
public string? PrivateCode { get; set; }
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
public UserGetListOutputDto User { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Yi.Framework.Ddd.Dtos;
|
using Yi.Framework.Ddd.Dtos;
|
||||||
|
using Yi.RBAC.Application.Contracts.Identity.Dtos;
|
||||||
|
|
||||||
namespace Yi.BBS.Application.Contracts.Forum.Dtos
|
namespace Yi.BBS.Application.Contracts.Forum.Dtos
|
||||||
{
|
{
|
||||||
@@ -15,12 +16,23 @@ namespace Yi.BBS.Application.Contracts.Forum.Dtos
|
|||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Types { get; set; }
|
public string Types { get; set; }
|
||||||
public string? Introduction { get; set; }
|
public string? Introduction { get; set; }
|
||||||
public DateTime? CreateTime { get; set; }
|
|
||||||
public int AgreeNum { get; set; }
|
public int AgreeNum { get; set; }
|
||||||
public int SeeNum { get; set; }
|
public int SeeNum { get; set; }
|
||||||
public string Content { get; set; }
|
public string Content { get; set; }
|
||||||
public string? Color { get; set; }
|
public string? Color { get; set; }
|
||||||
|
|
||||||
public long PlateId { get; set; }
|
public long PlateId { get; set; }
|
||||||
|
//<2F>Ƿ<EFBFBD><C7B7>ö<EFBFBD><C3B6><EFBFBD>Ĭ<EFBFBD><C4AC>false
|
||||||
|
public bool IsTop { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
//<2F>Ƿ<EFBFBD>˽<EFBFBD>У<EFBFBD>Ĭ<EFBFBD><C4AC>false
|
||||||
|
public bool IsPrivate { get; set; }
|
||||||
|
|
||||||
|
//˽<><CBBD><EFBFBD><EFBFBD>Ҫ<EFBFBD>ж<EFBFBD>codeȨ<65><C8A8>
|
||||||
|
public string? PrivateCode { get; set; }
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
|
||||||
|
public UserGetListOutputDto User { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<Compile Include="..\GlobalUsings.cs" Link="Properties\GlobalUsings.cs" />
|
<Compile Include="..\GlobalUsings.cs" Link="Properties\GlobalUsings.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\rbac\Yi.RBAC.Application.Contracts\Yi.RBAC.Application.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj" />
|
<ProjectReference Include="..\Yi.BBS.Domain.Shared\Yi.BBS.Domain.Shared.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,13 @@
|
|||||||
Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息
|
Discuss应用服务实现,用于参数效验、领域服务业务组合、日志记录、事务处理、账户信息
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetAsync(System.Int64)">
|
||||||
|
<summary>
|
||||||
|
单查
|
||||||
|
</summary>
|
||||||
|
<param name="id"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetListAsync(Yi.BBS.Application.Contracts.Forum.Dtos.Discuss.DiscussGetListInputVo)">
|
<member name="M:Yi.BBS.Application.Forum.DiscussService.GetListAsync(Yi.BBS.Application.Contracts.Forum.Dtos.Discuss.DiscussGetListInputVo)">
|
||||||
<summary>
|
<summary>
|
||||||
查询
|
查询
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ using SqlSugar;
|
|||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Yi.BBS.Domain.Shared.Forum.ConstClasses;
|
using Yi.BBS.Domain.Shared.Forum.ConstClasses;
|
||||||
using Yi.Framework.Ddd.Repositories;
|
using Yi.Framework.Ddd.Repositories;
|
||||||
|
using Yi.RBAC.Domain.Identity.Entities;
|
||||||
|
using Yi.RBAC.Application.Contracts.Identity.Dtos;
|
||||||
|
using Cike.EventBus.DistributedEvent;
|
||||||
|
using Yi.BBS.Domain.Shared.Forum.Etos;
|
||||||
|
using Yi.BBS.Domain.Shared.Forum.EnumClasses;
|
||||||
|
|
||||||
namespace Yi.BBS.Application.Forum
|
namespace Yi.BBS.Application.Forum
|
||||||
{
|
{
|
||||||
@@ -28,6 +33,28 @@ namespace Yi.BBS.Application.Forum
|
|||||||
[Autowired]
|
[Autowired]
|
||||||
private IRepository<PlateEntity> _plateEntityRepository { get; set; }
|
private IRepository<PlateEntity> _plateEntityRepository { get; set; }
|
||||||
|
|
||||||
|
[Autowired]
|
||||||
|
private IDistributedEventBus _distributedEventBus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单查
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async override Task<DiscussGetOutputDto> GetAsync(long id)
|
||||||
|
{
|
||||||
|
//查询主题发布 浏览主题 事件,浏览数+1
|
||||||
|
var item = await _DbQueryable.LeftJoin<UserEntity>((discuss, user) => discuss.CreatorId == user.Id)
|
||||||
|
.Select((discuss, user) => new DiscussGetOutputDto
|
||||||
|
{
|
||||||
|
User = new UserGetListOutputDto() { UserName = user.UserName, Nick = user.Nick,Icon=user.Icon }
|
||||||
|
}, true).SingleAsync(discuss => discuss.Id==id);
|
||||||
|
|
||||||
|
_distributedEventBus.PublishAsync(new SeeDiscussEventArgs { DiscussId= item.Id, OldSeeNum= item .SeeNum});
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询
|
/// 查询
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -36,13 +63,19 @@ namespace Yi.BBS.Application.Forum
|
|||||||
|
|
||||||
public override async Task<PagedResultDto<DiscussGetListOutputDto>> GetListAsync( [FromQuery] DiscussGetListInputVo input)
|
public override async Task<PagedResultDto<DiscussGetListOutputDto>> GetListAsync( [FromQuery] DiscussGetListInputVo input)
|
||||||
{
|
{
|
||||||
|
//需要关联创建者用户
|
||||||
RefAsync<int> total = 0;
|
RefAsync<int> total = 0;
|
||||||
var entities = await _DbQueryable
|
var items = await _DbQueryable
|
||||||
.WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title.Contains(input.Title))
|
.WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title.Contains(input.Title))
|
||||||
.WhereIF(input.PlateId is not null, x => x.PlateId == input.PlateId)
|
.WhereIF(input.PlateId is not null, x => x.PlateId == input.PlateId)
|
||||||
.OrderByDescending(x => x.CreateTime)
|
.Where(x=>x.IsTop==input.IsTop)
|
||||||
|
.OrderByIF(input.Type==QueryDiscussTypeEnum.New, x =>x.CreationTime,OrderByType.Desc )
|
||||||
|
.OrderByIF(input.Type == QueryDiscussTypeEnum.Host, x => x.SeeNum, OrderByType.Desc)
|
||||||
|
.LeftJoin<UserEntity>((discuss, user) => discuss.CreatorId==user.Id)
|
||||||
|
.Select((discuss,user) =>new DiscussGetListOutputDto {
|
||||||
|
User=new UserGetListOutputDto() { UserName=user.UserName,Nick=user.Nick, Icon = user.Icon }
|
||||||
|
},true)
|
||||||
.ToPageListAsync(input.PageNum, input.PageSize, total);
|
.ToPageListAsync(input.PageNum, input.PageSize, total);
|
||||||
var items = await MapToGetListOutputDtosAsync(entities);
|
|
||||||
return new PagedResultDto<DiscussGetListOutputDto>(total, items);
|
return new PagedResultDto<DiscussGetListOutputDto>(total, items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Yi.Framework.Data.Auditing;
|
||||||
using Yi.Framework.Data.Entities;
|
using Yi.Framework.Data.Entities;
|
||||||
using Yi.Framework.Ddd.Entities;
|
using Yi.Framework.Ddd.Entities;
|
||||||
|
|
||||||
namespace Yi.BBS.Domain.Forum.Entities
|
namespace Yi.BBS.Domain.Forum.Entities
|
||||||
{
|
{
|
||||||
[SugarTable("Discuss")]
|
[SugarTable("Discuss")]
|
||||||
public class DiscussEntity : IEntity<long>, ISoftDelete
|
public class DiscussEntity : IEntity<long>, ISoftDelete,IAuditedObject
|
||||||
{
|
{
|
||||||
public DiscussEntity()
|
public DiscussEntity()
|
||||||
{
|
{
|
||||||
@@ -26,7 +27,6 @@ namespace Yi.BBS.Domain.Forum.Entities
|
|||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Types { get; set; }
|
public string Types { get; set; }
|
||||||
public string? Introduction { get; set; }
|
public string? Introduction { get; set; }
|
||||||
public DateTime? CreateTime { get; set; }
|
|
||||||
public int AgreeNum { get; set; }
|
public int AgreeNum { get; set; }
|
||||||
public int SeeNum { get; set; }
|
public int SeeNum { get; set; }
|
||||||
|
|
||||||
@@ -36,7 +36,23 @@ namespace Yi.BBS.Domain.Forum.Entities
|
|||||||
|
|
||||||
public bool IsDeleted { get; set; }
|
public bool IsDeleted { get; set; }
|
||||||
|
|
||||||
|
//是否置顶,默认false
|
||||||
|
public bool IsTop { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
//是否私有,默认false
|
||||||
|
public bool IsPrivate { get; set; }
|
||||||
|
|
||||||
|
//私有需要判断code权限
|
||||||
|
public string? PrivateCode { get; set; }
|
||||||
|
|
||||||
public long PlateId { get; set; }
|
public long PlateId { get; set; }
|
||||||
|
public DateTime CreationTime { get; set; }
|
||||||
|
|
||||||
|
public long? CreatorId { get; set; }
|
||||||
|
|
||||||
|
public long? LastModifierId { get; set; }
|
||||||
|
|
||||||
|
public DateTime? LastModificationTime { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Yi.BBS.Domain.Forum
|
|||||||
entity.Types = types;
|
entity.Types = types;
|
||||||
entity.Introduction = introduction;
|
entity.Introduction = introduction;
|
||||||
entity.Content = content;
|
entity.Content = content;
|
||||||
entity.CreateTime = DateTime.Now;
|
entity.CreationTime = DateTime.Now;
|
||||||
entity.AgreeNum = 0;
|
entity.AgreeNum = 0;
|
||||||
entity.SeeNum = 0;
|
entity.SeeNum = 0;
|
||||||
return await _discussRepository.InsertReturnEntityAsync(entity);
|
return await _discussRepository.InsertReturnEntityAsync(entity);
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ namespace Yi.RBAC.Domain.Identity
|
|||||||
|
|
||||||
if (!user.JudgePassword(oldPassword))
|
if (!user.JudgePassword(oldPassword))
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("无效更新!新密码不能与老密码相同");
|
throw new UserFriendlyException("无效更新!原密码错误!");
|
||||||
}
|
}
|
||||||
user.Password = newPassword;
|
user.Password = newPassword;
|
||||||
user.BuildPassword();
|
user.BuildPassword();
|
||||||
|
|||||||