parent
0cf6e42287
commit
2caf79f6e4
15 changed files with 6353 additions and 12351 deletions
@ -1,5 +1,5 @@ |
||||
# 变量必须以 VITE_ 为前缀才能暴露给外部读取 |
||||
NODE_ENV = 'development' |
||||
VITE_APP_TITLE = '无糖运营平台' |
||||
VITE_APP_BASE_API = 'http://127.0.0.1:8080' |
||||
# VITE_APP_BASE_API = 'http://39.106.16.162:8080' |
||||
# VITE_APP_BASE_API = 'http://127.0.0.1:8080' |
||||
VITE_APP_BASE_API = 'http://39.106.16.162:8080' |
||||
|
@ -1,15 +1,18 @@ |
||||
<!doctype html> |
||||
<html lang="en"> |
||||
<head> |
||||
|
||||
<head> |
||||
<meta charset="UTF-8" /> |
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
<title>教学一体化后师生后台</title> |
||||
</head> |
||||
<body> |
||||
</head> |
||||
|
||||
<body> |
||||
<div id="app"></div> |
||||
<script type="module" src="/src/main.ts"></script> |
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script> |
||||
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> |
||||
</body> |
||||
</body> |
||||
|
||||
</html> |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,19 @@ |
||||
import request from '@/utils/request' |
||||
// 获取发件箱信息列表
|
||||
export const getSendMessagesListApi = (params) => { |
||||
return request.get('/user-inbox/page/sendmessages', { |
||||
params, |
||||
}) |
||||
} |
||||
// 获取收件箱信息列表
|
||||
export const getMessagesListApi = (params) => { |
||||
return request.get('/user-inbox/page/receivemessages', { |
||||
params, |
||||
}) |
||||
} |
||||
//删除收件箱
|
||||
export const deleteSendMessageApi = (params) => { |
||||
return request.delete('/user-inbox/deletereceivemessage', { |
||||
params, |
||||
}) |
||||
} |
@ -0,0 +1,7 @@ |
||||
import request from '@/utils/request' |
||||
//发送消息
|
||||
export const sendMessagesApi = (params) => { |
||||
return request.post('/messages/addmessage', { |
||||
params, |
||||
}) |
||||
} |
@ -0,0 +1,80 @@ |
||||
<template> |
||||
<div class="common-layout"> |
||||
<el-container> |
||||
<el-header class="header"> |
||||
<p>收到信息详情</p> |
||||
</el-header> |
||||
<el-main > |
||||
<el-card> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<el-button type="primary" style="width: 80px" @click="back" round plain>返回</el-button> |
||||
</div> |
||||
</template> |
||||
<div class="container"> |
||||
<div class="header_content"> |
||||
<span class="sender">发送人:{{ Message.senderName }}</span> |
||||
<span class="time">发送时间:{{ Message.sendTime }}</span> |
||||
<span class="read-status">是否阅读:{{Message.isRead}}</span> |
||||
</div> |
||||
<div class="recipient">标题:{{ Message.title }}</div> |
||||
<div class="content"> |
||||
内容:{{ Message.content }} |
||||
</div> |
||||
</div> |
||||
<!-- <template #footer>Footer content</template>--> |
||||
</el-card> |
||||
</el-main> |
||||
</el-container> |
||||
</div> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import {useRouter,useRoute} from "vue-router"; |
||||
const router = useRouter() |
||||
const route = useRoute() |
||||
//获取数据,如果失败返回上一级 |
||||
if(!Object.keys(route.query).length){ |
||||
router.go(-1) |
||||
} |
||||
//返回按钮 |
||||
const back = ()=>{ |
||||
router.push('/messageManagement/message') |
||||
} |
||||
import {ref} from "vue"; |
||||
//获取参数 |
||||
const Message = ref(route.query) |
||||
|
||||
</script> |
||||
|
||||
<style scoped> |
||||
.header{ |
||||
background: #7f98cb; |
||||
height: 50px; |
||||
font-size: 20px; |
||||
text-align: center; |
||||
padding: 15px; |
||||
} |
||||
.container { |
||||
padding: 10px; /* 容器内边距 */ |
||||
margin-top: 10px; /* 容器上边距 */ |
||||
height: 65vh; |
||||
} |
||||
.header_content { |
||||
margin-bottom: 10px; /* 与下面的收件人信息保持一定间距 */ |
||||
} |
||||
|
||||
.header_content span { |
||||
margin-right: 50px; /* 发件人和时间之间的间距 */ |
||||
} |
||||
|
||||
.header_content .read-status { |
||||
margin-right: 0; /* 已读状态右侧不需要间距 */ |
||||
} |
||||
|
||||
.recipient, .content { |
||||
font-size: 20px; |
||||
color: #333; |
||||
margin-top: 10px; |
||||
margin-bottom: 20px; |
||||
} |
||||
</style> |
@ -0,0 +1,204 @@ |
||||
<template> |
||||
<div class="common-layout"> |
||||
<el-container> |
||||
<el-header class="header"> |
||||
<p>写栈内信函</p> |
||||
</el-header> |
||||
<el-main class="mainContainer"> |
||||
<el-card> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<span>写栈内信函</span> |
||||
<div> |
||||
<el-button style="width: 100px;text-align: center" type="primary" round @click="back" plain>返回</el-button> |
||||
<el-button style="width: 100px;text-align: center" type="primary" round>发送</el-button> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
<!-- 输入框内容--> |
||||
<el-input |
||||
v-model="inputPerson" |
||||
size="large" |
||||
placeholder="收件人:" |
||||
> |
||||
<template #append> |
||||
<el-button @click="addPerson = true"> |
||||
<el-icon><CirclePlus /></el-icon> |
||||
</el-button> |
||||
</template> |
||||
</el-input> |
||||
<el-input |
||||
v-model="inputText" |
||||
size="large" |
||||
placeholder="标题:" |
||||
> |
||||
</el-input> |
||||
<el-input |
||||
v-model="textarea" |
||||
:rows="15" |
||||
type="textarea" |
||||
placeholder="内容:" |
||||
/> |
||||
<!--添加收件人信息--> |
||||
<el-dialog class="dialogType" v-model="addPerson" title="选择收件人"> |
||||
<el-divider/> |
||||
<div class="content-container"> |
||||
<div class="left-panel" style="flex: 1; display: flex; align-items: center; justify-content: center;"> |
||||
<!-- <el-input--> |
||||
<!-- v-model="inputSearch"--> |
||||
<!-- style="max-width: 300px;--> |
||||
<!-- margin-bottom: 20px"--> |
||||
<!-- placeholder="搜索"--> |
||||
<!-- >--> |
||||
<!-- <template #append>--> |
||||
<!-- <el-button :icon="Search" @click="editSearch"/>--> |
||||
<!-- </template>--> |
||||
<!-- </el-input>--> |
||||
<!-- 组织架构--> |
||||
<div> |
||||
组织框架: |
||||
<el-tree-select |
||||
v-model="inputPerson" |
||||
:data="data" |
||||
multiple |
||||
:render-after-expand="false" |
||||
show-checkbox |
||||
style="width: 240px" |
||||
/> |
||||
</div> |
||||
</div> |
||||
<div class="right-panel" style="flex: 1;"> |
||||
<p>已选人:</p> |
||||
<el-divider/> |
||||
<li v-for="item in inputPerson" :key="item.lable"> |
||||
<p>{{item}}</p> |
||||
</li> |
||||
</div> |
||||
</div> |
||||
<el-divider/> |
||||
<div style="text-align: right"> |
||||
<el-button type="primary" plain round>取消</el-button> |
||||
<el-button type="primary" @click="confirm" round>确定</el-button> |
||||
</div> |
||||
</el-dialog> |
||||
<template #footer> |
||||
<p>发送此站内信函即表示您已阅读并接受<el-link href="https://element-plus.org/zh-CN/component/overview.html" type="primary">《用户协议》</el-link>,请遵守该协议</p> |
||||
</template> |
||||
</el-card> |
||||
</el-main> |
||||
</el-container> |
||||
</div> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import { ref,onMounted} from 'vue' |
||||
import { Search } from '@element-plus/icons-vue' |
||||
import { useRouter } from 'vue-router'; |
||||
|
||||
const inputPerson = ref([]) |
||||
const inputText = ref('') |
||||
const textarea = ref('') |
||||
const inputSearch = ref('') |
||||
const addPerson = ref(false) |
||||
const router = useRouter() |
||||
|
||||
//返回 |
||||
const back= ()=>{ |
||||
router.push('/messageManagement/message') |
||||
} |
||||
//选择收件人 |
||||
const confirm = ()=>{ |
||||
addPerson.value = false |
||||
} |
||||
//收件人姓名搜索 |
||||
const editSearch=()=>{ |
||||
|
||||
} |
||||
//虚拟数据 |
||||
const data = ref([ |
||||
{ |
||||
value: '计算机学院', |
||||
label: '计算机学院', |
||||
children: [ |
||||
{ |
||||
value: '软件技术专业', |
||||
label: '软件技术专业', |
||||
children: [ |
||||
{ |
||||
value: '彭于晏', |
||||
label: '彭于晏', |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
value: '艺术学院', |
||||
label: '艺术学院', |
||||
children: [ |
||||
{ |
||||
value: '编导专业', |
||||
label: '编导专业', |
||||
children: [ |
||||
{ |
||||
value: '刘亦菲', |
||||
label: '刘亦菲', |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
value: '动画专业', |
||||
label: '动画专业', |
||||
children: [ |
||||
{ |
||||
value: '辛芷蕾', |
||||
label: '辛芷蕾', |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
]) |
||||
|
||||
</script> |
||||
<style scoped> |
||||
|
||||
.header{ |
||||
background: steelblue; |
||||
text-align: center; |
||||
font-size: 18px; |
||||
line-height: 45px; |
||||
height: 45px; |
||||
width: 100%; |
||||
margin-bottom: 30px; |
||||
} |
||||
.header p{ |
||||
color: gainsboro; |
||||
} |
||||
li{ |
||||
list-style: none; |
||||
} |
||||
.mainContainer{ |
||||
width: 80%; |
||||
margin: auto; |
||||
} |
||||
.card-header{ |
||||
display: flex; /* 启用Flexbox布局 */ |
||||
justify-content: space-between; /* 在主轴上分布项目,这里让h2和button分布在两端 */ |
||||
align-items: center; /* 在交叉轴上居中项目,这里是垂直居中 */ |
||||
height: 30px; /* 示例高度,根据实际需求调整 */ |
||||
padding: 0 20px; /* 添加一些内边距以避免内容紧贴边缘 */ |
||||
} |
||||
.el-input{ |
||||
margin-bottom: 30px; |
||||
} |
||||
.content-container { |
||||
display: flex; |
||||
height: 100%; /* 根据需要调整高度 */ |
||||
} |
||||
.left-panel, .right-panel { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; /* 垂直居中内容 */ |
||||
align-items: center; /* 水平居中内容 */ |
||||
} |
||||
</style> |
@ -0,0 +1,267 @@ |
||||
<template> |
||||
<el-card> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<el-button type="primary" @click="back" round plain>返回</el-button> |
||||
<el-button type="primary" @click="sendContent" round>写栈内信函</el-button> |
||||
</div> |
||||
</template> |
||||
<div class="container"> |
||||
<div class="checkboxHeader"> |
||||
<input type="checkbox" class="custom-checkbox" @change="toggleAll" :checked="allSelected" /> |
||||
<p class="selected-count">已选 {{ selectedCount }} 条记录</p> |
||||
</div> |
||||
<li v-for="item in sendMessage" |
||||
:key="item.title" |
||||
class="message-list-item" |
||||
> |
||||
<!--添加悬浮删除按钮--> |
||||
<!-- <div class="message-list" @mouseover="hoveringOver = item.id" @mouseleave="hoveringOver = null">--> |
||||
<div class="message-list"> |
||||
<!-- 添加勾选框 --> |
||||
<div class="message-check"> |
||||
<input type="checkbox" class="custom-checkbox" :value="item.id" @change="toggleSelection(item.id)" :checked="isSelected(item.id)"/> |
||||
</div> |
||||
<div class="message-icon"> |
||||
<el-icon><Comment /></el-icon> |
||||
</div> |
||||
<div class="message-content" @click="handleClick(item)"> |
||||
<h2 class="message-title">{{item.title}}</h2> |
||||
<div class="message-details"> |
||||
<span class="sender">发送人:{{item.senderName}}</span> |
||||
<span class="read-status">阅读人数:{{item.readUserNum}}</span> |
||||
</div> |
||||
<div class="message-time">{{item.sendTime}}</div> |
||||
</div> |
||||
<!-- 删除按钮,默认不显示,hover时显示 --> |
||||
<!-- <el-button v-if="hoveringOver === item.id" class="delete-btn" @click="deleteSendMessage(item.id)" type="danger" round >删除</el-button>--> |
||||
</div> |
||||
<el-divider/> |
||||
</li> |
||||
</div> |
||||
<template #footer> |
||||
<!-- 分页--> |
||||
<el-pagination |
||||
v-model:current-page="params.pageNo" |
||||
v-model:page-size="params.pageSize" |
||||
:page-sizes="[2,3, 5, 7, 10]" |
||||
:background="true" |
||||
layout="jumper,total, sizes, prev, pager, next " |
||||
:total="total" |
||||
@size-change="handleSizeChange" |
||||
@current-change="handleCurrentChange" |
||||
style="margin-top: 10px; justify-content: center" |
||||
/> |
||||
</template> |
||||
</el-card> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import { ref,computed,onMounted} from 'vue'; |
||||
import { useRouter } from 'vue-router'; |
||||
import useUserStore from "@/store/modules/user"; |
||||
import {getSendMessagesListApi,deleteSendMessageApi} from "@/api/user/messag"; |
||||
import { ElMessageBox, ElMessage } from 'element-plus' |
||||
const userStore = useUserStore() |
||||
//传参 |
||||
const params = ref({ |
||||
userId: userStore.userInfo.id, |
||||
// userId: 4, |
||||
isAsc:true, |
||||
isDelete:0, |
||||
isRead:'', |
||||
isSend:1, |
||||
// messageId:false, |
||||
pageNo:1, |
||||
pageSize:3, |
||||
sortBy:false,//排序字段 |
||||
}) |
||||
const total = ref(0) |
||||
const sendMessage = ref([]) |
||||
const loading = ref(false) |
||||
// const hoveringOver = ref(null) |
||||
//复选框 |
||||
const selectedIds = ref([]); // 存储已选中的消息ID |
||||
const allSelected = computed(() => { |
||||
// 如果所有消息都被选中,则返回true |
||||
return sendMessage.value.length > 0 && sendMessage.value.every(item => selectedIds.value.includes(item.id)); |
||||
}); |
||||
|
||||
const selectedCount = computed(() => { |
||||
// 返回已选中的消息数量 |
||||
return selectedIds.value.length; |
||||
}); |
||||
|
||||
function toggleAll(event) { |
||||
// 切换所有消息的选中状态 |
||||
const target = event.target; |
||||
if (target.checked) { |
||||
// 如果全选框被选中,则将所有消息的ID添加到selectedIds中 |
||||
selectedIds.value = sendMessage.value.map(item => item.id); |
||||
} else { |
||||
// 如果全选框未被选中,则清空selectedIds |
||||
selectedIds.value = []; |
||||
} |
||||
} |
||||
|
||||
function toggleSelection(id: number) { |
||||
// 切换单个消息的选中状态 |
||||
const index = selectedIds.value.indexOf(id); |
||||
if (index > -1) { |
||||
selectedIds.value.splice(index, 1); |
||||
} else { |
||||
selectedIds.value.push(id); |
||||
} |
||||
} |
||||
function isSelected(id) { |
||||
return selectedIds.value.includes(id); |
||||
} |
||||
// 获取课程列表 |
||||
const getSendMessageList = async () => { |
||||
loading.value = true |
||||
const res = await getSendMessagesListApi(params.value) |
||||
sendMessage.value = res.data.list |
||||
total.value = res.data.total |
||||
loading.value = false |
||||
} |
||||
// 渲染 |
||||
onMounted(() => { |
||||
getSendMessageList() |
||||
}) |
||||
//删除当前记录 |
||||
// const deleteSendMessage = async (id: any) => { |
||||
// await ElMessageBox.confirm('您确定删除这条课程信息吗', '温馨提示', { |
||||
// confirmButtonText: '确认', |
||||
// cancelButtonText: '取消', |
||||
// type: 'warning', |
||||
// }) |
||||
// await deleteSendMessageApi({ |
||||
// messageIds:id, |
||||
// userId:userStore.userInfo.id |
||||
// }) |
||||
// .then(() => { |
||||
// console.log(id, '删除id') |
||||
// getSendMessageList() // 删除成功后重新获取列表数据以更新页面 |
||||
// ElMessage.success('删除成功') |
||||
// // console.log(res) |
||||
// }) |
||||
// .catch((err: any) => { |
||||
// console.log(id, 'id') |
||||
// ElMessage.error(err.response.data.message) |
||||
// }) |
||||
// |
||||
// await getSendMessageList() |
||||
// } |
||||
|
||||
// 分页 |
||||
const handleSizeChange = (size: any) => { |
||||
// loading.value = true |
||||
// console.log(size) |
||||
params.value.pageNo = 1 |
||||
params.value.pageSize = size |
||||
// 基于每页条数重新渲染 |
||||
getSendMessageList() |
||||
} |
||||
const handleCurrentChange = (page: any) => { |
||||
console.log(page) |
||||
params.value.pageNo = page |
||||
// 基于当前页渲染数据 |
||||
getSendMessageList() |
||||
} |
||||
const userId = userStore.userInfo.id |
||||
const router = useRouter() |
||||
//返回 |
||||
const back =()=>{ |
||||
router.push('/messageManagement/message') |
||||
} |
||||
//写栈内信函 |
||||
const sendContent = ()=>{ |
||||
router.push('/messageContent') |
||||
} |
||||
|
||||
// 消息事件点击 |
||||
const handleClick = (item)=> { |
||||
//带查询参数 |
||||
router.push({ path: '/sendMessageList', query: item }) |
||||
} |
||||
|
||||
</script> |
||||
<style scoped> |
||||
.container{ |
||||
margin: auto; |
||||
width: 95%; |
||||
padding: 15px; |
||||
} |
||||
.checkboxHeader { |
||||
width: 100%; |
||||
padding: 10px; |
||||
height: 50px; |
||||
display: flex; /* 使用Flex布局使子元素在同一行显示 */ |
||||
align-items: center; /* 垂直居中对齐子元素 */ |
||||
gap: 10px; /* 设置子元素之间的间距 */ |
||||
} |
||||
|
||||
.custom-checkbox { |
||||
transform: scale(1.5); /* 将勾选框放大1.5倍 */ |
||||
} |
||||
|
||||
.selected-count { |
||||
|
||||
} |
||||
.message-check{ |
||||
margin-right: 20px; |
||||
} |
||||
.message-list { |
||||
display: flex; |
||||
align-items: center; /* 垂直居中 */ |
||||
height: 80px; |
||||
/*background-color: #f2f2f2;*/ |
||||
padding: 0 10px; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.message-icon { |
||||
margin-right: 30px; /* 图标右侧间距 */ |
||||
font-size: 34px; /* 图标大小 */ |
||||
} |
||||
li{ |
||||
list-style: none; |
||||
} |
||||
.message-content { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; /* 标题和详情内容垂直居中 */ |
||||
flex: 1; /* 填充剩余空间 */ |
||||
} |
||||
|
||||
.message-title { |
||||
line-height: 30px; |
||||
font-size: 20px; |
||||
} |
||||
|
||||
.message-details { |
||||
display: flex; |
||||
align-items: center; /* 细节内容水平居中 */ |
||||
margin-top: 10px; /* 与标题的间距 */ |
||||
} |
||||
|
||||
.sender { |
||||
margin-right: 88px; /* 发件人和已读状态的间距 */ |
||||
} |
||||
|
||||
.read-status { |
||||
color: #888; /* 已读状态的颜色 */ |
||||
} |
||||
|
||||
.message-time { |
||||
margin-left: auto; /* 发送时间靠右显示 */ |
||||
font-size: 15px; /* 发送时间字体大小 */ |
||||
color: #666; /* 发送时间颜色 */ |
||||
} |
||||
|
||||
.message-list-item { |
||||
cursor: pointer; /* 鼠标悬停时显示手指形状,表示可点击 */ |
||||
} |
||||
.message-list-item:hover{ |
||||
background-image: linear-gradient(60deg,powderblue,darkgrey,snow); |
||||
} |
||||
</style> |
@ -0,0 +1,80 @@ |
||||
<template> |
||||
<div class="common-layout"> |
||||
<el-container> |
||||
<el-header class="header"> |
||||
<p>收到信息详情</p> |
||||
</el-header> |
||||
<el-main > |
||||
<el-card> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<el-button type="primary" style="width: 80px" @click="back" round plain>返回</el-button> |
||||
</div> |
||||
</template> |
||||
<div class="container"> |
||||
<div class="header_content"> |
||||
<span class="sender">发送人:{{ sendMessage.senderName }}</span> |
||||
<span class="time">发送时间:{{ sendMessage.sendTime }}</span> |
||||
<span class="read-status">是否阅读:{{sendMessage.isRead}}</span> |
||||
</div> |
||||
<div class="recipient">标题:{{ sendMessage.title }}</div> |
||||
<div class="content"> |
||||
内容:{{ sendMessage.content }} |
||||
</div> |
||||
</div> |
||||
<!-- <template #footer>Footer content</template>--> |
||||
</el-card> |
||||
</el-main> |
||||
</el-container> |
||||
</div> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import {useRouter,useRoute} from "vue-router"; |
||||
const router = useRouter() |
||||
const route = useRoute() |
||||
//获取数据,如果失败返回上一级 |
||||
if(!Object.keys(route.query).length){ |
||||
router.go(-1) |
||||
} |
||||
//返回按钮 |
||||
const back = ()=>{ |
||||
router.push('/messageManagement/sendMessage') |
||||
} |
||||
import {ref} from "vue"; |
||||
//获取参数 |
||||
const sendMessage = ref(route.query) |
||||
|
||||
</script> |
||||
|
||||
<style scoped> |
||||
.header{ |
||||
background: #7f98cb; |
||||
height: 50px; |
||||
font-size: 20px; |
||||
text-align: center; |
||||
padding: 15px; |
||||
} |
||||
.container { |
||||
padding: 10px; /* 容器内边距 */ |
||||
margin-top: 10px; /* 容器上边距 */ |
||||
height: 65vh; |
||||
} |
||||
.header_content { |
||||
margin-bottom: 10px; /* 与下面的收件人信息保持一定间距 */ |
||||
} |
||||
|
||||
.header_content span { |
||||
margin-right: 50px; /* 发件人和时间之间的间距 */ |
||||
} |
||||
|
||||
.header_content .read-status { |
||||
margin-right: 0; /* 已读状态右侧不需要间距 */ |
||||
} |
||||
|
||||
.recipient, .content { |
||||
font-size: 20px; |
||||
color: #333; |
||||
margin-top: 10px; |
||||
margin-bottom: 20px; |
||||
} |
||||
</style> |
@ -1,5 +1,269 @@ |
||||
<template> |
||||
<div>消息</div> |
||||
<el-card> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<el-button type="primary" @click="editContent" round>写栈内信函</el-button> |
||||
<el-button type="primary" @click="sendContent" round>个人发出</el-button> |
||||
</div> |
||||
</template> |
||||
<div class="container"> |
||||
<div class="checkboxHeader"> |
||||
<input type="checkbox" class="custom-checkbox" @change="toggleAll" :checked="allSelected" /> |
||||
<p class="selected-count">已选 {{ selectedCount }} 条记录</p> |
||||
</div> |
||||
<li v-for="item in Message" |
||||
:key="item.title" |
||||
class="message-list-item" |
||||
> |
||||
<!--添加悬浮删除按钮--> |
||||
<div class="message-list" @mouseover="hoveringOver = item.id" @mouseleave="hoveringOver = null"> |
||||
<!-- 添加勾选框 --> |
||||
<div class="messageCheck"> |
||||
<input type="checkbox" class="custom-checkbox" :value="item.id" @change="toggleSelection(item.id)" :checked="isSelected(item.id)"/> |
||||
</div> |
||||
<!-- 图标 --> |
||||
<div class="message-icon"> |
||||
<el-icon><Comment /></el-icon> |
||||
</div> |
||||
<div class="message-content" @click="handleClick(item)"> |
||||
<h2 class="message-title">{{item.title}}</h2> |
||||
<div class="message-details"> |
||||
<span class="sender">发件人:{{item.sendPerson}}</span> |
||||
<span class="read-status">已读状态:{{item.isRead}}</span> |
||||
</div> |
||||
<div class="message-time">发送时间:{{item.sendTime}}</div> |
||||
</div> |
||||
<!-- 删除按钮,默认不显示,hover时显示 --> |
||||
<el-button v-if="hoveringOver === item.id" class="delete-btn" @click="deleteMessage(item.id)" type="danger" round>删除</el-button> |
||||
</div> |
||||
<el-divider/> |
||||
</li> |
||||
</div> |
||||
<template #footer> |
||||
<el-pagination |
||||
v-model:current-page="params.pageNo" |
||||
v-model:page-size="params.pageSize" |
||||
:page-sizes="[2,4, 5, 7, 10]" |
||||
:background="true" |
||||
layout="jumper,total, sizes, prev, pager, next " |
||||
:total="total" |
||||
@size-change="handleSizeChange" |
||||
@current-change="handleCurrentChange" |
||||
style="margin-top: 10px; justify-content: center" |
||||
/> |
||||
</template> |
||||
</el-card> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import { ref,computed,onMounted} from 'vue'; |
||||
import { useRouter } from 'vue-router'; |
||||
import useUserStore from "@/store/modules/user"; |
||||
import {getMessagesListApi,deleteSendMessageApi} from "@/api/user/messag"; |
||||
import { ElMessageBox, ElMessage } from 'element-plus' |
||||
const userStore = useUserStore() |
||||
const params = ref({ |
||||
userId: userStore.userInfo.id, |
||||
// userId: 4, |
||||
isAsc:true, |
||||
isDelete:0, |
||||
isRead:'', |
||||
isSend:1, |
||||
// messageId:false, |
||||
pageNo:1, |
||||
pageSize:4, |
||||
sortBy:false,//排序字段 |
||||
}) |
||||
const total = ref(0) |
||||
const Message = ref([]) |
||||
const loading = ref(false) |
||||
const hoveringOver = ref(null) |
||||
//复选框 |
||||
const selectedIds = ref([]); // 存储已选中的消息ID |
||||
const allSelected = computed(() => { |
||||
// 如果所有消息都被选中,则返回true |
||||
return Message.value.length > 0 && Message.value.every(item => selectedIds.value.includes(item.id)); |
||||
}); |
||||
|
||||
<script></script> |
||||
const selectedCount = computed(() => { |
||||
// 返回已选中的消息数量 |
||||
return selectedIds.value.length; |
||||
}); |
||||
|
||||
function toggleAll(event) { |
||||
// 切换所有消息的选中状态 |
||||
const target = event.target; |
||||
if (target.checked) { |
||||
// 如果全选框被选中,则将所有消息的ID添加到selectedIds中 |
||||
selectedIds.value = Message.value.map(item => item.id); |
||||
} else { |
||||
// 如果全选框未被选中,则清空selectedIds |
||||
selectedIds.value = []; |
||||
} |
||||
} |
||||
|
||||
function toggleSelection(id: number) { |
||||
// 切换单个消息的选中状态 |
||||
const index = selectedIds.value.indexOf(id); |
||||
if (index > -1) { |
||||
selectedIds.value.splice(index, 1); |
||||
} else { |
||||
selectedIds.value.push(id); |
||||
} |
||||
} |
||||
|
||||
function isSelected(id) { |
||||
return selectedIds.value.includes(id); |
||||
} |
||||
|
||||
// 获取课程列表 |
||||
const getMessageList = async () => { |
||||
loading.value = true |
||||
const res = await getMessagesListApi(params.value) |
||||
Message.value = res.data.list |
||||
total.value = res.data.total |
||||
loading.value = false |
||||
} |
||||
// 渲染 |
||||
onMounted(() => { |
||||
getMessageList() |
||||
}) |
||||
//删除当前记录 |
||||
const deleteMessage = async (id: any) => { |
||||
await ElMessageBox.confirm('您确定删除这条课程信息吗', '温馨提示', { |
||||
confirmButtonText: '确认', |
||||
cancelButtonText: '取消', |
||||
type: 'warning', |
||||
}) |
||||
await deleteSendMessageApi({ |
||||
messageIds:id, |
||||
userId:userStore.userInfo.id |
||||
}) |
||||
.then(() => { |
||||
console.log(id, '删除id') |
||||
getMessageList() // 删除成功后重新获取列表数据以更新页面 |
||||
ElMessage.success('删除成功') |
||||
// console.log(res) |
||||
}) |
||||
.catch((err: any) => { |
||||
console.log(id, 'id') |
||||
ElMessage.error(err.response.data.message) |
||||
}) |
||||
|
||||
await getMessageList() |
||||
} |
||||
// 分页 |
||||
const handleSizeChange = (size: any) => { |
||||
// loading.value = true |
||||
// console.log(size) |
||||
params.value.pageNo = 1 |
||||
params.value.pageSize = size |
||||
// 基于每页条数重新渲染 |
||||
getMessageList() |
||||
} |
||||
const handleCurrentChange = (page: any) => { |
||||
console.log(page) |
||||
params.value.pageNo = page |
||||
// 基于当前页渲染数据 |
||||
getMessageList() |
||||
} |
||||
const router = useRouter() |
||||
//写站内信函跳转 |
||||
const editContent =()=>{ |
||||
router.push('/messageContent') |
||||
} |
||||
//个人发出跳转 |
||||
const sendContent = ()=>{ |
||||
router.push('/messageManagement/sendMessage') |
||||
} |
||||
|
||||
// 消息事件点击 |
||||
const handleClick = (item)=> { |
||||
// console.log(item) |
||||
//带查询参数 |
||||
router.push({ path: '/messageContentList', query: item }) |
||||
} |
||||
|
||||
</script> |
||||
<style scoped> |
||||
.container{ |
||||
/*background: darkgray;*/ |
||||
margin: auto; |
||||
width: 95%; |
||||
padding: 15px; |
||||
} |
||||
.checkboxHeader { |
||||
/*background: lightgrey;*/ |
||||
width: 100%; |
||||
padding: 10px; |
||||
height: 50px; |
||||
display: flex; /* 使用Flex布局使子元素在同一行显示 */ |
||||
align-items: center; /* 垂直居中对齐子元素 */ |
||||
gap: 10px; /* 设置子元素之间的间距 */ |
||||
} |
||||
|
||||
.custom-checkbox { |
||||
transform: scale(1.5); /* 将勾选框放大1.5倍 */ |
||||
} |
||||
|
||||
.selected-count { |
||||
|
||||
} |
||||
.messageCheck{ |
||||
margin-right: 20px; |
||||
} |
||||
.message-list { |
||||
display: flex; |
||||
align-items: center; /* 垂直居中 */ |
||||
height: 80px; |
||||
/*background-color: #f2f2f2;*/ |
||||
padding: 0 10px; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.message-icon { |
||||
margin-right: 30px; /* 图标右侧间距 */ |
||||
font-size: 34px; /* 图标大小 */ |
||||
} |
||||
li{ |
||||
list-style: none; |
||||
} |
||||
.message-content { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; /* 标题和详情内容垂直居中 */ |
||||
flex: 1; /* 填充剩余空间 */ |
||||
} |
||||
|
||||
.message-title { |
||||
line-height: 30px; |
||||
font-size: 20px; |
||||
} |
||||
|
||||
.message-details { |
||||
display: flex; |
||||
align-items: center; /* 细节内容水平居中 */ |
||||
margin-top: 10px; /* 与标题的间距 */ |
||||
} |
||||
|
||||
.sender { |
||||
margin-right: 88px; /* 发件人和已读状态的间距 */ |
||||
} |
||||
|
||||
.read-status { |
||||
color: #888; /* 已读状态的颜色 */ |
||||
} |
||||
|
||||
.message-time { |
||||
margin-left: auto; /* 发送时间靠右显示 */ |
||||
font-size: 15px; /* 发送时间字体大小 */ |
||||
color: #666; /* 发送时间颜色 */ |
||||
} |
||||
|
||||
.message-list-item { |
||||
cursor: pointer; /* 鼠标悬停时显示手指形状,表示可点击 */ |
||||
} |
||||
|
||||
.message-list-item:hover{ |
||||
background-image: linear-gradient(60deg,powderblue,darkgrey,snow); |
||||
} |
||||
</style> |
||||
|
@ -0,0 +1,59 @@ |
||||
<template> |
||||
<div style="margin: 10px"> |
||||
<img src="C:\project\Teaching_integration_platform_admin_template\public\newslogo.jpg"> |
||||
</div> |
||||
<div> |
||||
<el-card shadow="always"> |
||||
<el-dropdown placement="bottom"> |
||||
<el-button> bottom </el-button> |
||||
<template #dropdown> |
||||
<el-dropdown-menu> |
||||
<el-dropdown-item>The Action 1st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 2st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 3st</el-dropdown-item> |
||||
</el-dropdown-menu> |
||||
</template> |
||||
</el-dropdown> |
||||
<el-dropdown placement="bottom"> |
||||
<el-button> bottom </el-button> |
||||
<template #dropdown> |
||||
<el-dropdown-menu> |
||||
<el-dropdown-item>The Action 1st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 2st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 3st</el-dropdown-item> |
||||
</el-dropdown-menu> |
||||
</template> |
||||
</el-dropdown> |
||||
<el-dropdown placement="bottom"> |
||||
<el-button> bottom </el-button> |
||||
<template #dropdown> |
||||
<el-dropdown-menu> |
||||
<el-dropdown-item>The Action 1st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 2st</el-dropdown-item> |
||||
<el-dropdown-item>The Action 3st</el-dropdown-item> |
||||
</el-dropdown-menu> |
||||
</template> |
||||
</el-dropdown> |
||||
|
||||
</el-card> |
||||
</div> |
||||
<el-card class="container"> |
||||
<template #header> |
||||
<div class="card-header"> |
||||
<span>Card name</span> |
||||
<el-card shadow="hover">Hover</el-card> |
||||
</div> |
||||
</template> |
||||
<p v-for="o in 4" :key="o" class="text item">{{ 'List item ' + o }}</p> |
||||
<template #footer>Footer content</template> |
||||
</el-card> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.container{ |
||||
height: 65vh; |
||||
} |
||||
</style> |
@ -0,0 +1,40 @@ |
||||
// vite.config.ts
|
||||
import vue from "file:///C:/project/Teaching_integration_platform_admin_template/node_modules/.pnpm/@vitejs+plugin-vue@5.1.2_vite@5.4.0_@types+node@22.2.0_sass@1.77.8__vue@3.4.37_typescript@5.5.4_/node_modules/@vitejs/plugin-vue/dist/index.mjs"; |
||||
import path from "path"; |
||||
import { viteMockServe } from "file:///C:/project/Teaching_integration_platform_admin_template/node_modules/.pnpm/vite-plugin-mock@3.0.2_esbuild@0.21.5_mockjs@1.1.0_vite@5.4.0_@types+node@22.2.0_sass@1.77.8_/node_modules/vite-plugin-mock/dist/index.mjs"; |
||||
import { createSvgIconsPlugin } from "file:///C:/project/Teaching_integration_platform_admin_template/node_modules/.pnpm/vite-plugin-svg-icons@2.0.1_vite@5.4.0_@types+node@22.2.0_sass@1.77.8_/node_modules/vite-plugin-svg-icons/dist/index.mjs"; |
||||
var vite_config_default = ({ command }) => { |
||||
return { |
||||
plugins: [ |
||||
vue(), |
||||
viteMockServe({ |
||||
enable: command === "serve" |
||||
}), |
||||
createSvgIconsPlugin({ |
||||
// Specify the icon folder to be cached
|
||||
iconDirs: [path.resolve(process.cwd(), "src/assets/icons")], |
||||
// Specify symbolId format
|
||||
symbolId: "icon-[dir]-[name]" |
||||
}) |
||||
], |
||||
resolve: { |
||||
alias: { |
||||
"@": path.resolve("./src") |
||||
// 相对路径别名配置,使用 @ 代替 src
|
||||
} |
||||
}, |
||||
// 配置scss
|
||||
css: { |
||||
preprocessorOptions: { |
||||
scss: { |
||||
javascriptEnabled: true, |
||||
additionalData: '@import "./src/styles/variable.scss";' |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
}; |
||||
export { |
||||
vite_config_default as default |
||||
}; |
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJDOlxcXFxwcm9qZWN0XFxcXFRlYWNoaW5nX2ludGVncmF0aW9uX3BsYXRmb3JtX2FkbWluX3RlbXBsYXRlXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCJDOlxcXFxwcm9qZWN0XFxcXFRlYWNoaW5nX2ludGVncmF0aW9uX3BsYXRmb3JtX2FkbWluX3RlbXBsYXRlXFxcXHZpdGUuY29uZmlnLnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9DOi9wcm9qZWN0L1RlYWNoaW5nX2ludGVncmF0aW9uX3BsYXRmb3JtX2FkbWluX3RlbXBsYXRlL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcclxuaW1wb3J0IHZ1ZSBmcm9tICdAdml0ZWpzL3BsdWdpbi12dWUnXHJcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXHJcbi8vIFx1NUJGQ1x1NTE2NW1vY2tcdTYzRDJcdTRFRjZcclxuaW1wb3J0IHsgdml0ZU1vY2tTZXJ2ZSB9IGZyb20gJ3ZpdGUtcGx1Z2luLW1vY2snXHJcbi8vIFx1NUJGQ1x1NTE2NXN2Z1x1OTE0RFx1N0Y2RVx1NjNEMlx1NEVGNlxyXG5pbXBvcnQgeyBjcmVhdGVTdmdJY29uc1BsdWdpbiB9IGZyb20gJ3ZpdGUtcGx1Z2luLXN2Zy1pY29ucydcclxuLy8gaHR0cHM6Ly92aXRlanMuZGV2L2NvbmZpZy9cclxuZXhwb3J0IGRlZmF1bHQgKHsgY29tbWFuZCB9OiBhbnkpID0+IHtcclxuICByZXR1cm4ge1xyXG4gICAgcGx1Z2luczogW1xyXG4gICAgICB2dWUoKSxcclxuICAgICAgdml0ZU1vY2tTZXJ2ZSh7XHJcbiAgICAgICAgZW5hYmxlOiBjb21tYW5kID09PSAnc2VydmUnLFxyXG4gICAgICB9KSxcclxuICAgICAgY3JlYXRlU3ZnSWNvbnNQbHVnaW4oe1xyXG4gICAgICAgIC8vIFNwZWNpZnkgdGhlIGljb24gZm9sZGVyIHRvIGJlIGNhY2hlZFxyXG4gICAgICAgIGljb25EaXJzOiBbcGF0aC5yZXNvbHZlKHByb2Nlc3MuY3dkKCksICdzcmMvYXNzZXRzL2ljb25zJyldLFxyXG4gICAgICAgIC8vIFNwZWNpZnkgc3ltYm9sSWQgZm9ybWF0XHJcbiAgICAgICAgc3ltYm9sSWQ6ICdpY29uLVtkaXJdLVtuYW1lXScsXHJcbiAgICAgIH0pLFxyXG4gICAgXSxcclxuICAgIHJlc29sdmU6IHtcclxuICAgICAgYWxpYXM6IHtcclxuICAgICAgICAnQCc6IHBhdGgucmVzb2x2ZSgnLi9zcmMnKSwgLy8gXHU3NkY4XHU1QkY5XHU4REVGXHU1Rjg0XHU1MjJCXHU1NDBEXHU5MTREXHU3RjZFXHVGRjBDXHU0RjdGXHU3NTI4IEAgXHU0RUUzXHU2NkZGIHNyY1xyXG4gICAgICB9LFxyXG4gICAgfSxcclxuICAgIC8vIFx1OTE0RFx1N0Y2RXNjc3NcclxuICAgIGNzczoge1xyXG4gICAgICBwcmVwcm9jZXNzb3JPcHRpb25zOiB7XHJcbiAgICAgICAgc2Nzczoge1xyXG4gICAgICAgICAgamF2YXNjcmlwdEVuYWJsZWQ6IHRydWUsXHJcbiAgICAgICAgICBhZGRpdGlvbmFsRGF0YTogJ0BpbXBvcnQgXCIuL3NyYy9zdHlsZXMvdmFyaWFibGUuc2Nzc1wiOycsXHJcbiAgICAgICAgfSxcclxuICAgICAgfSxcclxuICAgIH0sXHJcbiAgfVxyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFDQSxPQUFPLFNBQVM7QUFDaEIsT0FBTyxVQUFVO0FBRWpCLFNBQVMscUJBQXFCO0FBRTlCLFNBQVMsNEJBQTRCO0FBRXJDLElBQU8sc0JBQVEsQ0FBQyxFQUFFLFFBQVEsTUFBVztBQUNuQyxTQUFPO0FBQUEsSUFDTCxTQUFTO0FBQUEsTUFDUCxJQUFJO0FBQUEsTUFDSixjQUFjO0FBQUEsUUFDWixRQUFRLFlBQVk7QUFBQSxNQUN0QixDQUFDO0FBQUEsTUFDRCxxQkFBcUI7QUFBQTtBQUFBLFFBRW5CLFVBQVUsQ0FBQyxLQUFLLFFBQVEsUUFBUSxJQUFJLEdBQUcsa0JBQWtCLENBQUM7QUFBQTtBQUFBLFFBRTFELFVBQVU7QUFBQSxNQUNaLENBQUM7QUFBQSxJQUNIO0FBQUEsSUFDQSxTQUFTO0FBQUEsTUFDUCxPQUFPO0FBQUEsUUFDTCxLQUFLLEtBQUssUUFBUSxPQUFPO0FBQUE7QUFBQSxNQUMzQjtBQUFBLElBQ0Y7QUFBQTtBQUFBLElBRUEsS0FBSztBQUFBLE1BQ0gscUJBQXFCO0FBQUEsUUFDbkIsTUFBTTtBQUFBLFVBQ0osbUJBQW1CO0FBQUEsVUFDbkIsZ0JBQWdCO0FBQUEsUUFDbEI7QUFBQSxNQUNGO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K
|
Loading…
Reference in new issue