首页大型更新,修正通信ui

This commit is contained in:
2024-12-30 16:44:53 +08:00
parent a23c049c7d
commit 28e379aa2a
26 changed files with 929 additions and 399 deletions

View File

@@ -64,6 +64,14 @@ public class SysOaFinanceController extends BaseController {
return sysOaFinanceList;
}
@GetMapping("/pieData")
public R<List<SysOaFinanceVo>> pieData(SysOaFinanceBo bo) {
List<SysOaFinanceVo> sysOaFinanceList = iSysOaFinanceService.getPieData(bo);
return R.ok(sysOaFinanceList);
}
/**
* 根据时间查询
*/

View File

@@ -80,13 +80,21 @@ public class SysOaProjectController extends BaseController {
/**
* 获取项目管理详细信息
*
* @param projectId 主键
*/
@GetMapping("/projectDataByMonth")
public R<List<SysOaProjectVo>> getProjectDataByMonth() {
return R.ok(iSysOaProjectService.getProjectDataByMonth());
}
/**
* 获取项目管理详细信息
*
*/
@GetMapping("/projectDataByMonthAndDate")
public R<List<SysOaProjectVo>> getProjectDataByMonthAndDate() {
return R.ok(iSysOaProjectService.getProjectDataByMonthAndDate());
}
/**
* 新增项目管理

View File

@@ -96,6 +96,11 @@ public class SysOaFinance extends BaseEntity {
*/
private Long receiveAccountId;
/**
* 出账类型
*/
private String outType;
/**
* 一对多关联进出账明细
*/

View File

@@ -115,4 +115,10 @@ public class SysOaFinanceBo extends BaseEntity {
private List<SysOaDetail> detailList;
/**
* 出账类型
*/
private String outType;
}

View File

@@ -134,5 +134,15 @@ public class SysOaFinanceVo extends SysOaFinance {
*/
private List<SysOaDetail> detailList;
/**
* 出账类型
*/
private String outType;
/**
* 类型金钱综合用于饼图数据
*/
private Double outMoney;
}

View File

@@ -2,6 +2,8 @@ package com.ruoyi.oa.domain.vo;
import java.math.BigDecimal;
import java.util.Date;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
@@ -156,6 +158,7 @@ public class SysOaProjectVo {
* 创建时间
*/
@ExcelProperty(value = "创建时间")
@DateTimeFormat("yyyy-MM-dd")
private Date createTime;
/**

View File

@@ -64,6 +64,14 @@ public interface SysOaFinanceMapper extends BaseMapperPlus<SysOaFinanceMapper, S
*/
List<SysOaFinance> findFinanceByTime(Map params);
/**
* 获取饼图数据
* @param bo
* @return
*/
List<SysOaFinanceVo> getPieData(SysOaFinanceBo bo);
/**
* 项目资金管理,根据时间范围查询列表数据
* @param params

View File

@@ -28,5 +28,7 @@ public interface SysOaProjectMapper extends BaseMapperPlus<SysOaProjectMapper, S
List<SysOaProjectVo> getProjectDataByMonth(@Param("firstDay") Date firstDay, @Param("lastDay") Date lastDay);
List<SysOaProjectVo> getProjectDataByMonthAndDate(@Param("firstDay") Date firstDay, @Param("lastDay") Date lastDay);
}

View File

@@ -89,4 +89,6 @@ public interface ISysOaFinanceService {
* @return
*/
Boolean deleteSysOaFinanceById(Long financeId);
List<SysOaFinanceVo> getPieData(SysOaFinanceBo bo);
}

View File

@@ -58,4 +58,9 @@ public interface ISysOaProjectService {
List<SysOaProjectVo> getProjectDataByMonth();
/**
* 统计项目活跃度需要
* @return
*/
List<SysOaProjectVo> getProjectDataByMonthAndDate();
}

View File

@@ -262,6 +262,17 @@ public class SysOaFinanceServiceImpl implements ISysOaFinanceService {
return baseMapper.deleteById(financeId) > 0;
}
/**
* 获取饼图数据
* @param bo
* @return
*/
@Override
public List<SysOaFinanceVo> getPieData(SysOaFinanceBo bo) {
return baseMapper.getPieData(bo);
}
/**
* 批量删除进出账管理
*/

View File

@@ -140,6 +140,18 @@ public class SysOaProjectServiceImpl implements ISysOaProjectService {
return projectVos;
}
/**
* 统计数据需要
* @return
*/
@Override
public List<SysOaProjectVo> getProjectDataByMonthAndDate() {
Date date = new Date();
List<SysOaProjectVo> projectVos = baseMapper.getProjectDataByMonthAndDate(getFirstDay(date),getLastDay(date));
return projectVos;
}
private QueryWrapper<SysOaProject> buildOutWareQueryWrapper(SysOaOutWarehouseBo bo) {
QueryWrapper<SysOaProject> lqw = Wrappers.query();
lqw.like(StringUtils.isNotBlank(bo.getProjectName()), "sop.projec_name", bo.getProjectName());

View File

@@ -22,6 +22,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="outType" column="out_type"/>
<result property="outMoney" column="out_money"/>
<result property="receiveAccountId" column="receive_account_id"/>
<result property="receiveAccountName" column="receive_account_name"/>
<association property="project" column="project_id" javaType="SysOaProject" resultMap="SysOaProjectResult"/>
@@ -63,6 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.update_time,
b.detail_id,
b.detail_title,
a.out_type,
b.price,
b.big_price,
b.remark as detail_remark
@@ -93,6 +97,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
sof.create_time,
sof.update_by,
sof.update_time,
sof.out_type,
b.detail_id,
b.detail_title,
b.price,
@@ -127,6 +132,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
sof.create_time,
sof.update_by,
sof.update_time,
sof.out_type,
b.detail_id,
b.detail_title,
b.price,
@@ -145,7 +151,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!--进出账查询-->
<select id="selectFinanceByProjectId" resultMap="SysOaFinanceResult">
select a.finance_id, a.project_id, a.finance_title, a.finance_parties, a.pay_type, a.finance_type, a.finance_time, a.make_ratio, a.make_price, a.make_time, a.make_explain, a.accessory, a.remark as finance_remark, a.create_by, a.create_time, a.update_by, a.update_time,
b.detail_id, b.detail_title, b.price, b.big_price, b.remark as detail_remark
b.detail_id, b.detail_title, b.price, b.big_price, b.remark as detail_remark,a.out_type
from sys_oa_finance a
left join sys_oa_detail b on a.finance_id = b.finance_id
where a.project_id = #{projectId} and a.finance_type = #{financeType}
@@ -163,6 +169,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and date_format(a.finance_time,'%Y-%m-%d %H:%i:%s') &lt;= date_format(#{endTime},'%Y-%m-%d %H:%i:%s')
</select>
<select id="getPieData" resultMap="SysOaFinanceResult">
select
sum(b.price) as out_money,a.out_type
from sys_oa_finance a
left join sys_oa_detail b on a.finance_id = b.finance_id
where a.finance_type = '0' AND YEAR(a.create_time) = YEAR(NOW()) and a.project_id = '0'
group by a.out_type
</select>
<!--项目进出账查询-->
<!-- <select id="findFinanceByTimeAndProjectId" resultMap="SysOaFinanceResult">
<include refid="selectFinanceVo" />

View File

@@ -97,5 +97,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
group by sop.project_id
</select>
<select id="getProjectDataByMonthAndDate" resultType="com.ruoyi.oa.domain.vo.SysOaProjectVo">
select sum(soa.day_length+soa.hour/8) as labor_cost ,color,sop.project_name,date_format(soa.create_time,'%Y-%m-%d') as create_time from sys_oa_project sop
left join sys_oa_attendance soa on sop.project_id = soa.project_id
where soa.create_time between #{firstDay} and #{lastDay}
and soa.del_flag = '0'
group by sop.project_id,create_time
</select>
</mapper>

View File

@@ -56,9 +56,7 @@ public class SocketContactServiceImpl implements ISocketContactService {
SocketContactVo socketContactVo = baseMapper.selectVoById(id);
LambdaQueryWrapper<SocketMessage> socketMessageLambdaQueryWrapper = new LambdaQueryWrapper<>();
socketMessageLambdaQueryWrapper.eq(SocketMessage::getRoomId, socketContactVo.getRoomId())
.and(item ->
item.eq(SocketMessage::getContactId,id)
);
.eq(SocketMessage::getContactId, id);
Long userId = LoginHelper.getUserId();
socketContactVo.setUser(sysUserMapper.selectUserById(Objects.equals(socketContactVo.getContactUserId(), userId) ?socketContactVo.getUserId():socketContactVo.getContactUserId()));
List<SocketMessageVo> socketMessageVos = socketMessageMapper.selectVoList(socketMessageLambdaQueryWrapper);
@@ -68,6 +66,7 @@ public class SocketContactServiceImpl implements ISocketContactService {
item.setUser(sysUser);
}).collect(Collectors.toList());
socketContactVo.setMessages(socketMessageVos);
return socketContactVo;
}

View File

@@ -8,6 +8,14 @@ export function listFinance(query) {
params: query
})
}
// 查询进出账管理列表
export function pieData(query) {
return request({
url: '/oa/finance/pieData',
method: 'get',
params: query
})
}
// 查询进项目出账管理列表
export function listFinancePro(query) {

View File

@@ -23,6 +23,13 @@ export function projectData() {
method: 'get'
})
}
// 查询项目管理详细
export function projectDataByMonthAndDate() {
return request({
url: '/oa/project/projectDataByMonthAndDate',
method: 'get'
})
}
// 新增项目管理
export function addProject(data) {

View File

@@ -0,0 +1,86 @@
<template>
<div class="announcements">
<el-card>
<h2>公告</h2>
<el-skeleton v-if="loading" rows="3" animated />
<div v-else>
<div
class="announcement-item"
v-for="(announcement, index) in noticeList"
:key="index"
@click="openDrawer(announcement)"
style="cursor: pointer;"
>
<el-tooltip class="item" effect="dark" content="点击查看详情" placement="top">
<div style="display: flex;justify-content: space-between">
<span>{{ announcement.noticeTitle }}</span>
<span style="font-weight: 100;font-size: small">{{ announcement.createTime }}</span>
</div>
</el-tooltip>
</div>
</div>
</el-card>
<!-- </div>-->
<el-drawer
:title="selectNotice.noticeTitle"
:visible.sync="drawerVisible"
:with-header="true">
<div class="drawer-con">
<div style="font-size: small;font-weight: lighter">发布时间{{selectNotice.createTime}}</div>
<div v-html="selectNotice.noticeContent"></div>
</div>
</el-drawer>
</div>
</template>
<script>
import {listNoticeLimit} from "../../api/system/notice";
export default {
name: 'Announcements',
props: {
},
data() {
return {
noticeList: [], // 存储公告数据
loading: true, // 加载状态
drawerVisible: false, // 控制Drawer显示
selectNotice:{}
};
},
methods: {
fetchNotices() {
this.loading = true;
// 调用接口获取公告数据
listNoticeLimit()
.then((response) => {
this.noticeList = response; // 假设接口返回的数据是数组
this.loading = false;
})
},
openDrawer(announcement) {
// 打开Drawer并设置内容
this.selectNotice = announcement;
this.drawerVisible = true;
},
},
mounted() {
this.fetchNotices(); // 组件挂载后获取数据
},
};
</script>
<style scoped>
.drawer-con{
padding: 10px;
}
.announcement-item {
margin-bottom: 5px;
}
</style>

View File

@@ -0,0 +1,193 @@
<template>
<el-card>
<h2>财务分析</h2>
<div style="display: flex; justify-content: space-between;">
<!-- 月度收入与支出对比柱状图 -->
<div id="bar-chart" style="height: 400px;width: 50%;"></div>
<!-- 年度费用分类占比饼图 -->
<div id="pie-chart" style="height: 400px; width: 48%; margin-top: 20px;"></div>
</div>
<!-- 项目活跃度堆叠条形图 -->
<div id="activity-chart" style="width: 100%; height: 450px; margin-top: 20px;"></div>
</el-card>
</template>
<script>
import * as echarts from 'echarts';
import {findFinanceList, listFinance, pieData} from "../../api/oa/finance";
import {projectDataByMonthAndDate} from "../../api/oa/project";
import loadTinymce from "../../utils/loadTinymce";
export default {
name: 'FinancialCharts',
data() {
return {
// 示例数据:每个项目在不同日期的进度
activityData: [
{date: "2024-12-01", project: "项目A", progress: 5},
{date: "2024-12-01", project: "项目B", progress: 3},
{date: "2024-12-01", project: "项目C", progress: 2},
{date: "2024-12-02", project: "项目A", progress: 7},
{date: "2024-12-02", project: "项目B", progress: 4},
{date: "2024-12-02", project: "项目C", progress: 3},
{date: "2024-12-03", project: "项目A", progress: 6},
{date: "2024-12-03", project: "项目B", progress: 5},
{date: "2024-12-03", project: "项目C", progress: 3}
],
queryFinanceParams:{
pageNum: 1,
pageSize: 9999,
financeType: '0',
projectId:0
}
};
},
mounted() {
this.currentBlurList()
},
methods: {
/**
* 最近六个月核算情况如果显示更多月份请修改控制器int[] integers = {0,1, 2, 3, 4, 5};
*/
currentBlurList() {
findFinanceList().then(res => {
this.currentList = res.data.reverse();
pieData(this.queryFinanceParams).then(response => {
this.financeListOut =response.data;
this.initCharts();
})
})
// 获取活动图数据
projectDataByMonthAndDate().then(res => {
this.projects = res.data;
this.drawActivityChart(); // 绘制项目活跃度堆叠条形图
})
},
// 初始化财务图表
initCharts() {
const barChart = echarts.init(document.getElementById('bar-chart'));
const months = this.currentList.map(item => item.onMonth);
const financeCome = this.currentList.map(item => parseFloat(item.financeCome));
const financeOut = this.currentList.map(item => parseFloat(item.financeOut));
const barOption = {
title: {text: '月度收入与支出对比', left: 'center'},
tooltip: {trigger: 'axis'},
xAxis: {
type: 'category',
data: months,
axisLabel: {
rotate: 45 // 设置X轴标签为斜体显示
}
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value}',
rotate: 60 // 设置Y轴标签为斜体显示
}
},
series: [
{name: '收入', type: 'bar', data: financeCome, color: '#5470C6'},
{name: '支出', type: 'bar', data: financeOut, color: '#91CC75'},
],
};
barChart.setOption(barOption);
const pieChart = echarts.init(document.getElementById('pie-chart'));
// 提取后端返回的 `detailList` 数据
const detailList = this.financeListOut.map(item => ({
name: item.outType || '其他', // 使用 financeParties 作为分类名,默认 "其他"
value: parseFloat(item.outMoney) || 0, // 使用 financeTitle 或默认值 0
}));
const pieOption = {
title: {text: '年度费用分类占比', left: 'center'},
tooltip: {trigger: 'item', formatter: '{a} <br/>{b}: {c} ({d}%)'},
series: [
{
name: '费用分类',
type: 'pie',
radius: '50%',
data: detailList,
},
],
};
pieChart.setOption(pieOption);
},
// 绘制项目活跃度堆叠条形图
drawActivityChart() {
const chart = echarts.init(document.getElementById('activity-chart'));
console.log(this.projects)
// 处理数据:转化为堆叠条形图所需的格式
const dates = [...new Set(this.projects.map(item => item.createTime.substring(0 ,10)))]; // 获取所有日期
const projects = [...new Set(this.projects.map(item => item.projectName))]; // 获取所有项目
// 创建数据系列:每个项目一个系列
const series = projects.map(project => ({
name: project,
type: 'bar',
stack: 'total',
data: dates.map(date => {
const progress = this.projects.find(item => item.projectName === project && item.createTime.substring(0 ,10) === date.substring(0 ,10));
return progress ? progress.laborCost : 0;
})
}));
// 配置项
const option = {
title: {
text: '项目活跃度',
subtext: '显示每个项目的参与进度',
top:0,
},
grid: {
top: '20%', // 设置 grid 上部距离,确保有空间放置 title
bottom: '30%', // 保证底部有足够空间放置 legend
},
tooltip: {
trigger: 'axis',
axisPointer: {type: 'shadow'}
},
legend: {
align: 'left', // 对齐方式
itemWidth: 10, // 图例标记的宽度
itemHeight: 20, // 图例标记的高度
data: projects,
bottom:0
},
xAxis: {
type: 'category',
data: dates,
},
yAxis: {
type: 'value',
},
series: series
};
// 使用配置项
chart.setOption(option);
}
}
};
</script>
<style scoped>
#bar-chart, #pie-chart, #activity-chart {
width: 48%;
height: 400px;
}
</style>

View File

@@ -0,0 +1,67 @@
<template>
<el-card>
<div style="display: flex;justify-content: space-between">
<h2>最近出库记录</h2>
<el-button type="text" @click="goTarget('ware/oaOutWarehouse')">更多
<i class="el-icon-arrow-right"></i>
</el-button>
</div>
<el-skeleton v-if="loading" rows="3" animated />
<div v-else class="inventory-item" v-for="(item, index) in outWareHouseList" :key="index">
{{ item.createTime }}
<div>
项目{{item.projectName}}出库了
<strong>
{{ item.warehouseName }}
</strong>
</div>
</div>
</el-card>
</template>
<script>
import {listOaOutWarehouse} from "../../api/oa/oaOutWarehouse";
export default {
name: 'Inventory',
data() {
return {
queryParams:{
pageNum: 1,
pageSize: 3,
},
outWareHouseList:[],
loading: true
};
},
mounted() {
this.getList()
},
methods: {
/** 查询仓库出库列表 */
getList() {
this.loading = true;
listOaOutWarehouse(this.queryParams).then(res => {
this.outWareHouseList = res.rows
console.log(res.rows)
this.total = res.total
this.loading = false
})
},
goTarget(href) {
this.$router.push({ path: href});
},
}
};
</script>
<style scoped>
.inventory-item {
margin-bottom: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<el-card>
<div style="display: flex;justify-content: space-between">
<h2>
正在进行中的项目
</h2>
<el-button type="text" @click="goTarget('project/project')">更多
<i class="el-icon-arrow-right"></i>
</el-button>
</div>
<el-skeleton v-if="loading" rows="3" animated />
<div v-else class="project-item" v-for="(project, index) in projects" :key="index">
<strong>{{ project.projectName }}</strong>
<div>开始日期{{ project.beginTime }}</div>
<div> 负责人{{ project.functionary }}</div>
</div>
</el-card>
</template>
<script>
import {listProject} from "../../api/oa/project";
export default {
name: 'ProjectManagement',
data() {
return {
projects: [
],
queryParams: {
pageNum: 1,
pageSize: 4,
},
loading: true
};
},
mounted() {
this.getList()
},
methods: {
/** 查询项目管理列表 */
getList() {
this.loading = true;
listProject(this.queryParams).then(response => {
this.projects = response.rows;
this.total = response.total;
this.loading = false;
});
},
//路由跳转
goTarget(href) {
this.$router.push({ path: href});
},
}
};
</script>
<style scoped>
.project-item {
margin-bottom: 10px;
padding: 10px;
border-bottom: 1px solid #eee;
}
</style>

View File

@@ -0,0 +1,37 @@
<template>
<el-card>
<h2>快捷入口</h2>
<div class="shortcut" v-for="(item, index) in shortcuts" :key="index">
<el-button type="primary" :icon="item.icon" @click="goTarget(item.url)">{{ item.name }}</el-button>
</div>
</el-card>
</template>
<script>
export default {
name: 'QuickAccess',
data() {
return {
shortcuts: [
{ name: '人员考勤' ,url:'produce/attendance',icon:'el-icon-data-line'},
{ name: '日常财务' ,url:'finance/finance',icon:'el-icon-edit-outline'},
{ name: '出库管理' ,url:'ware/oaOutWarehouse',icon:'el-icon-document'},
]
};
},
methods: {
//路由跳转
goTarget(href) {
this.$router.push({ path: href});
console.log(999,href)
},
}
};
</script>
<style scoped>
.shortcut {
margin-bottom: 10px;
}
</style>

View File

@@ -0,0 +1,252 @@
<template>
<el-drawer
:visible.sync="drawerVisible"
size="50%"
title="聊天"
:before-close="handleClose"
>
<div class="chat-container">
<!-- 联系人列表 -->
<div class="contact-list">
<el-scrollbar>
<div
v-for="contact in contacts"
:key="contact.contactId"
class="contact-item"
@click="selectContact(contact)"
>
<el-avatar :src="contact.user.avatar"/>
<span>{{ contact.user.nickName }}</span>
</div>
</el-scrollbar>
</div>
<!-- 聊天内容区域 -->
<div class="chat-box">
<el-scrollbar style="height:80%" id="message_content_end">
<div class="messages" ref="messageBox" >
<div v-for="message in chatHistory" :key="message.id" class="message">
<span>{{ contactUser.nickName }}: </span>
<span>{{ message.content }}</span>
</div>
</div>
</el-scrollbar>
<!-- 消息输入框 -->
<div style="bottom:0;height:20%">
<el-input
v-model="newMessage"
placeholder="输入消息..."
suffix-icon="el-icon-chat-dot-round"
@keyup.enter="sendMessage"
/>
<el-button @click="sendMessage" icon="el-icon-paperclip">发送</el-button>
</div>
</div>
</div>
</el-drawer>
</template>
<script>
import {getContact, listContact} from "../../../api/system/contact";
import {parseTime} from "../../../utils/ruoyi";
import {addMessage} from "../../../api/system/message";
export default {
name: 'ChatComponent',
props:{
drawerVisible:Boolean,
},
data() {
return {
contacts: [], // 联系人列表
selectedContact: null, // 当前选中的联系人
chatHistory: [], // 当前聊天记录
newMessage: '', // 输入框中的消息
socket: null, // WebSocket实例
contactQueryParams: {
pageSize: 10,
pageNum: 1
},
contactUser:{}
};
},
methods: {
// 打开聊天窗口
openChat() {
console.log("窗口打开")
this.drawerVisible = true;
},
// 关闭聊天窗口
handleClose() {
this.drawerVisible = false;
},
// 选择联系人
selectContact(contact) {
this.selectedContact = contact;
this.chatHistory = []; // 清空当前聊天记录
console.log(contact);
this.loadMessage(contact.id);
},
getContactList() {
this.contactListLoading = true;
this.contactQueryParams.userId = this.userId;
listContact(this.contactQueryParams).then(response => {
if (response.code === 200) {
this.contacts = response.rows;
this.contactListTotal = response.total;
const contactUserId = this.$route.query.userId;
if (contactUserId) {
this.contactUserId = contactUserId;
let contact = response.rows.find(row => row.contactUserId === contactUserId);
this.loadMessage(contact.id);
}
}
this.contactListLoading = false;
})
},
contactLoadMore() {
// this.contactQueryParams.pageSize = 5;
// this.contactQueryParams.pageNum++;
this.getContactList();
},
loadMessage(concatId) {
this.msgListLoading = true;
getContact(concatId).then(response => {
if (response.code === 200) {
console.log(response.data)
this.currentContact = response.data;
this.contactUser = response.data.user;
this.chatHistory = response.data.messages;
}
this.msgListLoading = false;
this.fleshScroll();
})
},
insertEmoji(emoji) {
this.inputVal += emoji.data;
},
sendMessage() {
const message = {
contactId: this.currentContact.id,
userId: this.userId,
content: this.inputVal,
roomId: this.currentContact.roomId
}
this.msgList.push({
...message,
id: this.msgList.length + 1,
createTime: parseTime(new Date())
})
this.fleshLastMsg();
addMessage(message)
const msg = {
sendUserId: this.userId,
sendUserName: this.$store.state.user.name,
userId: this.currentContact.contactUserId === this.userId ? this.currentContact.user.userId : this.currentContact.contactUserId,
type: "chat",
detail: this.inputVal
}
this.$webSocket.sendWebsocket(JSON.stringify(msg));
this.inputVal = '';
this.fleshScroll();
},
subscribeMessage(res) {
if (res) {
const {sendUserId, sendUserName, userId, type, detail} = res.detail.data;
const message = {
id: 1,
contactId: this.currentContact.id,
userId: sendUserId,
content: detail,
roomId: this.currentContact.roomId,
createTime: parseTime(new Date()),
user: this.contactUser
}
this.msgList.push(message);
this.fleshLastMsg();
this.fleshScroll();
}
},
fleshLastMsg() {
const index = this.contactList.findIndex(e => e.id === this.currentContact.id);
this.contactList[index].endMsg = this.msgList[this.msgList.length - 1].content;
},
fleshScroll() {
this.$nextTick(() => {
document.getElementById("message_content_end").scrollIntoView();
})
}
},
created() {
this.userId = this.$store.state.user.id;
this.subscribeMessage();
this.getContactList();
},
mounted() {
window.addEventListener("onmessageWS", this.subscribeMessage);
}
,
}
;
</script>
<style scoped>
.chat-container {
display: flex;
height: 100%;
}
.contact-list {
width:40%;
background: #f4f4f4;
padding: 10px;
border-right: 1px solid #ddd;
}
.contact-item {
display: flex;
align-items: center;
padding: 10px;
cursor: pointer;
}
.contact-item:hover {
background: #e0e0e0;
}
.chat-box {
display: flex;
width: 55%;
height: 100%;
flex-direction: column;
padding: 10px;
}
.messages {
overflow-y: auto;
margin-bottom: 10px;
}
.message {
margin-bottom: 10px;
}
.el-input {
margin-top: 10px;
}
</style>

View File

@@ -14,8 +14,8 @@
<div style="position: absolute;top: 0;right: 300px;font-weight: 200">
<!-- <i style="position: relative;top: -7px;font-size: small;right: -20px;background-color: red;border-radius: 50%;color: white;width: 50px">99</i>-->
<i class="el-icon-s-comment" @click="chat = true" style=""></i>
<el-button class="el-icon-s-comment" @click="chat=true" style="">打开聊天</el-button>
<chat-component :drawerVisible="chat" ref="chatComponent"/>
</div>
<screenfull id="screenfull" class="right-menu-item hover-effect"/>
<el-tooltip content="用户" effect="dark" placement="bottom">
@@ -41,162 +41,6 @@
</el-dropdown-menu>
</el-dropdown>
</div>
<el-drawer
size="50%"
:visible.sync="chat"
:with-header="false">
<!-- 好友列表-->
<el-aside width="" style="background-color: white;display: flex;height: 90%">
<el-main :class="currentContact.id ? 'main' : 'main_empty'" v-loading="msgListLoading">
<div v-if="currentContact.id">
<el-row style="position: absolute;background: white;width: 50%;z-index: 999;height: 10%;top: 0;left: 10px">
<el-col :span="24" style="color: #666;position: relative;top: 25px">
<span style="font-weight: 500; font-size: 16px">{{ currentContact.user.nickName }}</span>
<el-divider direction="vertical"/>
</el-col>
</el-row>
<el-row style="height: 60%">
<el-col :span="24" class="msg_content" id="message_content">
<el-row v-for="(item, index) in msgList" :key="item.id" :style="index > 0 && 'margin-top: 30px'">
<div v-if="item.userId !== userId" style="">
<el-col :span="24" style="font-size: 16px;">
<div>{{ item.user.nickName }}:</div>
<div style="display: flex">
<div style="background-color: #f6f6f6;border-radius: 5px;padding: 0 12px 0 12px;">
{{ item.content }}
</div>
</div>
<div style="font-size: 11px; color: gray; margin-left: 5px">{{ item.createTime }}</div>
</el-col>
</div>
<div v-else>
<el-col :span="24" style="font-size: 16px;">
<div class="chat_bubble">
<span>{{ item.content }}</span>
</div>
<i class="el-icon-circle-check"
style="float: right; margin-right: 5px; color: lightgray; vertical-align: bottom; margin-top: 23px"></i>
<span
style="font-size: 11px; color: gray; margin-right: 5px; float: right; margin-top: 25px">{{ item.createTime }}</span>
</el-col>
</div>
</el-row>
<el-row id="message_content_end" style="height: 15px">
<el-col></el-col>
</el-row>
</el-col>
</el-row>
<el-row
style="position: absolute;background: white;width: 50%;z-index: 999;height: 20%;bottom: 15px;left: 10px">
<el-col :span="24">
<el-row>
<el-col :span="24">
<el-popover
placement="top-start"
trigger="click">
<div>
<VEmojiPicker :showSearch="false" @select="insertEmoji"/>
</div>
<img slot="reference" src="@/assets/images/emoji.png" title="表情" class="input_top_menu_img"/>
</el-popover>
</el-col>
</el-row>
<el-input type="textarea" :rows="3" v-model="inputVal"
style="font-size: 17px; color: black;position: relative;height: 20%"
@keyup.enter.native="send" placeholder="Enter 回车发送消息"/>
<el-button style="position: relative;left: 80%;top:10px" @click="send">发送</el-button>
</el-col>
</el-row>
</div>
<div v-else>
<el-row>
<el-col :span="24">
<img src="@/assets/images/message.png"/>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span style="color: gray">与您进行过沟通的联系人都会在左侧列表中显示</span>
</el-col>
</el-row>
</div>
</el-main>
<el-container>
<el-header>
<el-row>
<el-col :span="24">
<el-input suffix-icon="el-icon-search" placeholder="Enter 回车搜索联系人"
v-model="contactQueryParams.userName" @keyup.enter.native="getContactList"/>
</el-col>
</el-row>
<el-row style="margin-top: 15px">
<el-button size="mini">全部</el-button>
<el-button size="mini">个人</el-button>
<el-button size="mini">群聊</el-button>
</el-row>
</el-header>
<div v-loading="contactListLoading" style="margin-top: 10px">
<el-main v-if="contactList.length > 0" v-infinite-scroll="contactLoadMore" :infinite-scroll-distance="750"
:infinite-scroll-disabled="contactListTotal < 10" class="msgListMain">
<el-row class="msgUserList" v-for="(item, index) in contactList" :key="item.contactUserId"
:style="index > 0 && 'margin-top: 10px'" @click.native="loadMessage(item.id)">
<el-col :span="6">
<el-image
:src="(item.user.avatar === '' || item.user.avatar == null) ? require('@/assets/images/profile.jpg') : item.user.avatar"
fit="fill" style="width: 70%;border-radius: 50%;"/>
</el-col>
<el-col :span="18">
<el-row>
<el-col :span="15"><span style="font-weight: 500; font-size: 16px">{{ item.user.nickName }}</span>
</el-col>
<el-col :span="5">
<el-divider direction="vertical"/>
</el-col>
</el-row>
<el-row>
<el-col :span="5" style="font-size: 13px; text-overflow: ellipsis; white-space: nowrap">
<span><i class="el-icon-circle-check"></i> {{ item.endMsg }}</span>
</el-col>
<el-col :span="5" style="float: right">
<el-dropdown class="hover_down_menu">
<span class="el-dropdown-link">
<i class="el-icon-arrow-down el-icon-more"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>置顶</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-col>
</el-row>
</el-col>
</el-row>
</el-main>
<el-main v-else class="msgListMain_empty">
<el-row>
<el-col :span="24">
<img src="@/assets/images/contact.png" style="width: 80%; height: 80%"/>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<span style="color: gray">暂无联系人</span>
</el-col>
</el-row>
</el-main>
</div>
</el-container>
</el-aside>
</el-drawer>
</div>
</template>
@@ -214,9 +58,12 @@ import {getUserProfile} from "@/api/system/user";
import {getContact, listContact} from "../../api/system/contact";
import {addMessage} from "../../api/system/message";
import {parseTime} from "../../utils/ruoyi";
import ChatComponent from "./ChatComponent/index.vue";
import chatComponent from "./ChatComponent/index.vue";
export default {
components: {
ChatComponent,
Breadcrumb,
TopNav,
Hamburger,
@@ -227,6 +74,9 @@ export default {
RuoYiDoc
},
computed: {
chatComponent() {
return chatComponent
},
...mapGetters([
'sidebar',
'avatar',
@@ -274,7 +124,7 @@ export default {
pageNum: 1
},
currentContact: {},
contactUser:{}
contactUser: {}
};
},
mounted() {
@@ -388,7 +238,7 @@ export default {
content: detail,
roomId: this.currentContact.roomId,
createTime: parseTime(new Date()),
user:this.contactUser
user: this.contactUser
}
this.msgList.push(message);
this.fleshLastMsg();

View File

@@ -1,269 +1,112 @@
<template>
<div class="app-container home">
<div style="display: flex;flex-flow:wrap;">
<div style="display: flex;flex-flow:row wrap;margin-right: 15px">
<div @click="goTarget('project/project')" class="work">
<el-badge class="item-ico" type="warning">
<i class="el-icon-s-operation fz cl1"></i>
<div size="small">项目管理</div>
</el-badge>
</div>
<div @click="goTarget('produce/attendance')" class="work">
<!-- :value="ownCount" -->
<el-badge class="item-ico" type="warning">
<i class="el-icon-date fz cl2"></i>
<div size="small">人员考勤</div>
</el-badge>
</div>
<div @click="goTarget('notice/notice')" class="work">
<el-badge class="item-ico" type="warning">
<i class="el-icon-chat-line-round fz cl3"></i>
<div size="small">通知公告</div>
</el-badge>
</div>
<div class="home">
<el-container style="height: 100vh;">
<el-main>
<el-row :gutter="20">
<!-- 右侧展示区域 -->
<el-col :span="18" class="content-area">
<announcements />
<financial-charts />
</el-col>
<div @click="goTarget('finance/costing')" class="work">
<el-badge class="item-ico" type="warning" v-on:click="goTarget('finance/costing')">
<i class="el-icon-set-up fz cl4"></i>
<div size="small">财务管理</div>
</el-badge>
</div>
</div>
<el-card class="box-card" style="width: 250px">
<div slot="header" class="clearfix">
<span><i class="el-icon-microphone"></i> 通知公告</span>
<!-- <el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button>-->
</div>
<div v-for="(v, k) in noticeList" :key="k" class="text item" @click="toDrawer(v.noticeId)" type="primary" style="margin-left: 3px;margin-bottom: 5px;">
<span class="pull-right">{{ parseTime(v.createTime, '{y}-{m}-{d}') }}</span>
<i class="el-icon-arrow-right"></i>
{{v.noticeTitle}}
</div>
</el-card>
</div>
<!-- <div class="card-info" style="margin-top: 30px">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span><i class="el-icon-monitor"></i> 系统基本信息</span>
<el-button style="float: right; padding: 3px 0" type="text">操作按钮</el-button>
</div>
<div class="el-table el-table&#45;&#45;enable-row-hover el-table&#45;&#45;medium">
<table cellspacing="0" style="width: 100%">
<tbody>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">Redis版本</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">运行模式</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">端口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">客户端数</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">运行时间()</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用内存</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用CPU</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">内存配置</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
</tr>
<tr>
<td class="el-table__cell is-leaf"><div class="cell">AOF是否开启</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">RDB是否成功</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">Key数量</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
<td class="el-table__cell is-leaf"><div class="cell">网络入口/出口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</div>-->
<h2>新的一天从这里开始助力工作,让办公更轻松!!!</h2>
<el-drawer
:title="noticeTitle"
:visible.sync="drawer"
:with-header="true">
<div class="drawer-con">
<div v-html="noticeContent"></div>
</div>
</el-drawer>
<!-- 左侧功能区域 -->
<el-col :span="6" class="sidebar">
<quick-access />
<inventory />
<project-management />
</el-col>
</el-row>
</el-main>
</el-container>
</div>
</template>
<script>
import { getCache } from "@/api/monitor/cache";
import {getFinishedCount, getOwnCount, getTodoListCount} from "@/api/oa/homeCount";
import {getNotice, listNoticeLimit} from "@/api/system/notice";
import { getFinishedCount, getOwnCount, getTodoListCount } from "@/api/oa/homeCount";
import { getNotice, listNoticeLimit } from "@/api/system/notice";
import QuickAccess from "../components/QuickAccess/index.vue";
import Inventory from "../components/Inventory/index.vue";
import Announcements from "../components/Announcements/index.vue";
import ProjectManagement from "../components/ProjectManagement/index.vue";
import FinancialCharts from "../components/FinancialCharts/index.vue";
export default {
name: "Index",
components: {
FinancialCharts,
ProjectManagement,
Announcements,
Inventory,
QuickAccess,
},
data() {
return {
// 版本号
version: "0.8.3",
// 统计命令信息
commandstats: null,
// 使用内存
usedmemory: null,
// cache信息
cache: [],
finishedCount: 0,
todoListCount: 0,
ownCount: 0,
noticeList:[],
noticeList: [],
noticeTitle: '',
noticeContent : '',
//抽屉
noticeContent: '',
drawer: false,
};
},
created() {
this.getList();
this.getListNotice()
this.getListNotice();
},
methods: {
/** 查缓存询信息 */
getList() {
getCache().then((response) => {
this.cache = response.data;
this.$modal.closeLoading();
});
},
/** 查询公告列表 */
getListNotice() {
this.loading = true;
listNoticeLimit().then(response => {
listNoticeLimit().then((response) => {
this.noticeList = response;
this.loading = false;
});
},
toDrawer(nid){
this.drawer = true
getNotice(nid).then(res => {
toDrawer(nid) {
this.drawer = true;
getNotice(nid).then((res) => {
this.noticeTitle = res.data.noticeTitle;
this.noticeContent = res.data.noticeContent;
})
},
/** 修改按钮操作 */
/* handleUpdate(row) {
this.reset();
const noticeId = row.noticeId || this.ids
getNotice(noticeId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改公告";
});
},*/
toNotice(nid){
console.log(2222,nid)
},
//路由跳转
goTarget(href) {
this.$router.push({ path: href});
console.log(999,href)
this.$router.push({path: href});
},
},
};
</script>
<style scoped lang="scss">
.home {
background-color: #f5f5f5;
font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
color: #676a6c;
overflow-x: hidden;
/* 栅格列样式 */
.content-area {
background: #fff;
}
/* 左侧功能区域 */
.sidebar {
background: #f9f9f9;
}
.work {
background: #ffffff;
text-align: center;
}
.item-ico {
width: 100%;
height: 208px;
margin-top: 10px;
padding: 50px;
background-color: #ffffff;
font-size: 18px;
text-align: center;
color: #999999;
}
.item-ico .fz{font-size: 88px;margin-bottom: 12px;}
.item-ico .cl1{color: #67C23A}
.item-ico .cl2{color: #E6A23C}
.item-ico .cl3{color: #F56C6C}
.item-ico .cl4{color: #409EFF}
.box-card .el-card__header {
padding: 0;
border-bottom: 10px solid #EBEEF5;
box-sizing: border-box;
}
.clearfix{font-size: 18px;font-weight: 600;}
.text {
font-size: 16px;
border-bottom: #cccccc 1px dashed;
padding-bottom: 6px;
}
.item {
margin-bottom: 18px;
}
.item span{font-size: 12px;color: #cccccc}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.row-bg {
padding: 10px 0;
background-color: #f9fafc;
/* 响应式隐藏侧边栏 */
@media screen and (max-width: 768px) {
.sidebar {
display: none;
}
h2 {
margin-top: 30px;
font-size: 18px;
font-weight: 100;
.content-area {
width: 100% !important;
}
.drawer-con{padding:0 20px}
/* .card-info .item{
width: 100%;
height: 24px;
margin-top: 10px;
margin-right: 10px;
padding: 10px;
background-color: #ffffff;
font-size: 16px;
text-align: left;
color: #999999;
}*/
}
</style>

View File

@@ -300,7 +300,7 @@
<el-row :gutter="20">
<el-col :span="24">
<div class="tip-top">
<div style="display: flex;justify-content: space-between">
<div style="display: flex;justify-content: space-between">
<div style="display: flex;justify-content: center;align-items: center;white-space: nowrap">
<span> 日期检索</span>
<el-date-picker
@@ -425,10 +425,10 @@
<el-row :gutter="20">
<el-col :span="24">
<div class="tip-top">
<div style="display: flex;justify-content: space-between">
<div style="display: flex;justify-content: space-between">
<div style="display: flex;justify-content: center;align-items: center;white-space: nowrap">
<span> 支付类型</span>
<el-select v-model="payType" placeholder="请选择付款类型" @change = "getFinanceDateByPayType">
<el-select v-model="payType" placeholder="请选择付款类型" @change="getFinanceDateByPayType">
<el-option
v-for="dict in dict.type.sys_pay_type"
:key="dict.value"
@@ -585,7 +585,9 @@
<!--附件-->
<template v-if="form.accessory">
<el-tooltip class="item" effect="dark" content="点击下载" placement="bottom">
<el-link type="primary" @click="downloadFile(form.accessory)">{{form.accessory.match('[^/]+(?!.*/)')[0]}}</el-link>
<el-link type="primary" @click="downloadFile(form.accessory)">
{{ form.accessory.match('[^/]+(?!.*/)')[0] }}
</el-link>
</el-tooltip>
</template>
<template v-else>
@@ -629,14 +631,14 @@
<el-col :span="8">
<el-form-item label="账户" prop="receiveAccountId">
<el-select v-model="form.receiveAccountId" placeholder="请选择账户">
<el-option
v-for="item in receiveAccounts"
:key="item.receiveAccountId"
:label="item.receiveAccountName"
:value="item.receiveAccountId">
<span v-if="item.receiveAccountId===-1">无分类</span>
</el-option>
</el-select>
<el-option
v-for="item in receiveAccounts"
:key="item.receiveAccountId"
:label="item.receiveAccountName"
:value="item.receiveAccountId">
<span v-if="item.receiveAccountId===-1">无分类</span>
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -650,12 +652,25 @@
</el-form-item>
</el-col>
<el-col :span="16">
<el-col :span="type == 1 ? 16 : 8">
<el-form-item :label="type == 1 ? '付款方' : '经手人'" prop="financeParties">
<el-input v-model="form.financeParties" placeholder="请输入经手人/付款方"/>
</el-form-item>
</el-col>
<el-col v-if="type==0" :span="8">
<el-form-item label="出账类型" prop="outType">
<el-select v-model="form.outType" placeholder="请选择出账类型(默认其他)">
<el-option
v-for="dict in dict.type.oa_out_finance"
:key="dict.value"
:label="dict.label"
:value="dict.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="支付类型" prop="payType">
<el-select v-model="form.payType" placeholder="请选择支付类型">
@@ -770,11 +785,11 @@ import {numberToCNY} from "../../../utils/currencyFormatter";
export default {
name: "Finance",
dicts: ['sys_pay_type'],
dicts: ['sys_pay_type', 'oa_out_finance'],
data() {
return {
// 支付类型
payType:0,
payType: 0,
// 按钮loading
buttonLoading: false,
// 遮罩层
@@ -837,7 +852,7 @@ export default {
titleLink: "增长人数",
checkByTime: {},
monthCheck: {},
receiveAccounts:[],
receiveAccounts: [],
// monthOutByTime: 0,
// monthComeByTime: 0,
yearCheck: {},
@@ -897,7 +912,7 @@ export default {
},
methods: {
// 获取核算信息通过支付类型
getFinanceDateByPayType(){
getFinanceDateByPayType() {
this.getPayTypeBlur()
this.currentBlur()
this.currentBlurList()
@@ -978,7 +993,9 @@ export default {
projectId: 0, //项目id为0排除项目
financeTitle: this.queryParams.financeTitle,
financeParties: this.queryParams.financeParties,
receiveAccountId: this.queryParams.receiveAccountId
receiveAccountId: this.queryParams.receiveAccountId,
pageNum: this.queryParams.pageNum,
pageSize: this.queryParams.pageSize,
}
//使用实体里的参数属性,日期转为字符串格式
this.queryParams.params = {};
@@ -989,6 +1006,7 @@ export default {
listFinance(this.queryParams).then(response => {
console.log(response)
//出账列表
if (type == '0') {
this.financeListPro(response.rows).then(res => {
@@ -1018,7 +1036,7 @@ export default {
//tabs选项卡
handleClick(tab, event) {
this.nowTab = tab.index
this.payType=0
this.payType = 0
if (tab.index == '0') {
this.getListFinance('1');
}
@@ -1337,7 +1355,7 @@ export default {
})
},
getPayTypeBlur(){
getPayTypeBlur() {
let now = new Date()
var nowMonth = new Date(now.getFullYear(), now.getMonth(), 1); // 获取本月第一天的日期时间时间为0:0:0
var monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0, 23, 59, 59); // 获取本月最后一天的日期时间时间为23:59:59
@@ -1516,7 +1534,7 @@ export default {
}, `finance_${new Date().getTime()}.xlsx`)
},
/** 下载文件 */
downloadFile(filePath){
downloadFile(filePath) {
this.$download.resource(filePath)
}
@@ -1627,7 +1645,8 @@ export default {
font-size: 14px;
padding-right: 8px;
}
.node-label{
.node-label {
width: 130px;
overflow: hidden;
text-overflow: ellipsis;