开源版重新整理提交
118
README.md
@@ -13,7 +13,7 @@
|
||||
</p>
|
||||
|
||||
## 平台简介
|
||||
* 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev/) 版本。
|
||||
* 本仓库为红薯管理端:前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev/) 版本。
|
||||
* 配套后端代码仓库地址 [HongShu](https://gitee.com/Maverick_Ma/hongshu.git)
|
||||
|
||||
## 前端运行
|
||||
@@ -25,120 +25,12 @@ git clone https://gitee.com/Maverick_Ma/hongshu-admin.git
|
||||
cd hongshu-admin
|
||||
|
||||
# 安装依赖
|
||||
yarn --registry=https://registry.npmmirror.com
|
||||
npm install
|
||||
|
||||
# 启动服务
|
||||
yarn dev
|
||||
npm run dev
|
||||
|
||||
# 构建测试环境 yarn build:stage
|
||||
# 构建生产环境 yarn build:prod
|
||||
# 构建测试环境 npm build:stage
|
||||
# 构建生产环境 npm build:prod
|
||||
# 前端访问地址 http://localhost:81
|
||||
```
|
||||
|
||||
## 管理端内置功能
|
||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
|
||||
3. 岗位管理:配置系统用户所属担任职务。
|
||||
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
|
||||
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||
7. 参数管理:对系统动态配置常用参数。
|
||||
8. 通知公告:系统通知公告信息发布维护。
|
||||
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||
10. 登录日志:系统登录日志记录查询包含登录异常。
|
||||
11. 在线用户:当前系统中活跃用户状态监控。
|
||||
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||
13. 系统接口:根据业务代码自动生成相关的api接口文档。
|
||||
14. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
|
||||
15. 缓存监控:对系统的缓存信息查询,命令统计等。
|
||||
16. 在线构建器:拖动表单元素生成相应的HTML代码。
|
||||
17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
||||
|
||||
## 2.0版本实现功能
|
||||
1. 添加移动端
|
||||
2. 重构实现 SpringCloud 微服务架构
|
||||
3. 加入商城购物功能
|
||||
4. 加入推荐算法,优化内容推荐和用户推荐功能
|
||||
5. 使用 MQ+Redis 优化点赞、收藏、浏览功能
|
||||
6. 支持七牛云、阿里、腾讯、Minio等多种oss对象存储方式
|
||||
7. 笔记内容支持视频和live图
|
||||
|
||||
#### ⚠️如有【项目问题】或【部署需求】可联系微信:coder_xiaomage
|
||||
|
||||
## 演示站(2.0版)
|
||||
- web端 ➡️ [点我体验](http://47.95.205.22)
|
||||
- admin端 ➡️ [点我体验](http://47.95.205.22/admin/)
|
||||
- app端 ➡️ [点我体验](http://47.95.205.22/app/)
|
||||
- 文档及资料会暂时放到我的个人博客:[点我进入](https://mayongjian.cn)
|
||||
* 由于服务器资源有限,首次加载可能缓慢一些。
|
||||
* 同时为优化服务器也感谢小伙伴们打赏支持❤️。
|
||||
<img src="src/assets/images/reward.png" style="width: 50px heihgt: 50px"/>
|
||||
|
||||
## 视频演示
|
||||
➡️ [点击查看](https://www.bilibili.com/video/BV1QP8dekEGq/?spm_id_from=333.999.list.card_archive.click&vd_source=ec9224821314432ac6e12dc7d500d74b)
|
||||
|
||||
|
||||
## 演示图
|
||||
### - web端:
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/web/web-login.png"/></td>
|
||||
<td><img src="src/assets/images/web/web-dashboard.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/web/web-search.png"/></td>
|
||||
<td><img src="src/assets/images/web/web-trends.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/web/web-message.png"/></td>
|
||||
<td><img src="src/assets/images/web/web-follow.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/web/web-publish.png"/></td>
|
||||
<td><img src="src/assets/images/web/web-user.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### - admin端:
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/admin/admin-login.png"/></td>
|
||||
<td><img src="src/assets/images/admin/admin-data.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/admin/admin-category.png"/></td>
|
||||
<td><img src="src/assets/images/admin/admin-member.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/admin/admin-note.png"/></td>
|
||||
<td><img src="src/assets/images/admin/admin-album.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/admin/admin-comment.png"/></td>
|
||||
<td><img src="src/assets/images/admin/admin-log.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### - app端:
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/app/app-login.png"/></td>
|
||||
<td><img src="src/assets/images/app/app-index.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/app/app-trend.png"/></td>
|
||||
<td><img src="src/assets/images/app/app-message.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/app/app-user.png"/></td>
|
||||
<td><img src="src/assets/images/app/app-follow.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/app/app-hot.png"/></td>
|
||||
<td><img src="src/assets/images/app/app-main.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="src/assets/images/app/app-search.png"/></td>
|
||||
<td><img src="src/assets/images/app/app-push.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
Before Width: | Height: | Size: 2.0 MiB |
Before Width: | Height: | Size: 781 KiB |
Before Width: | Height: | Size: 440 KiB |
Before Width: | Height: | Size: 416 KiB |
Before Width: | Height: | Size: 635 KiB |
Before Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 853 KiB |
Before Width: | Height: | Size: 862 KiB |
Before Width: | Height: | Size: 3.6 MiB |
Before Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 2.7 MiB |
Before Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 939 KiB |
Before Width: | Height: | Size: 416 KiB |
Before Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 102 KiB |
Before Width: | Height: | Size: 986 KiB |
Before Width: | Height: | Size: 2.5 MiB |
Before Width: | Height: | Size: 731 KiB |
Before Width: | Height: | Size: 5.7 MiB |
Before Width: | Height: | Size: 467 KiB |
Before Width: | Height: | Size: 3.6 MiB |
Before Width: | Height: | Size: 326 KiB |
Before Width: | Height: | Size: 304 KiB |
Before Width: | Height: | Size: 5.0 MiB |
Before Width: | Height: | Size: 1016 KiB |
Before Width: | Height: | Size: 3.7 MiB |
@@ -5,117 +5,130 @@
|
||||
<script setup>
|
||||
import { getBlogContributeCount } from "@/api/web/index";
|
||||
import * as echarts from "echarts";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { onMounted, onBeforeUnmount, ref, watch } from "vue";
|
||||
|
||||
const contributeDate = ref([]);
|
||||
const blogContributeCount = ref([]);
|
||||
let chart = null;
|
||||
|
||||
async function initDate() {
|
||||
getBlogContributeCount().then((response) => {
|
||||
if (response.code == 200) {
|
||||
try {
|
||||
const response = await getBlogContributeCount();
|
||||
if (response.code === 200) {
|
||||
contributeDate.value = response.data.contributeDate;
|
||||
blogContributeCount.value = response.data.blogContributeCount;
|
||||
|
||||
const container = document.getElementById("container");
|
||||
if (!container) {
|
||||
console.error("容器元素未找到");
|
||||
return;
|
||||
}
|
||||
|
||||
let chart = echarts.init(container);
|
||||
console.log("ECharts实例化成功:", chart);
|
||||
|
||||
let option = {
|
||||
title: {
|
||||
top: 30,
|
||||
text: "笔记贡献度",
|
||||
subtext: "一年内笔记提交的数量",
|
||||
left: "center",
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: function (params) {
|
||||
return params.data[0] + "<br>笔记数:" + params.data[1];
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: "30",
|
||||
left: "100",
|
||||
data: ["笔记数", "Top 12"],
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
calendar: [
|
||||
{
|
||||
top: 100,
|
||||
left: "center",
|
||||
range: contributeDate.value,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#D3D3D3",
|
||||
width: 4,
|
||||
type: "solid",
|
||||
},
|
||||
},
|
||||
yearLabel: { show: false },
|
||||
dayLabel: {
|
||||
nameMap: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
firstDay: 1,
|
||||
},
|
||||
monthLabel: {
|
||||
nameMap: "cn",
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#ffffff",
|
||||
borderWidth: 1,
|
||||
borderColor: "#D3D3D3",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "笔记数",
|
||||
type: "scatter",
|
||||
coordinateSystem: "calendar",
|
||||
data: blogContributeCount.value,
|
||||
symbolSize: function (val) {
|
||||
if (val[1] == 0) {
|
||||
return val[1];
|
||||
} else {
|
||||
let size = 8 + val[1] * 2;
|
||||
if (size > 18) {
|
||||
size = 18;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "#2ec7c9",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
chart.setOption(option);
|
||||
renderChart();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取数据失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
function renderChart() {
|
||||
const container = document.getElementById("container");
|
||||
if (!container) {
|
||||
console.error("容器元素未找到");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chart) {
|
||||
chart = echarts.init(container);
|
||||
}
|
||||
|
||||
const option = {
|
||||
title: {
|
||||
top: 30,
|
||||
text: "笔记贡献度",
|
||||
subtext: "一年内笔记提交的数量",
|
||||
left: "center",
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: function (params) {
|
||||
return params.data[0] + "<br>笔记数:" + params.data[1];
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: "30",
|
||||
left: "100",
|
||||
data: ["笔记数", "Top 12"],
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
calendar: [
|
||||
{
|
||||
top: 100,
|
||||
left: "center",
|
||||
range: contributeDate.value,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#D3D3D3",
|
||||
width: 4,
|
||||
type: "solid",
|
||||
},
|
||||
},
|
||||
yearLabel: { show: false },
|
||||
dayLabel: {
|
||||
nameMap: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
firstDay: 1,
|
||||
},
|
||||
monthLabel: {
|
||||
nameMap: "cn",
|
||||
textStyle: {
|
||||
color: "#000",
|
||||
},
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#ffffff",
|
||||
borderWidth: 1,
|
||||
borderColor: "#D3D3D3",
|
||||
},
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: "笔记数",
|
||||
type: "scatter",
|
||||
coordinateSystem: "calendar",
|
||||
data: blogContributeCount.value,
|
||||
symbolSize: function (val) {
|
||||
let size = val[1] === 0 ? 0 : Math.min(18, 8 + val[1] * 2);
|
||||
return size;
|
||||
},
|
||||
itemStyle: {
|
||||
color: "#2ec7c9",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chart.setOption(option);
|
||||
}
|
||||
|
||||
function resizeChart() {
|
||||
chart && chart.resize();
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initDate();
|
||||
window.addEventListener("resize", resizeChart);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("resize", resizeChart);
|
||||
if (chart) {
|
||||
chart.dispose();
|
||||
chart = null;
|
||||
}
|
||||
});
|
||||
|
||||
watch([contributeDate, blogContributeCount], renderChart);
|
||||
</script>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a
|
||||
href=""
|
||||
href="https://gitee.com/Maverick_Ma/hongshu"
|
||||
target="_blank"
|
||||
class="github-corner"
|
||||
aria-label="View source on Github"
|
||||
|
@@ -5,9 +5,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const url = ref('http://doc.ruoyi.vip/ruoyi-vue');
|
||||
const url = ref("https://gitee.com/Maverick_Ma/hongshu");
|
||||
|
||||
function goto() {
|
||||
window.open(url.value)
|
||||
window.open(url.value);
|
||||
}
|
||||
</script>
|
@@ -5,9 +5,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const url = ref('https://gitee.com/y_project/RuoYi-Vue');
|
||||
const url = ref("https://gitee.com/Maverick_Ma/hongshu");
|
||||
|
||||
function goto() {
|
||||
window.open(url.value)
|
||||
window.open(url.value);
|
||||
}
|
||||
</script>
|
||||
|
@@ -1,8 +1,21 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
|
||||
<top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
|
||||
<hamburger
|
||||
id="hamburger-container"
|
||||
:is-active="appStore.sidebar.opened"
|
||||
class="hamburger-container"
|
||||
@toggleClick="toggleSideBar"
|
||||
/>
|
||||
<breadcrumb
|
||||
id="breadcrumb-container"
|
||||
class="breadcrumb-container"
|
||||
v-if="!settingsStore.topNav"
|
||||
/>
|
||||
<top-nav
|
||||
id="topmenu-container"
|
||||
class="topmenu-container"
|
||||
v-if="settingsStore.topNav"
|
||||
/>
|
||||
|
||||
<div class="right-menu">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
@@ -23,7 +36,11 @@
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<div class="avatar-container">
|
||||
<el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
|
||||
<el-dropdown
|
||||
@command="handleCommand"
|
||||
class="right-menu-item hover-effect"
|
||||
trigger="click"
|
||||
>
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="userStore.avatar" class="user-avatar" />
|
||||
<el-icon><caret-bottom /></el-icon>
|
||||
@@ -33,7 +50,10 @@
|
||||
<router-link to="/user/profile">
|
||||
<el-dropdown-item>个人中心</el-dropdown-item>
|
||||
</router-link>
|
||||
<el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
|
||||
<el-dropdown-item
|
||||
command="setLayout"
|
||||
v-if="settingsStore.showSettings"
|
||||
>
|
||||
<span>布局设置</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logout">
|
||||
@@ -48,25 +68,25 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import Breadcrumb from '@/components/Breadcrumb'
|
||||
import TopNav from '@/components/TopNav'
|
||||
import Hamburger from '@/components/Hamburger'
|
||||
import Screenfull from '@/components/Screenfull'
|
||||
import SizeSelect from '@/components/SizeSelect'
|
||||
import HeaderSearch from '@/components/HeaderSearch'
|
||||
import RuoYiGit from '@/components/RuoYi/Git'
|
||||
import RuoYiDoc from '@/components/RuoYi/Doc'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import { ElMessageBox } from "element-plus";
|
||||
import Breadcrumb from "@/components/Breadcrumb";
|
||||
import TopNav from "@/components/TopNav";
|
||||
import Hamburger from "@/components/Hamburger";
|
||||
import Screenfull from "@/components/Screenfull";
|
||||
import SizeSelect from "@/components/SizeSelect";
|
||||
import HeaderSearch from "@/components/HeaderSearch";
|
||||
import RuoYiGit from "@/components/RuoYi/Git";
|
||||
import RuoYiDoc from "@/components/RuoYi/Doc";
|
||||
import useAppStore from "@/store/modules/app";
|
||||
import useUserStore from "@/store/modules/user";
|
||||
import useSettingsStore from "@/store/modules/settings";
|
||||
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
function toggleSideBar() {
|
||||
appStore.toggleSideBar()
|
||||
appStore.toggleSideBar();
|
||||
}
|
||||
|
||||
function handleCommand(command) {
|
||||
@@ -83,24 +103,26 @@ function handleCommand(command) {
|
||||
}
|
||||
|
||||
function logout() {
|
||||
ElMessageBox.confirm('确定注销并退出系统吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
userStore.logOut().then(() => {
|
||||
location.href = '/index';
|
||||
ElMessageBox.confirm("确定注销并退出系统吗?", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
})
|
||||
.then(() => {
|
||||
userStore.logOut().then(() => {
|
||||
location.href = "/index";
|
||||
});
|
||||
})
|
||||
}).catch(() => { });
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
const emits = defineEmits(['setLayout'])
|
||||
const emits = defineEmits(["setLayout"]);
|
||||
function setLayout() {
|
||||
emits('setLayout');
|
||||
emits("setLayout");
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
|
@@ -145,19 +145,19 @@ export const dynamicRoutes = [
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/tool/gen-edit',
|
||||
path: '/web/comment-data',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['tool:gen:edit'],
|
||||
permissions: ['web:comment:list'],
|
||||
children: [
|
||||
{
|
||||
path: 'index/:tableId(\\d+)',
|
||||
component: () => import('@/views/tool/gen/editTable'),
|
||||
name: 'GenEdit',
|
||||
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
|
||||
path: 'index/:nid(\\d+)',
|
||||
component: () => import('@/views/web/comment/data'),
|
||||
name: 'CommentData',
|
||||
meta: { title: '评论数据', activeMenu: '/web/comment' }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
|
@@ -35,7 +35,8 @@ const useUserStore = defineStore(
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
const user = res.user
|
||||
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
|
||||
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : user.avatar;
|
||||
// const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
|
||||
|
||||
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
this.roles = res.roles
|
||||
|
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="24" :lg="8">
|
||||
<!-- <el-col :xs="24" :sm="24" :lg="8">
|
||||
<div class="chart-wrapper">
|
||||
<PieChart
|
||||
v-if="showPieChart"
|
||||
@@ -105,7 +105,7 @@
|
||||
:tagName="tagNameArray"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-col> -->
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
@@ -213,7 +213,7 @@ async function fetchData() {
|
||||
|
||||
const btnClick = (id) => {
|
||||
const routes = {
|
||||
1: "/system/log/webLoginInfo",
|
||||
1: "/loginlog/loginlog",
|
||||
2: "/member/member",
|
||||
3: "/message/comment",
|
||||
4: "/note/note",
|
||||
|
@@ -27,15 +27,17 @@
|
||||
type="primary"
|
||||
icon="Cloudy"
|
||||
plain
|
||||
@click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
|
||||
>访问码云</el-button
|
||||
@click="goTarget('https://gitee.com/Maverick_Ma/hongshu')"
|
||||
>
|
||||
访问码云
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="HomeFilled"
|
||||
plain
|
||||
@click="goTarget('http://ruoyi.vip')"
|
||||
>访问主页</el-button
|
||||
@click="goTarget('https://gitee.com/Maverick_Ma/hongshu')"
|
||||
>
|
||||
访问主页
|
||||
</el-button>
|
||||
</p>
|
||||
</el-col>
|
||||
|
||||
@@ -106,24 +108,6 @@
|
||||
</h3>
|
||||
</div>
|
||||
<blockquote class="text-warning" style="font-size: 16px">
|
||||
领取阿里云通用云产品1888优惠券
|
||||
<br />
|
||||
<el-link
|
||||
href="https://www.aliyun.com/minisite/goods?source=5176.11533457&userCode=ojvsntx1"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
>☛☛ 点我进入 ☚☚</el-link
|
||||
>
|
||||
<br />
|
||||
领取腾讯云通用云产品2860优惠券
|
||||
<br />
|
||||
<el-link
|
||||
href="https://curl.qcloud.com/efTJbNyi"
|
||||
type="primary"
|
||||
target="_blank"
|
||||
>☛☛ 点我进入 ☚☚</el-link
|
||||
>
|
||||
<br />
|
||||
阿里云服务器折扣区
|
||||
<br />
|
||||
<el-link
|
||||
@@ -151,7 +135,7 @@
|
||||
</el-col>
|
||||
|
||||
<!-- 捐赠支持 -->
|
||||
<el-col :xs="24" :sm="24" :md="12" :lg="8">
|
||||
<el-col :xs="24" :sm="24" :md="12" :lg="6">
|
||||
<el-card class="update-log">
|
||||
<template v-slot:header>
|
||||
<div class="clearfix">
|
||||
@@ -160,7 +144,7 @@
|
||||
</template>
|
||||
<div class="body">
|
||||
<img
|
||||
src="@/assets/images/reward.png"
|
||||
src="@/assets/images/pay.png"
|
||||
alt="donate"
|
||||
style="width: 92%"
|
||||
/>
|
||||
|
@@ -261,14 +261,11 @@ const { queryParams, form, rules } = toRefs(data);
|
||||
function subjectList() {
|
||||
getSubjectList(queryParams.value).then((response) => {
|
||||
tableData.value = response.rows;
|
||||
currentPage.value = 1;
|
||||
pageSize.value = 20;
|
||||
total.value = response.total;
|
||||
});
|
||||
}
|
||||
|
||||
function handleFind() {
|
||||
currentPage.value = 1;
|
||||
subjectList();
|
||||
}
|
||||
|
||||
@@ -296,8 +293,8 @@ function checkAll() {
|
||||
chooseTitle.value = "全选";
|
||||
} else {
|
||||
selectUids.value = [];
|
||||
tableData.value.forEach((picture) => {
|
||||
selectUids.value.push(picture.uid);
|
||||
tableData.value.forEach((album) => {
|
||||
selectUids.value.push(album.id);
|
||||
});
|
||||
isCheckedAll.value = true;
|
||||
chooseTitle.value = "取消全选";
|
||||
|
@@ -1,8 +1,86 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryRef"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
>
|
||||
<el-form-item label="评论人" prop="dictLabel">
|
||||
<el-input
|
||||
v-model="queryParams.dictLabel"
|
||||
placeholder="请输入评论人"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="评论内容" prop="dictLabel">
|
||||
<el-input
|
||||
v-model="queryParams.dictLabel"
|
||||
placeholder="请输入评论内容"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="评论时间" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
value-format="YYYY-MM-DD"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
>
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['system:dict:remove']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['system:dict:export']"
|
||||
>
|
||||
导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Close" @click="handleClose">
|
||||
关闭
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
@queryTable="getList"
|
||||
></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="commentList"
|
||||
:data="dataList"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
@@ -12,10 +90,16 @@
|
||||
<el-avatar :size="60" :src="scope.row.avatar"> </el-avatar>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="评论人" align="center" prop="uid" />
|
||||
<el-table-column label="被评论人" align="center" prop="noteUid" />
|
||||
<el-table-column label="评论人" align="center" prop="username" />
|
||||
<el-table-column label="被评论人" align="center" prop="pushUsername" />
|
||||
<el-table-column label="评论内容" align="center" prop="content" />
|
||||
<el-table-column label="评论等级" align="center" prop="level" />
|
||||
<el-table-column label="评论等级" align="center" prop="level">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getTagType(scope.row.level)">
|
||||
{{ getLevelText(scope.row.level) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="评论时间"
|
||||
align="center"
|
||||
@@ -26,23 +110,31 @@
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="操作"
|
||||
align="center"
|
||||
fixed="right"
|
||||
min-width="200"
|
||||
width="160"
|
||||
class-name="small-padding fixed-width"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="Delete"
|
||||
size="small"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['web:member:remove']"
|
||||
/>
|
||||
</el-tooltip>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
v-hasPermi="['system:dict:edit']"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
icon="Delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-hasPermi="['system:dict:remove']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -54,18 +146,136 @@
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="dataRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="字典类型">
|
||||
<el-input v-model="form.dictType" :disabled="true" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据标签" prop="dictLabel">
|
||||
<el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
|
||||
</el-form-item>
|
||||
<el-form-item label="数据键值" prop="dictValue">
|
||||
<el-input v-model="form.dictValue" placeholder="请输入数据键值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="样式属性" prop="cssClass">
|
||||
<el-input v-model="form.cssClass" placeholder="请输入样式属性" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="dictSort">
|
||||
<el-input-number
|
||||
v-model="form.dictSort"
|
||||
controls-position="right"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="回显样式" prop="listClass">
|
||||
<el-select v-model="form.listClass">
|
||||
<el-option
|
||||
v-for="item in listClassOptions"
|
||||
:key="item.value"
|
||||
:label="item.label + '(' + item.value + ')'"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="form.status">
|
||||
<el-radio
|
||||
v-for="dict in sys_normal_disable"
|
||||
:key="dict.value"
|
||||
:label="dict.value"
|
||||
>{{ dict.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="form.remark"
|
||||
type="textarea"
|
||||
placeholder="请输入内容"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="Comment">
|
||||
import { getCommentByNid, delComment } from "@/api/web/comment";
|
||||
<script setup name="Data">
|
||||
import useDictStore from "@/store/modules/dict";
|
||||
import {
|
||||
optionselect as getDictOptionselect,
|
||||
getType,
|
||||
} from "@/api/system/dict/type";
|
||||
import {
|
||||
listData,
|
||||
getData,
|
||||
delData,
|
||||
addData,
|
||||
updateData,
|
||||
} from "@/api/web/comment/data";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const dateRange = ref([]);
|
||||
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
|
||||
|
||||
const commentList = ref([]);
|
||||
const dataList = ref([]);
|
||||
const open = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
const defaultDictType = ref("");
|
||||
const typeOptions = ref([]);
|
||||
const route = useRoute();
|
||||
// 数据标签回显样式
|
||||
const listClassOptions = ref([
|
||||
{ value: "default", label: "默认" },
|
||||
{ value: "primary", label: "主要" },
|
||||
{ value: "success", label: "成功" },
|
||||
{ value: "info", label: "信息" },
|
||||
{ value: "warning", label: "警告" },
|
||||
{ value: "danger", label: "危险" },
|
||||
]);
|
||||
|
||||
const levelMap = {
|
||||
1: "一级评论",
|
||||
2: "二级评论",
|
||||
3: "三级评论",
|
||||
4: "四级评论",
|
||||
5: "五级评论",
|
||||
};
|
||||
// 根据 level 值返回对应的颜色
|
||||
const getTagType = (level) => {
|
||||
switch (level) {
|
||||
case 1:
|
||||
return "success"; // 一级评论,绿色
|
||||
case 2:
|
||||
return "primary"; // 二级评论,蓝色
|
||||
case 3:
|
||||
return "warning"; // 三级评论,黄色
|
||||
case 4:
|
||||
return "danger"; // 四级评论,红色
|
||||
case 5:
|
||||
return "info"; // 五级评论,蓝色(或者可以用其他颜色)
|
||||
default:
|
||||
return "default"; // 默认颜色
|
||||
}
|
||||
};
|
||||
|
||||
// 根据 level 返回对应的文本
|
||||
const getLevelText = (level) => {
|
||||
return levelMap[level] || "其他评论";
|
||||
};
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
@@ -76,34 +286,153 @@ const data = reactive({
|
||||
noteUid: undefined,
|
||||
content: undefined,
|
||||
},
|
||||
rules: {},
|
||||
rules: {
|
||||
dictLabel: [
|
||||
{ required: true, message: "数据标签不能为空", trigger: "blur" },
|
||||
],
|
||||
dictValue: [
|
||||
{ required: true, message: "数据键值不能为空", trigger: "blur" },
|
||||
],
|
||||
dictSort: [
|
||||
{ required: true, message: "数据顺序不能为空", trigger: "blur" },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询评论列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
getCommentByNid(queryParams.value).then((response) => {
|
||||
commentList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
/** 查询字典类型详细 */
|
||||
function getTypes(nid) {
|
||||
getType(nid).then((response) => {
|
||||
queryParams.value.dictType = response.data.dictType;
|
||||
defaultDictType.value = response.data.dictType;
|
||||
getList();
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询字典类型列表 */
|
||||
function getTypeList() {
|
||||
getDictOptionselect().then((response) => {
|
||||
typeOptions.value = response.data;
|
||||
});
|
||||
}
|
||||
/** 查询字典数据列表 */
|
||||
function getList(nid) {
|
||||
loading.value = true;
|
||||
queryParams.value.nid = nid;
|
||||
listData(proxy.addDateRange(queryParams.value, dateRange.value)).then(
|
||||
(response) => {
|
||||
dataList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
/** 取消按钮 */
|
||||
function cancel() {
|
||||
open.value = false;
|
||||
reset();
|
||||
}
|
||||
/** 表单重置 */
|
||||
function reset() {
|
||||
form.value = {
|
||||
dictCode: undefined,
|
||||
dictLabel: undefined,
|
||||
dictValue: undefined,
|
||||
cssClass: undefined,
|
||||
listClass: "default",
|
||||
dictSort: 0,
|
||||
status: "0",
|
||||
remark: undefined,
|
||||
};
|
||||
proxy.resetForm("dataRef");
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
/** 返回按钮操作 */
|
||||
function handleClose() {
|
||||
const obj = { path: "/message/comment" };
|
||||
proxy.$tab.closeOpenPage(obj);
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
proxy.resetForm("queryRef");
|
||||
queryParams.value.dictType = defaultDictType.value;
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset();
|
||||
open.value = true;
|
||||
title.value = "添加字典数据";
|
||||
form.value.dictType = queryParams.value.dictType;
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map((item) => item.dictCode);
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
const dictCode = row.dictCode || ids.value;
|
||||
getData(dictCode).then((response) => {
|
||||
form.value = response.data;
|
||||
open.value = true;
|
||||
title.value = "修改字典数据";
|
||||
});
|
||||
}
|
||||
/** 提交按钮 */
|
||||
function submitForm() {
|
||||
proxy.$refs["dataRef"].validate((valid) => {
|
||||
if (valid) {
|
||||
if (form.value.dictCode != undefined) {
|
||||
updateData(form.value).then((response) => {
|
||||
useDictStore().removeDict(queryParams.value.dictType);
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
} else {
|
||||
addData(form.value).then((response) => {
|
||||
useDictStore().removeDict(queryParams.value.dictType);
|
||||
proxy.$modal.msgSuccess("新增成功");
|
||||
open.value = false;
|
||||
getList();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const commentIds = row.id || ids.value;
|
||||
const dictCodes = row.dictCode || ids.value;
|
||||
proxy.$modal
|
||||
.confirm('是否确认删除评论编号为"' + commentIds + '"的数据项?')
|
||||
.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?')
|
||||
.then(function () {
|
||||
return delComment(commentIds);
|
||||
return delData(dictCodes);
|
||||
})
|
||||
.then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("删除成功");
|
||||
useDictStore().removeDict(queryParams.value.dictType);
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
getList();
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download(
|
||||
"system/dict/data/export",
|
||||
{
|
||||
...queryParams.value,
|
||||
},
|
||||
`dict_data_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
}
|
||||
|
||||
getList(route.params && route.params.nid);
|
||||
</script>
|
||||
|
@@ -54,11 +54,38 @@
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['web:comment:remove']"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="Download"
|
||||
@click="handleExport"
|
||||
v-hasPermi="['web:comment:export']"
|
||||
>
|
||||
导出
|
||||
</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList">
|
||||
</right-toolbar>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
@@ -68,34 +95,53 @@
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="序号" align="center" prop="id" />
|
||||
<el-table-column label="评论人" align="center" prop="username" />
|
||||
<el-table-column label="头像" align="center" prop="avatar">
|
||||
<template #default="scope">
|
||||
<el-avatar :size="60" :src="scope.row.avatar"> </el-avatar>
|
||||
<el-avatar :size="50" :src="scope.row.avatar"> </el-avatar>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="评论人" align="center" prop="username" />
|
||||
<el-table-column label="被评论人" align="center" prop="pushUsername" />
|
||||
<el-table-column label="被评论笔记" align="center" prop="title">
|
||||
<el-table-column label="被评论人" align="center" prop="replyUsername" />
|
||||
<el-table-column label="头像" align="center" prop="replyAvatar">
|
||||
<template #default="scope">
|
||||
<el-link
|
||||
type="primary"
|
||||
:underline="false"
|
||||
@click="handleDetail(scope.row)"
|
||||
>
|
||||
<el-tooltip
|
||||
class="item"
|
||||
effect="dark"
|
||||
:content="scope.row.title"
|
||||
placement="top"
|
||||
>
|
||||
<div class="table-cell">{{ scope.row.title }}</div>
|
||||
</el-tooltip>
|
||||
</el-link>
|
||||
<el-avatar :size="50" :src="scope.row.replyAvatar"> </el-avatar>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="笔记"
|
||||
width="120"
|
||||
align="center"
|
||||
:show-overflow-tooltip="true"
|
||||
>
|
||||
<template #default="scope">
|
||||
<router-link
|
||||
:to="'/web/comment-data/index/' + scope.row.nid"
|
||||
class="link-type"
|
||||
>
|
||||
<span>{{ scope.row.title }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="笔记封面" align="center" prop="noteCover">
|
||||
<template #default="scope">
|
||||
<el-avatar
|
||||
:size="60"
|
||||
:src="scope.row.noteCover"
|
||||
shape="square"
|
||||
@mouseover="showPreview(scope.row.noteCover, $event)"
|
||||
@mouseleave="hidePreview"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="笔记作者" align="center" prop="pushUsername" />
|
||||
<el-table-column label="评论内容" align="center" prop="content" />
|
||||
<el-table-column label="评论等级" align="center" prop="level" />
|
||||
<el-table-column label="评论等级" align="center" prop="level">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getTagType(scope.row.level)">
|
||||
{{ getLevelText(scope.row.level) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="评论时间"
|
||||
align="center"
|
||||
@@ -134,6 +180,11 @@
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 放大预览图片的容器 -->
|
||||
<div v-if="previewVisible" class="image-preview" :style="previewStyle">
|
||||
<img :src="previewSrc" alt="Preview" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -146,6 +197,9 @@ const router = useRouter();
|
||||
|
||||
const commentList = ref([]);
|
||||
const open = ref(false);
|
||||
const previewVisible = ref(false);
|
||||
const previewSrc = ref("");
|
||||
const previewStyle = reactive({ top: "0px", left: "0px" });
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
@@ -154,6 +208,36 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const dateRange = ref([]);
|
||||
|
||||
const levelMap = {
|
||||
1: "一级评论",
|
||||
2: "二级评论",
|
||||
3: "三级评论",
|
||||
4: "四级评论",
|
||||
5: "五级评论",
|
||||
};
|
||||
// 根据 level 值返回对应的颜色
|
||||
const getTagType = (level) => {
|
||||
switch (level) {
|
||||
case 1:
|
||||
return "success"; // 一级评论,绿色
|
||||
case 2:
|
||||
return "primary"; // 二级评论,蓝色
|
||||
case 3:
|
||||
return "warning"; // 三级评论,黄色
|
||||
case 4:
|
||||
return "danger"; // 四级评论,红色
|
||||
case 5:
|
||||
return "info"; // 五级评论,蓝色(或者可以用其他颜色)
|
||||
default:
|
||||
return "default"; // 默认颜色
|
||||
}
|
||||
};
|
||||
|
||||
// 根据 level 返回对应的文本
|
||||
const getLevelText = (level) => {
|
||||
return levelMap[level] || "其他评论";
|
||||
};
|
||||
|
||||
const data = reactive({
|
||||
form: {},
|
||||
queryParams: {
|
||||
@@ -168,6 +252,20 @@ const data = reactive({
|
||||
|
||||
const { queryParams, form } = toRefs(data);
|
||||
|
||||
/** 显示放大预览图片 */
|
||||
function showPreview(src, event) {
|
||||
previewSrc.value = src;
|
||||
previewVisible.value = true;
|
||||
previewStyle.top = event.clientY + 10 + "px";
|
||||
previewStyle.left = event.clientX + 10 + "px";
|
||||
}
|
||||
|
||||
/** 隐藏放大预览图片 */
|
||||
function hidePreview() {
|
||||
previewVisible.value = false;
|
||||
previewSrc.value = "";
|
||||
}
|
||||
|
||||
/** 查询评论列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
@@ -214,5 +312,33 @@ function handleDelete(row) {
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
/** 导出按钮操作 */
|
||||
function handleExport() {
|
||||
proxy.download(
|
||||
"system/post/export",
|
||||
{
|
||||
...queryParams.value,
|
||||
},
|
||||
`post_${new Date().getTime()}.xlsx`
|
||||
);
|
||||
}
|
||||
|
||||
getList();
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.image-preview {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff;
|
||||
padding: 5px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.image-preview img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -111,10 +111,8 @@
|
||||
>导出</el-button
|
||||
>
|
||||
</el-col>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
@queryTable="getList"
|
||||
></right-toolbar>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList">
|
||||
</right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
|
@@ -86,9 +86,9 @@
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -619,8 +619,8 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.image-preview img {
|
||||
max-width: 200px;
|
||||
max-height: 200px;
|
||||
max-width: 300px;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.image-uploader .el-upload {
|
||||
|
@@ -28,9 +28,9 @@
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">
|
||||
搜索
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
@@ -1,266 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form
|
||||
:model="queryParams"
|
||||
ref="queryRef"
|
||||
:inline="true"
|
||||
v-show="showSearch"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="登录地址" prop="ipaddr">
|
||||
<el-input
|
||||
v-model="queryParams.ipaddr"
|
||||
placeholder="请输入登录地址"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名称" prop="username">
|
||||
<el-input
|
||||
v-model="queryParams.username"
|
||||
placeholder="请输入用户名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select
|
||||
v-model="queryParams.status"
|
||||
placeholder="登录状态"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
>
|
||||
<el-option
|
||||
v-for="dict in sys_common_status"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="登录时间" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[
|
||||
new Date(2000, 1, 1, 0, 0, 0),
|
||||
new Date(2000, 1, 1, 23, 59, 59),
|
||||
]"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery"
|
||||
>搜索</el-button
|
||||
>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
v-hasPermi="['web:logininfor:remove']"
|
||||
>删除</el-button
|
||||
>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="Delete"
|
||||
@click="handleClean"
|
||||
v-hasPermi="['monitor:logininfor:remove']"
|
||||
>清空</el-button
|
||||
>
|
||||
</el-col>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
@queryTable="getList"
|
||||
></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table
|
||||
ref="loginInforRef"
|
||||
v-loading="loading"
|
||||
:data="loginInfoList"
|
||||
@selection-change="handleSelectionChange"
|
||||
:default-sort="defaultSort"
|
||||
@sort-change="handleSortChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="登录编号" align="center" prop="id" />
|
||||
<el-table-column
|
||||
label="用户名称"
|
||||
align="center"
|
||||
prop="username"
|
||||
:show-overflow-tooltip="true"
|
||||
sortable="custom"
|
||||
:sort-orders="['descending', 'ascending']"
|
||||
/>
|
||||
<el-table-column
|
||||
label="IP地址"
|
||||
align="center"
|
||||
prop="ipaddr"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="登录地点"
|
||||
align="center"
|
||||
prop="loginLocation"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="操作系统"
|
||||
align="center"
|
||||
prop="os"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="浏览器"
|
||||
align="center"
|
||||
prop="browser"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column label="登录状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_common_status" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="描述"
|
||||
align="center"
|
||||
prop="msg"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="访问时间"
|
||||
align="center"
|
||||
prop="loginTime"
|
||||
sortable="custom"
|
||||
:sort-orders="['descending', 'ascending']"
|
||||
width="180"
|
||||
>
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.loginTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="LoginInfo">
|
||||
import { list, delLoginInfo, cleanLoginInfo } from "@/api/web/loginInfor";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { sys_common_status } = proxy.useDict("sys_common_status");
|
||||
|
||||
const loginInfoList = ref([]);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const selectName = ref("");
|
||||
const total = ref(0);
|
||||
const dateRange = ref([]);
|
||||
const defaultSort = ref({ prop: "loginTime", order: "descending" });
|
||||
|
||||
// 查询参数
|
||||
const queryParams = ref({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
ipaddr: undefined,
|
||||
username: undefined,
|
||||
status: undefined,
|
||||
orderByColumn: undefined,
|
||||
isAsc: undefined,
|
||||
});
|
||||
|
||||
/** 查询登录日志列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
list(proxy.addDateRange(queryParams.value, dateRange.value)).then(
|
||||
(response) => {
|
||||
loginInfoList.value = response.rows;
|
||||
total.value = response.total;
|
||||
loading.value = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
function handleQuery() {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
/** 重置按钮操作 */
|
||||
function resetQuery() {
|
||||
dateRange.value = [];
|
||||
proxy.resetForm("queryRef");
|
||||
queryParams.value.pageNum = 1;
|
||||
proxy.$refs["loginInforRef"].sort(
|
||||
defaultSort.value.prop,
|
||||
defaultSort.value.order
|
||||
);
|
||||
}
|
||||
/** 多选框选中数据 */
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map((item) => item.id);
|
||||
multiple.value = !selection.length;
|
||||
single.value = selection.length != 1;
|
||||
selectName.value = selection.map((item) => item.userName);
|
||||
}
|
||||
/** 排序触发事件 */
|
||||
function handleSortChange(column, prop, order) {
|
||||
queryParams.value.orderByColumn = column.prop;
|
||||
queryParams.value.isAsc = column.order;
|
||||
getList();
|
||||
}
|
||||
/** 删除按钮操作 */
|
||||
function handleDelete(row) {
|
||||
const infoIds = row.id || ids.value;
|
||||
proxy.$modal
|
||||
.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?')
|
||||
.then(function () {
|
||||
return delLoginInfo(infoIds);
|
||||
})
|
||||
.then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("删除成功");
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
/** 清空按钮操作 */
|
||||
function handleClean() {
|
||||
proxy.$modal
|
||||
.confirm("是否确认清空所有登录日志数据项?")
|
||||
.then(function () {
|
||||
return cleanLoginInfo();
|
||||
})
|
||||
.then(() => {
|
||||
getList();
|
||||
proxy.$modal.msgSuccess("清空成功");
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
getList();
|
||||
</script>
|