|
|
@@ -1,7 +1,10 @@
|
|
|
<template>
|
|
|
- <div class="page-container">
|
|
|
- <PageTitle title="消息通知" />
|
|
|
-
|
|
|
+ <div class="message-container">
|
|
|
+ <div class="page-title"><i class="title-bar"></i><span>消息通知</span></div>
|
|
|
+ <!-- 搜索栏 -->
|
|
|
+ <div class="search-bar">
|
|
|
+ <div class="search-right"><el-button type="danger" @click="handleAdd">新增消息通知</el-button></div>
|
|
|
+ </div>
|
|
|
<!-- Tab切换 -->
|
|
|
<!-- <div class="tab-nav">
|
|
|
<div v-for="tab in tabs" :key="tab.key" :class="['tab-item', { active: activeTab === tab.key }]" @click="activeTab = tab.key">
|
|
|
@@ -11,36 +14,80 @@
|
|
|
</div> -->
|
|
|
|
|
|
<!-- 消息列表 -->
|
|
|
- <div class="message-list">
|
|
|
- <div v-for="(item, index) in messageList" :key="index" class="message-item">
|
|
|
- <div class="message-content">
|
|
|
- <div :class="['message-icon', item.iconType || 'user']">
|
|
|
- <el-icon v-if="item.iconType === 'package'" :size="20" color="#e60012"><Box /></el-icon>
|
|
|
- <template v-else-if="item.iconType === 'budget'"><span class="budget-text">¥</span></template>
|
|
|
- <el-icon v-else :size="20" color="#fff"><User /></el-icon>
|
|
|
- <span v-if="item.unread" class="unread-dot"></span>
|
|
|
- </div>
|
|
|
- <div class="message-info">
|
|
|
- <div class="message-title">{{ item.title }}</div>
|
|
|
- <div class="message-desc">{{ item.desc }}</div>
|
|
|
- </div>
|
|
|
- <div class="message-right">
|
|
|
- <div class="message-time">{{ item.time }}</div>
|
|
|
- <el-button v-if="item.showAction" type="danger" size="small" @click="handleProcess(item)">去处理</el-button>
|
|
|
+ <!-- <div class="message-list">
|
|
|
+ <div v-for="(item, index) in messageList" :key="index" class="message-item">
|
|
|
+ <div class="message-content">
|
|
|
+ <div :class="['message-icon', item.iconType || 'user']">
|
|
|
+ <el-icon v-if="item.iconType === 'package'" :size="20" color="#e60012"><Box /></el-icon>
|
|
|
+ <template v-else-if="item.iconType === 'budget'"><span class="budget-text">¥</span></template>
|
|
|
+ <el-icon v-else :size="20" color="#fff"><User /></el-icon>
|
|
|
+ <span v-if="item.unread" class="unread-dot"></span>
|
|
|
+ </div>
|
|
|
+ <div class="message-info">
|
|
|
+ <div class="message-title">{{ item.title }}</div>
|
|
|
+ <div class="message-desc">{{ item.content }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="message-right">
|
|
|
+ <div class="message-time">{{ item.createTime }}</div>
|
|
|
+ <el-button v-if="item.showAction" type="danger" size="small" @click="handleProcess(item)">去处理</el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <el-empty v-if="messageList.length === 0" description="暂无消息" />
|
|
|
- </div>
|
|
|
+ <el-empty v-if="messageList.length === 0" description="暂无消息" />
|
|
|
+ </div> -->
|
|
|
|
|
|
<!-- 分页 -->
|
|
|
- <TablePagination
|
|
|
- v-if="messageList.length > 0"
|
|
|
- v-model:page="queryParams.pageNum"
|
|
|
- v-model:pageSize="queryParams.pageSize"
|
|
|
- :total="total"
|
|
|
- @change="handleQuery"
|
|
|
- />
|
|
|
+ <!-- <TablePagination
|
|
|
+ v-if="messageList.length > 0"
|
|
|
+ v-model:page="queryParams.pageNum"
|
|
|
+ v-model:pageSize="queryParams.pageSize"
|
|
|
+ :total="total"
|
|
|
+ @change="handleQuery"
|
|
|
+ /> -->
|
|
|
+
|
|
|
+ <!-- 表格 -->
|
|
|
+ <el-table :data="messageList" border style="width: 100%">
|
|
|
+ <el-table-column prop="title" label="标题" width="120" align="center" />
|
|
|
+ <el-table-column prop="content" label="内容" />
|
|
|
+ <el-table-column prop="createTime" label="创建时间" width="160" align="center" />
|
|
|
+
|
|
|
+ <el-table-column label="操作" width="120" align="center" fixed="right">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div style="display: flex; gap: 8px; justify-content: center">
|
|
|
+ <el-button type="primary" link @click="handleEdit(row)">修改</el-button>
|
|
|
+ <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div class="pagination-wrap">
|
|
|
+ <span class="total-text">共计 {{ total }} 条</span>
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="queryParams.pageNum"
|
|
|
+ v-model:page-size="queryParams.pageSize"
|
|
|
+ :page-sizes="[10, 20, 50]"
|
|
|
+ :total="total"
|
|
|
+ layout="prev, pager, next, sizes, jumper"
|
|
|
+ @size-change="handleQuery"
|
|
|
+ @current-change="handleQuery"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <!-- 新增/编辑弹窗 -->
|
|
|
+ <el-dialog v-model="dialogVisible" :title="dialogTitle" width="550px">
|
|
|
+ <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
|
|
+ <el-form-item label="标题" prop="title">
|
|
|
+ <el-input v-model="form.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容" prop="content">
|
|
|
+ <el-input v-model="form.content" type="textare" :min="5" placeholder="请输入内容" />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="dialogVisible = false">取消</el-button>
|
|
|
+ <el-button type="danger" @click="handleSave">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -49,61 +96,110 @@ import { ref, reactive, watch } from 'vue';
|
|
|
import { Document, Bell, Warning, User, Box } from '@element-plus/icons-vue';
|
|
|
import { ElMessage } from 'element-plus';
|
|
|
import { PageTitle, TablePagination } from '@/components';
|
|
|
+import { getMessageList, getMessageInfo, addMessage, updateMessage, deleteMessage } from '@/api/pc/enterprise';
|
|
|
|
|
|
const activeTab = ref('approval');
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const dialogTitle = ref('新增消息通知');
|
|
|
+const formRef = ref();
|
|
|
+const editingId = ref<number | null>(null);
|
|
|
+const form = reactive({ title: '', content: '' });
|
|
|
+
|
|
|
+const rules = {
|
|
|
+ title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
|
|
+ content: [{ required: true, message: '请输入内容', trigger: 'blur' }]
|
|
|
+};
|
|
|
const tabs = [
|
|
|
{ key: 'approval', label: '审批待办', icon: Document },
|
|
|
{ key: 'arrival', label: '到货提醒', icon: Bell },
|
|
|
{ key: 'budget', label: '预算预警', icon: Warning }
|
|
|
];
|
|
|
|
|
|
+const resetForm = () => {
|
|
|
+ form.title = '';
|
|
|
+ form.content = '';
|
|
|
+ editingId.value = null;
|
|
|
+};
|
|
|
const queryParams = reactive({ pageNum: 1, pageSize: 10 });
|
|
|
const total = ref(0);
|
|
|
const messageList = ref<any[]>([]);
|
|
|
-
|
|
|
const loadData = () => {
|
|
|
if (activeTab.value === 'approval') {
|
|
|
- messageList.value = [
|
|
|
- // {
|
|
|
- // time: '2025/01/10 11:42:32',
|
|
|
- // title: '您有一个审批流程待处理',
|
|
|
- // desc: '审批名称:办公用品采购申请',
|
|
|
- // unread: true,
|
|
|
- // showAction: true,
|
|
|
- // iconType: 'user'
|
|
|
- // },
|
|
|
- // {
|
|
|
- // time: '2025/01/10 11:42:32',
|
|
|
- // title: '您的办公用品审批申请已通过',
|
|
|
- // desc: '审批名称:办公用品采购申请',
|
|
|
- // unread: true,
|
|
|
- // showAction: false,
|
|
|
- // iconType: 'user'
|
|
|
- // },
|
|
|
- // {
|
|
|
- // time: '2025/01/10 11:42:32',
|
|
|
- // title: '您的办公用品审批申请已通过',
|
|
|
- // desc: '审批名称:办公用品采购申请',
|
|
|
- // unread: true,
|
|
|
- // showAction: false,
|
|
|
- // iconType: 'user'
|
|
|
- // }
|
|
|
- ];
|
|
|
- total.value = 3;
|
|
|
+ messageList.value = [];
|
|
|
+ total.value = 0;
|
|
|
} else if (activeTab.value === 'arrival') {
|
|
|
- messageList.value = [
|
|
|
- // { time: '2025/01/10 11:42:32', title: '包裹到货提醒', desc: '物流状态:已到达代售点', unread: true, showAction: false, iconType: 'package' },
|
|
|
- // { time: '2025/01/10 11:42:32', title: '包裹到货提醒', desc: '物流状态:已到达代售点', unread: false, showAction: false, iconType: 'package' }
|
|
|
- ];
|
|
|
- total.value = 2;
|
|
|
+ messageList.value = [];
|
|
|
+ total.value = 0;
|
|
|
} else {
|
|
|
- messageList.value = [
|
|
|
- // { time: '2025/01/10 11:42:32', title: '预算预警', desc: '副标题副副标题', unread: true, showAction: false, iconType: 'budget' },
|
|
|
- // { time: '2025/01/10 11:42:32', title: '预算预警', desc: '副标题副副标题', unread: false, showAction: false, iconType: 'budget' }
|
|
|
- ];
|
|
|
- total.value = 2;
|
|
|
+ messageList.value = [];
|
|
|
+ total.value = 0;
|
|
|
}
|
|
|
};
|
|
|
+const handleAdd = () => {
|
|
|
+ resetForm();
|
|
|
+ dialogTitle.value = '新增收货地址';
|
|
|
+ dialogVisible.value = true;
|
|
|
+};
|
|
|
+const handleEdit = (item: any) => {
|
|
|
+ editingId.value = item.id;
|
|
|
+ form.title = item.title;
|
|
|
+ form.content = item.content;
|
|
|
+
|
|
|
+ dialogTitle.value = '编辑收货地址';
|
|
|
+ dialogVisible.value = true;
|
|
|
+};
|
|
|
+const handleSave = async () => {
|
|
|
+ const valid = await formRef.value?.validate();
|
|
|
+ if (!valid) return;
|
|
|
+ try {
|
|
|
+ const data: any = {
|
|
|
+ title: form.title,
|
|
|
+ content: form.content
|
|
|
+ };
|
|
|
+
|
|
|
+ if (editingId.value) {
|
|
|
+ data.id = editingId.value;
|
|
|
+ await updateMessage(data);
|
|
|
+ } else {
|
|
|
+ await addMessage(data);
|
|
|
+ }
|
|
|
+ ElMessage.success(editingId.value ? '修改成功' : '新增成功');
|
|
|
+ dialogVisible.value = false;
|
|
|
+ loadMessageList();
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('操作失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+const handleDelete = (item: any) => {
|
|
|
+ ElMessageBox.confirm('确定要删除该消息通知吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(
|
|
|
+ async () => {
|
|
|
+ try {
|
|
|
+ await deleteMessage([item.id]);
|
|
|
+ ElMessage.success('删除成功');
|
|
|
+ loadMessageList();
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('删除失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+// 加载消息通知
|
|
|
+const loadMessageList = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getMessageList();
|
|
|
+ if (res.code === 200) {
|
|
|
+ messageList.value = res.rows || [];
|
|
|
+ total.value = res.total || 0;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('加载消息通知列表失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ loadMessageList();
|
|
|
+});
|
|
|
|
|
|
watch(
|
|
|
activeTab,
|
|
|
@@ -114,7 +210,7 @@ watch(
|
|
|
{ immediate: true }
|
|
|
);
|
|
|
const handleQuery = () => {
|
|
|
- loadData();
|
|
|
+ loadMessageList();
|
|
|
};
|
|
|
const handleProcess = (_item: any) => {
|
|
|
ElMessage.info('跳转到审批处理页面');
|
|
|
@@ -122,100 +218,46 @@ const handleProcess = (_item: any) => {
|
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
-.tab-nav {
|
|
|
+.message-container {
|
|
|
+ padding: 20px;
|
|
|
+ background: #fff;
|
|
|
+ min-height: 100%;
|
|
|
+ flex: 1;
|
|
|
+}
|
|
|
+.page-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: bold;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+.title-bar {
|
|
|
+ display: inline-block;
|
|
|
+ width: 3px;
|
|
|
+ height: 16px;
|
|
|
+ background: #e60012;
|
|
|
+ border-radius: 2px;
|
|
|
+}
|
|
|
+.search-bar {
|
|
|
display: flex;
|
|
|
- gap: 30px;
|
|
|
- border-bottom: 1px solid #eee;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
margin-bottom: 20px;
|
|
|
- .tab-item {
|
|
|
+ .search-right {
|
|
|
+ flex: 1;
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 5px;
|
|
|
- padding: 10px 0;
|
|
|
- cursor: pointer;
|
|
|
- color: #666;
|
|
|
- font-size: 14px;
|
|
|
- border-bottom: 2px solid transparent;
|
|
|
- margin-bottom: -1px;
|
|
|
- &:hover,
|
|
|
- &.active {
|
|
|
- color: #333;
|
|
|
- }
|
|
|
- &.active {
|
|
|
- border-bottom-color: #e60012;
|
|
|
- }
|
|
|
+ justify-content: flex-end;
|
|
|
}
|
|
|
}
|
|
|
-.message-list {
|
|
|
- .message-item {
|
|
|
- padding: 15px 0;
|
|
|
- border-bottom: 1px solid #f5f5f5;
|
|
|
- &:last-child {
|
|
|
- border-bottom: none;
|
|
|
- }
|
|
|
- .message-content {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 15px;
|
|
|
- .message-icon {
|
|
|
- position: relative;
|
|
|
- width: 40px;
|
|
|
- height: 40px;
|
|
|
- border-radius: 8px;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- flex-shrink: 0;
|
|
|
- &.user {
|
|
|
- background: #e60012;
|
|
|
- }
|
|
|
- &.package {
|
|
|
- background: #fff5f5;
|
|
|
- border: 1px solid #ffe0e0;
|
|
|
- }
|
|
|
- &.budget {
|
|
|
- background: #e60012;
|
|
|
- .budget-text {
|
|
|
- color: #fff;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: bold;
|
|
|
- }
|
|
|
- }
|
|
|
- .unread-dot {
|
|
|
- position: absolute;
|
|
|
- top: -2px;
|
|
|
- right: -2px;
|
|
|
- width: 8px;
|
|
|
- height: 8px;
|
|
|
- border-radius: 50%;
|
|
|
- background: #e60012;
|
|
|
- border: 2px solid #fff;
|
|
|
- }
|
|
|
- }
|
|
|
- .message-info {
|
|
|
- flex: 1;
|
|
|
- .message-title {
|
|
|
- font-size: 14px;
|
|
|
- font-weight: 500;
|
|
|
- color: #333;
|
|
|
- margin-bottom: 5px;
|
|
|
- }
|
|
|
- .message-desc {
|
|
|
- font-size: 13px;
|
|
|
- color: #999;
|
|
|
- }
|
|
|
- }
|
|
|
- .message-right {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: flex-end;
|
|
|
- gap: 8px;
|
|
|
- .message-time {
|
|
|
- font-size: 12px;
|
|
|
- color: #999;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+.pagination-wrap {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-top: 20px;
|
|
|
+ .total-text {
|
|
|
+ font-size: 14px;
|
|
|
+ color: #666;
|
|
|
}
|
|
|
}
|
|
|
</style>
|