# Conflicts:
#	RuoYi-Vue-Oracle/src/main/resources/application-druid.yml
#	RuoYi-Vue-Oracle/src/main/resources/application.yml
This commit is contained in:
gongjiale 2024-11-15 08:14:12 +08:00
commit ef02c7a2c0
13 changed files with 500 additions and 94 deletions

View File

@ -155,10 +155,27 @@ public class OilStatisticsController extends BaseController {
resultMap.put("preMonthDs", preMonthDs);
resultMap.put("lastYearDs", lastYearDs);
return success(resultMap);
}
}
@GetMapping("/monthData/dataDetailGangQuCompare")
public AjaxResult dataDetailGangQuCompare(Long deptId, String month) {
// 本月ds均值
List<Map<String, Object>> currentMonthDs = oilThDeviceReportService.monthReportDataOverviewGangQuCompare(deptId, month);
// 上月ds均值
List<Map<String, Object>> preMonthDs = oilThDeviceReportService.monthReportDataOverviewGangQuCompare(deptId, getPreviousMonth(month));
// 去年同月ds均值
List<Map<String, Object>> lastYearDs = oilThDeviceReportService.monthReportDataOverviewGangQuCompare(deptId, getLastYearMonth(month));
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("currentMonthDs", currentMonthDs);
resultMap.put("preMonthDs", preMonthDs);
resultMap.put("lastYearDs", lastYearDs);
return success(resultMap);
}
/**
* 获取去年同月
*
* @param month 2024-09
* @return 2023-09
*/

View File

@ -53,7 +53,7 @@ public class SysSendInfoController extends BaseController {
*/
@Log(title = "发送消息", businessType = BusinessType.UPDATE)
@GetMapping ("/sendMessage")
public AjaxResult sendMessage(SendMessageDTO sendMessageDTO) {
public AjaxResult sendMessage(SendMessageDTO sendMessageDTO) throws Exception {
return success(iSysNoticeService.sendMessage(sendMessageDTO));
}

View File

@ -65,6 +65,9 @@ public interface ThDeviceReportMapper {
@MapKey("month")
List<Map<String, Object>> monthReportDataOverviewDeviceDs(@Param("deptId") Long deptId, @Param("month") String month);
@MapKey("month")
List<Map<String, Object>> monthReportDataOverviewGangQuCompare(@Param("deptId") Long deptId, @Param("month") String month);
/**
* 每日数据
* @param day 日期 2024-08-30

View File

@ -8,6 +8,8 @@ public interface IOilThDeviceReportService {
List<Map<String, Object>> monthReportDataOverviewDeviceDs(Long deptId, String month);
List<Map<String, Object>> monthReportDataOverviewGangQuCompare(Long deptId, String month);
List<Map<String, Object>> dailyReportDataOverview(String day);
List<Map<String, Object>> selectAlarmCountByDeptIdAndDateRange(Long deptId, String beginDate, String endDate);

View File

@ -26,6 +26,11 @@ public class OilThDeviceReportService implements IOilThDeviceReportService {
return camelCaseMapListKey(thDeviceReportMapper.monthReportDataOverviewDeviceDs(deptId, month));
}
@Override
public List<Map<String, Object>> monthReportDataOverviewGangQuCompare(Long deptId, String month) {
return camelCaseMapListKey(thDeviceReportMapper.monthReportDataOverviewGangQuCompare(deptId, month));
}
@Override
public List<Map<String, Object>> dailyReportDataOverview(String day) {
return camelCaseMapListKey(thDeviceReportMapper.dailyReportDataOverview(day));

View File

@ -1,67 +1,64 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: oracle.jdbc.driver.OracleDriver
druid:
# 主库数据源
master:
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
# username: root
# password: password
# url: jdbc:oracle:thin:@10.169.28.44:1521/orcl
# username: spg_voc
# password: SPG$spgvoc_24!
url: jdbc:oracle:thin:@218.58.79.146:17521/orcl
username: system
password: oracle
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: oracle.jdbc.driver.OracleDriver
druid:
# 主库数据源
master:
# url: jdbc:oracle:thin:@127.0.0.1:1521/orcl
# username: root
# password: password
url: jdbc:oracle:thin:@10.169.28.44:1521/orcl
username: spg_voc
password: SPG$spgvoc_24!
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true

View File

@ -15,7 +15,7 @@ ruoyi:
# 本地文件上传
file:
domain:
# path: /home/file/upload
# path: /home/file/upload
path: D:/ruoyi/uploadPath
prefix: /statics
# 开发环境配置
@ -73,15 +73,15 @@ spring:
# redis 配置
redis:
# 地址
host: 192.168.31.105
# host: 127.0.0.1
# host: 192.168.31.105
host: 127.0.0.1
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
# password: 123456
password: admin123!
password: 123456
# password: admin123!
# 连接超时时间
timeout: 10s
lettuce:
@ -103,7 +103,7 @@ token:
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期默认30分钟
expireTime: 30
# MyBatis配置
mybatis:
# 搜索指定包别名
@ -114,7 +114,7 @@ mybatis:
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
pagehelper:
helperDialect: oracle
supportMethodsArguments: true
params: count=countSql
@ -134,7 +134,7 @@ xss:
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 代码生成
gen:
# 作者

View File

@ -145,6 +145,29 @@
ORDER BY pp.dept_name, p.dept_name
</select>
<select id="monthReportDataOverviewGangQuCompare" parameterType="map" resultType="map">
SELECT
pp.dept_name as "gang_qu",
ppp.dept_name as "gang_kou",
ROUND(AVG(TO_NUMBER(d.ds)), 8) AS avg_ds
FROM th_device_report d
LEFT JOIN th_device td ON d.sn = td.sn
LEFT JOIN sys_dept p ON td.dept_id = p.dept_id
LEFT JOIN sys_dept pp ON p.parent_id = pp.dept_id
LEFT JOIN sys_dept ppp ON pp.parent_id = ppp.dept_id
WHERE d.sn IN (SELECT d.sn
FROM th_device d
LEFT JOIN sys_dept p ON d.dept_id = p.dept_id
WHERE d.dept_id IN (SELECT dept_id
FROM sys_dept START WITH dept_id = #{deptId}
CONNECT BY PRIOR dept_id = parent_id))
AND TO_CHAR(d.report_time, 'YYYY-MM') = #{month}
GROUP BY pp.dept_name, ppp.dept_name
ORDER BY ppp.dept_name, pp.dept_name
</select>
<select id="dailyReportDataOverview" parameterType="map" resultType="map">
SELECT TO_CHAR(d.report_time, 'YYYY-MM-DD') AS day,
d.sn,

View File

@ -48,15 +48,16 @@
<select id="selectThDeviceReportYearList" parameterType="map" resultType="map">
select
m.sn,
m.dept_id,
m.year,
round(AVG(TO_NUMBER(m.avg_value)), 8) AS avg_value,
p.dept_name,
p.ancestors,
pp.dept_name as "gangqu"
p.dept_name as "p",
pp.dept_name as "pp",
ppp.dept_name as "ppp"
from th_device_report_month1 m
left join sys_dept p on m.dept_id = p.dept_id
left join sys_dept pp on p.parent_id = pp.dept_id
left join sys_dept ppp on pp.parent_id = ppp.dept_id
WHERE m.dept_id IN (
SELECT dept_id
FROM sys_dept START WITH dept_id = #{deptId}
@ -65,8 +66,8 @@
<if test="year != null and year != ''">
AND m.year = #{year}
</if>
GROUP BY m.sn, m.dept_id, m.year, p.dept_name, p.ancestors, pp.dept_name
ORDER BY m.dept_id, m.year ASC
GROUP BY m.sn, m.year, p.dept_name, pp.dept_name, ppp.dept_name
ORDER BY ppp.dept_name, pp.dept_name, p.dept_name
</select>
<update

View File

@ -31,3 +31,11 @@ export function getDataDetail(params) {
method: 'get',
})
}
export function dataDetailGangQuCompare(params) {
return request({
url: '/statistics/monthData/dataDetailGangQuCompare',
params: params,
method: 'get',
})
}

View File

@ -0,0 +1,246 @@
<template>
<div>
<el-row :gutter="10">
<el-col :span="6" style="margin-top: 10px; margin-bottom: 10px">
<dept-tree @deptChange="handleDeptChange" :showQuickGroup="true" />
</el-col>
<el-col :span="6" style="margin-top: 10px; margin-bottom: 10px">
<el-date-picker
v-model="dateValue"
type="month"
format="yyyy-MM"
value-format="yyyy-MM"
placeholder="选择月份"
@change="handleDateChange"
>
</el-date-picker>
</el-col>
<el-col :span="12">
<div class="export_btn">
<el-button
type="primary"
icon="eel-icon-download"
@click="exportToExcel"
>导出</el-button
>
</div>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="24">
<el-table :data="tableData" :header-cell-style="headerStyle" :loading="loading" @sort-change="sortChange">
<el-table-column
prop="gangKou"
label="港口"
align="center"
></el-table-column>
<el-table-column
prop="gangQu"
label="港区"
align="center"
></el-table-column>
<el-table-column
prop="currAvgDs"
label="本月均值"
sortable
align="center"
></el-table-column>
<el-table-column
prop="preMonthAvgDs"
label="上月均值"
sortable
align="center"
></el-table-column>
<el-table-column
prop="mom"
label="环比%"
sortable
:sortMethod="sortMomMethod"
align="center"
>
<template slot-scope="scope">
{{ scope.row.mom }}%
</template>
</el-table-column>
<el-table-column
prop="lastYearAvgDs"
label="去年同月均值"
sortable
align="center"
></el-table-column>
<el-table-column
prop="yoy"
label="同比%"
sortable
:sortMethod="sortYoyMethod"
align="center"
>
<template slot-scope="scope">
{{ scope.row.yoy }}%
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
</template>
<script>
import * as XLSX from "xlsx";
import { dataDetailGangQuCompare } from "@/api/statistics/monthData.js";
export default {
name: "DataCompare",
data() {
return {
deptId: "",
deptName: "",
dateValue: "",
tableData: [],
loading: false,
headerStyle: {
fontSize: "14px",
backgroundColor: "#f8f8f8",
color: "#333",
},
};
},
created() {
this.initDate();
},
methods: {
initDate() {
const date = new Date();
const year = date.getFullYear();
const month = date.getMonth() + 1;
const monthStr = month < 10 ? `0${month}` : month;
this.dateValue = `${year}-${monthStr}`;
},
handleDeptChange(value) {
this.deptId = value.deptId;
this.deptName = value.deptName;
this.queryData();
},
handleDateChange(value) {
this.queryData();
},
sortMomMethod(a, b) {
return parseFloat(a.mom) - parseFloat(b.mom);
},
sortYoyMethod(a, b) {
return parseFloat(a.yoy) - parseFloat(b.yoy);
},
sortChange({ prop, order }) {
if (order === "ascending") {
this.tableData.sort((a, b) => a[prop] - b[prop]);
} else {
this.tableData.sort((a, b) => b[prop] - a[prop]);
}
},
queryData() {
this.tableData = [];
this.loading = true;
dataDetailGangQuCompare({
deptId: this.deptId,
month: this.dateValue,
}).then((res) => {
if (res.code === 200) {
const { currentMonthDs, lastYearDs, preMonthDs } = res.data;
// const minLength = Math.min(currentMonthDs.length, lastYearDs.length, preMonthDs.length);
//
// const minLength = Math.min(currentMonthDs.length, lastYearDs.length, preMonthDs.length);
// dsds%ds%
// mom % = ( - ) / *100%
// yoy % = ( - ) / *100%
// -
for (let i = 0; i < currentMonthDs.length; i++) {
const dataItem = {};
const currentMonthDsItem = currentMonthDs[i];
dataItem.gangQu = currentMonthDsItem.gangQu;
dataItem.gangKou = currentMonthDsItem.gangKou;
dataItem.currAvgDs = currentMonthDsItem.avgDs;
const lastYearDsItem = lastYearDs.find(
(item) => item.gangQu === currentMonthDsItem.gangQu
);
if (lastYearDsItem) {
dataItem.lastYearAvgDs = lastYearDsItem.avgDs;
dataItem.yoy =
(
((currentMonthDsItem.avgDs - lastYearDsItem.avgDs) /
lastYearDsItem.avgDs) *
100
).toFixed(2);
} else {
dataItem.lastYearAvgDs = 0;
dataItem.yoy = 0;
}
const preMonthDsItem = preMonthDs.find(
(item) => item.gangQu === currentMonthDsItem.gangQu
);
if (preMonthDsItem) {
dataItem.preMonthAvgDs = preMonthDsItem.avgDs;
dataItem.mom =
(
((currentMonthDsItem.avgDs - preMonthDsItem.avgDs) /
preMonthDsItem.avgDs) *
100
).toFixed(2);
} else {
dataItem.preMonthAvgDs = 0;
dataItem.mom = 0;
}
this.tableData.push(dataItem);
}
}
}).finally(() => {
this.loading = false;
});
},
exportToExcel() {
// 簿
const wb = XLSX.utils.book_new();
const filename = `${this.deptName} ${this.dateValue.replace("-", "年") + "月"} 数据详情`;
// //
const ws_name = "SheetJS";
const ws_data = [
[filename],
["港口", "港区", "本月均值", "上月均值", "环比%", "去年同月均值", "同比%"],
...this.tableData.map((row) => [
row.gangKou,
row.gangQu,
row.currAvgDs,
row.preMonthAvgDs,
row.mom,
row.lastYearAvgDs,
row.yoy,
]),
];
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// // 8
if(!ws['!merges']) ws['!merges'] = [];
ws['!merges'].push({s: {r: 0, c: 0}, e: {r: 0, c: 7}});
// // 簿
XLSX.utils.book_append_sheet(wb, ws, ws_name);
XLSX.writeFile(wb, `${filename}.xlsx`);
},
},
};
</script>
<style scoped>
.table-title {
border: 1px solid #ebeef5;
display: flex;
justify-content: center;
align-items: center;
height: 45px;
span {
font-size: 18px;
color: #333;
}
}
.export_btn {
padding: 10px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@ -18,12 +18,14 @@
import CreateReport from "./create-report.vue";
import DataOverview from "./data-overview.vue";
import DataDetail from "./data-detail.vue";
import DataCompare from "./data-compare.vue";
export default {
name: "MonthData",
components: {
CreateReport,
DataOverview,
DataDetail,
DataCompare,
},
data() {
return {
@ -41,6 +43,10 @@ export default {
label: "数据详情",
cpn: "DataDetail",
},
{
label: "港区对比",
cpn: "DataCompare",
},
],
};
},

View File

@ -31,13 +31,45 @@
:data="tableData"
style="width: 100%"
border
:max-height="tableHeight"
:span-method="objectSpanMethod"
:row-class-name="tableRowClassName"
v-loading="loading"
>
<el-table-column prop="gangqu" label="归属港区" />
<el-table-column prop="deptName" label="归属企业" />
<el-table-column prop="ppp" label="归属港口">
<template slot-scope="{ row }">
<div>{{ row.ppp }}</div>
<div style="display: flex; gap: 10px">
<el-tag>港区数: {{ getChildCount(row, "ppp", "pp") }}</el-tag>
<el-tag type="warning"
>平均值: {{ calculateChildAvg(row, "ppp") }}</el-tag
>
</div>
</template>
</el-table-column>
<el-table-column prop="pp" label="归属港区">
<template slot-scope="{ row }">
<div>{{ row.pp }}</div>
<div style="display: flex; gap: 10px">
<el-tag>企业数: {{ getChildCount(row, "pp", "p") }}</el-tag>
<el-tag type="warning"
>平均值: {{ calculateChildAvg(row, "pp") }}</el-tag
>
</div>
</template>
</el-table-column>
<el-table-column prop="p" label="归属企业">
<template slot-scope="{ row }">
<div>{{ row.p }}</div>
<div style="display: flex; gap: 10px">
<el-tag>设备数: {{ getChildCount(row, "p", "sn") }}</el-tag>
<el-tag type="warning"
>平均值: {{ calculateChildAvg(row, "p") }}</el-tag
>
</div>
</template>
</el-table-column>
<el-table-column prop="sn" label="设备编码" />
<el-table-column prop="year" label="年份" />
<!-- <el-table-column prop="year" label="年份" /> -->
<el-table-column prop="avgValue" label="平均值">
<!-- <template slot-scope="scope">
<div @dblclick="changeAvgValue(scope.$index, scope.row)">
@ -59,7 +91,7 @@
</template> -->
</el-table-column>
</el-table>
<div class="page-ele">
<!-- <div class="page-ele">
<el-pagination
layout="sizes, prev, pager, next, total"
:total="total"
@ -69,7 +101,7 @@
@size-change="handleSizeChange"
>
</el-pagination>
</div>
</div> -->
</el-row>
</div>
</template>
@ -102,6 +134,9 @@ export default {
tableHeight() {
return window.innerHeight - 300;
},
pppList() {
return Array.from(new Set(this.tableData.map((item) => item.ppp)));
},
},
mounted() {
// 2024
@ -109,6 +144,68 @@ export default {
this.queryDebounce = debounce(this.query, 100);
},
methods: {
tableRowClassName({ row, rowIndex }) {
const classNames = ["default-row", "success-row", "error-row", "warning-row", "info-row"];
const index = this.pppList.findIndex((item) => item === row.ppp);
if (index === -1) return "info-row";
return index > classNames.length - 1 ? classNames[index % classNames.length] : classNames[index];
},
getChildCount(row, key, childKey) {
const childSet = new Set();
for (let i = 0; i < this.tableData.length; i++) {
if (row[key] === this.tableData[i][key]) {
childSet.add(this.tableData[i][childKey]);
}
}
return childSet.size;
},
calculateChildAvg(row, key) {
const childList = [];
for (let i = 0; i < this.tableData.length; i++) {
if (row[key] === this.tableData[i][key]) {
childList.push(this.tableData[i].avgValue);
}
}
// ,
return (childList.reduce((a, b) => a + b, 0) / childList.length).toFixed(
2
);
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
const calculateRowSpan = (key) => {
const value = row[key];
let rowSpan = 1;
if (rowIndex === 0) {
while (
this.tableData[rowIndex + rowSpan] &&
this.tableData[rowIndex + rowSpan][key] === value
) {
rowSpan++;
}
return { rowspan: rowSpan, colspan: 1 };
} else {
if (this.tableData[rowIndex - 1][key] === value) {
return { rowspan: 0, colspan: 0 };
} else {
while (
this.tableData[rowIndex + rowSpan] &&
this.tableData[rowIndex + rowSpan][key] === value
) {
rowSpan++;
}
return { rowspan: rowSpan, colspan: 1 };
}
}
};
if (columnIndex === 0) {
return calculateRowSpan("ppp");
} else if (columnIndex === 1) {
return calculateRowSpan("pp");
} else if (columnIndex === 2) {
return calculateRowSpan("p");
}
},
handleYearChange() {
this.queryDebounce();
},
@ -130,16 +227,16 @@ export default {
}
this.loading = true;
getDeviceReportYearList({
getDeviceReportYearListAll({
deptId: this.dept.deptId,
year: this.year,
pageNum: this.pageNum,
pageSize: this.pageSize,
// pageNum: this.pageNum,
// pageSize: this.pageSize,
})
.then((res) => {
if (res.code === 200) {
this.tableData = res.rows;
this.total = res.total;
this.tableData = res.data;
// this.total = res.total;
}
})
.finally(() => {
@ -161,10 +258,11 @@ export default {
dataToExcel({
data: [
[fileName],
["归属港区", "归属企业", "设备编码", "年份", "平均值"],
["归属港口", "归属港区", "归属企业", "设备编码", "年份", "平均值"],
...data.map((row) => [
row.gangqu,
row.deptName,
row.ppp,
row.pp,
row.p,
row.sn,
row.year,
row.avgValue,