2025-11-20 16:44:45 +08:00

594 lines
14 KiB
Vue

<template>
<div class="mainBox">
<div class="leftBox">
<div class="section">
<div class="bigTitle">快捷导航</div>
<ul class="recUl">
<li v-for="(item,index) in navList" :key="index" @click="goBaidu(item)">
<img :src="getNavIcon(index)" class="nav-icon" alt="icon" />
{{ item.name }}
</li>
</ul>
</div>
<div class="section">
<div class="bigTitle">资源概览</div>
<ul class="recUl overView">
<li v-for="(item, index) in viewList" :key="index">
<div class="overview-item">
<span class="title">{{ item.name }}</span>
<span class="number">{{ item.count }}</span>
</div>
</li>
</ul>
</div>
<div class="section">
<div class="bigTitle">到期预警</div>
<div class="table-container">
<el-table
height="250px"
border
:data="tableData"
style="width: 100%"
header-cell-class-name="table-header"
cell-class-name="table-cell">
<el-table-column prop="name" label="名称" min-width="120"></el-table-column>
<el-table-column prop="instanceid" label="资源id" min-width="120"></el-table-column>
<el-table-column prop="status" label="状态" min-width="80">
<template slot-scope="scope">
<el-tag :type="scope.row.status === '即将到期' ? 'warning' : 'danger'">
{{ scope.row.status }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="days" label="剩余天数" min-width="80">
<template slot-scope="scope">
<span :class="scope.row.days < 3 ? 'critical' : ''">{{ scope.row.days }}</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<!-- 右侧部分保持不变 -->
<div class="rightBox">
<div class="user card">
<div class="userImg">
<div class="imgUser">{{ userInfo.username.charAt(0) }}</div>
</div>
<div class="userBox">
<h3>{{ userInfo.username }}</h3>
<div class="user-info">
<p><i class="el-icon-user"></i> ID: {{ userInfo.id }}</p>
<p><i class="el-icon-phone"></i> 手机号: {{ userInfo.mobile }}</p>
<p><i class="el-icon-message"></i> 邮箱: {{ userInfo.email }}</p>
</div>
</div>· </div>
<div class="price card">
<div class="title">账户余额</div>
<div class="content">
<span class="balance">{{ mybalance }}</span>
<el-button size="mini" type="primary" @click="$router.push('/kbossCharge')">
立即充值
</el-button>
</div>
</div>
<div class="todos card">
<div class="title">待办事项</div>
<ul class="todo-list">
<li
v-for="(item, index) in todoList"
:key="index"
class="todo-item"
@click="handleTodoClick(item.name)"
>
<span class="todo-name">{{ item.name }}</span>
<span class="todo-count">{{ item.count }}</span>
</li>
</ul>
</div>
</div>
<MessageCenter
ref="messageCenter"
:visible.sync="messageCenterVisible"
@unread-count-update="handleUnreadCountUpdate"
/>
</div>
</template>
<script>
import Vue from 'vue'
import { mapState } from "vuex";
import { reqNewHomeResource, reqNewHomeResourceWarning, reqQuickNav, todoCount } from "@/api/newHome";
import { editReachargelogAPI } from "@/api/finance/customerRechargeManagement";
import { getUnreadmsgAPI } from "@/api/login";
import MessageCenter from '@/components/MessageCenter/MessageCenter.vue';
import icon1 from '@/assets/image/icon1.png';
import icon2 from '@/assets/image/icon2.png';
import icon3 from '@/assets/image/icon3.png';
import icon4 from '@/assets/image/icon4.png';
export default Vue.extend({
name: "mainPage",
components: {
MessageCenter
},
data() {
return {
tableData: [],
userInfo: {
id: "",
username: "",
mobile: "",
email: ""
},
viewList: [],
navList: [],
// 移除 data 中的 mybalance 定义
mybalance: 0,
todoList: [
{ name: '待支付', count: 0 },
{ name: '待续费', count: 0 },
{ name: '处理中', count: 0 },
{ name: '站内信', count: 0 }
],
messageCenterVisible: false,
// 添加图标路径数组
navIcons: [icon1, icon2, icon3, icon4]
}
},
created() {
// 移除 initMybalance 调用,因为现在使用 computed 的 mybalance
this.initMybalance(); // ❌ 删除这一行
this.getUnreadMsgCount();
this.fetchTodoCount();
},
mounted() {
reqQuickNav().then(res => {
this.navList = res.data
})
this.userInfo = JSON.parse(localStorage.getItem("user_info") || "{}");
reqNewHomeResource().then(res => {
if (res.status) {
this.viewList = res.data || [];
} else {
this.$message.error(res.msg);
}
})
reqNewHomeResourceWarning().then(res => {
if (res.status) {
this.tableData = res.data || [];
} else {
this.$message.error(res.msg);
}
})
},
methods: {
goBaidu(item) {
this.$store.commit('setRedirectUrl', item.url)
localStorage.setItem('redirectUrl', item.url)
localStorage.setItem('userRescourseUrl', item.listUrl)
this.$router.push({
name: 'baiduProductShow',
params: {
listUrl: item.listUrl,
url: item.url
}
})
},
// 添加获取导航图标的方法
getNavIcon(index) {
// 如果导航项数量超过图标数量,循环使用图标
const iconIndex = index % this.navIcons.length;
return this.navIcons[iconIndex];
},
// 移除 initMybalance 方法,因为现在使用 computed 的 mybalance
async initMybalance() { // ❌ 删除这个方法
const res = await editReachargelogAPI()
if (res.status) {
this.mybalance = res.data
}
},
async getUnreadMsgCount() {
try {
const res = await getUnreadmsgAPI();
if (res.status) {
const messageItem = this.todoList.find(item => item.name === '站内信');
if (messageItem) {
messageItem.count = res.data || 0;
}
} else {
this.$message.error(res.msg || '获取未读消息失败');
}
} catch (error) {
console.error('获取未读消息失败:', error);
this.$message.error('获取未读消息失败');
}
},
// 获取待办事项数量
async fetchTodoCount() {
try {
const res = await todoCount();
if (res.status && res.data) {
// 更新待办事项数量
this.todoList = this.todoList.map(item => {
switch(item.name) {
case '待支付':
return { ...item, count: res.data.pending_payment_orders || 0 };
case '待续费':
return { ...item, count: res.data.pending_renew_orders || 0 };
case '处理中':
return { ...item, count: res.data.processing_orders || 0 };
default:
return item;
}
});
} else {
this.$message.error(res.msg || '获取待办事项数量失败');
}
} catch (error) {
console.error('获取待办事项数量失败:', error);
this.$message.error('获取待办事项数量失败');
}
},
handleTodoClick(todoName) {
if (todoName === '站内信') {
this.openMessageCenter();
} else {
let query = {};
switch(todoName) {
case '待支付':
query = {
filterType: 'processing'
};
break;
case '待续费':
query = {
filterType: 'pendingPayment'
};
break;
case '处理中':
query = {
filterType: 'processing'
};
break;
}
console.log(`跳转到资源概览,筛选类型: ${todoName}`, query);
this.$router.push({
path: '/orderManagement/orderManagement',
query: query
});
}
},
openMessageCenter() {
this.messageCenterVisible = true;
},
handleUnreadCountUpdate(count) {
const messageItem = this.todoList.find(item => item.name === '站内信');
if (messageItem) {
messageItem.count = count || 0;
}
}
},
computed: {
...mapState({
mybalance: state => state.user.mybalance,
})
},
})
</script>
<style lang="less" scoped>
::v-deep .table-header {
background: #409eff !important;
color: #ffffff !important;
font-weight: bold;
text-align: center;
}
.mainBox {
background: #f5f7fa;
width: 100%;
height: calc(100vh - 100px);
display: flex;
padding: 10px;
padding-bottom: 20px;
box-sizing: border-box;
gap: 20px;
overflow-y: auto;
overflow-x: hidden;
}
.leftBox {
width: 65%;
display: flex;
flex-direction: column;
gap: 20px;
min-width: 0;
.section {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
}
.rightBox {
width: 35%;
display: flex;
flex-direction: column;
gap: 20px;
min-width: 0;
.card {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
}
.table-container {
width: 100%;
overflow-x: auto;
border-radius: 4px;
}
.table-container ::v-deep .el-table {
width: 100% !important;
}
.recUl {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 15px;
list-style: none;
padding: 0;
margin: 0;
li {
padding: 15px;
cursor: pointer;
transition: all 0.3s ease;
border: 1px solid #ebeef5;
border-radius: 8px;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 0;
// 修改这里:为图片添加样式
.nav-icon {
width: 24px;
height: 24px;
margin-bottom: 10px;
object-fit: contain;
}
// 移除原来的图标样式
// i {
// font-size: 24px;
// margin-bottom: 10px;
// color: #409eff;
// }
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
border-color: #409eff;
}
}
}
.overView {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
li {
cursor: default;
&:hover {
transform: none;
box-shadow: none;
border-color: #ebeef5;
}
}
.overview-item {
display: flex;
justify-content: space-between;
width: 100%;
min-width: 0;
.title {
font-size: 16px;
color: #606266;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.number {
font-size: 20px;
font-weight: bold;
color: #303133;
white-space: nowrap;
}
}
}
.bigTitle {
color: #303133;
margin-bottom: 20px;
font-size: 18px;
font-weight: bold;
padding-bottom: 10px;
border-bottom: 2px solid #409eff;
display: inline-block;
}
.user {
display: flex;
align-items: center;
.userImg {
margin-right: 20px;
flex-shrink: 0;
.imgUser {
width: 80px;
height: 80px;
border-radius: 50%;
background: linear-gradient(135deg, #409eff, #64b5f6);
font-size: 36px;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
}
.userBox {
flex: 1;
min-width: 0;
h3 {
margin-top: 0;
margin-bottom: 15px;
color: #303133;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-info {
p {
margin: 8px 0;
color: #606266;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
i {
margin-right: 8px;
color: #409eff;
flex-shrink: 0;
}
}
}
}
}
.price {
.content {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
.balance {
font-size: 28px;
font-weight: bold;
color: #e6a23c;
}
}
}
.todos {
.title {
margin-bottom: 15px;
}
.todo-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
.todo-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 15px;
border: 1px solid #ebeef5;
border-radius: 8px;
text-align: center;
transition: all 0.3s ease;
cursor: pointer;
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
border-color: #409eff;
}
.todo-name {
font-size: 14px;
color: #606266;
margin-bottom: 8px;
}
.todo-count {
font-size: 24px;
font-weight: bold;
color: #409eff;
}
}
}
}
.critical {
color: #f56c6c;
font-weight: bold;
}
.table-header {
background-color: #f5f7fa !important;
color: #606266;
font-weight: bold;
}
.table-cell {
padding: 8px 0 !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 768px) {
.mainBox {
flex-direction: column;
height: auto;
overflow-x: hidden;
}
.leftBox, .rightBox {
width: 100%;
flex: none;
}
.recUl {
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.overView {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.todo-list {
grid-template-columns: repeat(2, 1fr);
}
}
</style>