feat: 对比分析功能前后端;优化部门数组件

This commit is contained in:
LokerL 2024-09-18 13:36:16 +08:00
parent 56e0b23e1e
commit 9f411c3b0c
9 changed files with 175 additions and 124 deletions

View File

@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -58,6 +59,16 @@ public class OilStatisticsController extends BaseController {
return getDataTable(result);
}
@GetMapping("/getAvgDsByDeptIdsAndDate")
public AjaxResult getAvgDsByDeptIdsAndDate(@RequestParam("ids") List<Long> ids, @RequestParam("startDate") String startDate, @RequestParam("endDate") String endDate) {
Map<Long, Object> resultMap = new HashMap<>();
for (Long id : ids) {
List<Map<String, Object>> result = thDeviceReportMonthService.selectAvgDsByDeptIdAndDate(id, startDate, endDate);
resultMap.put(id, result);
}
return success(resultMap);
}
@GetMapping("/getDeviceAvgByMonth")
public TableDataInfo getDeviceAvgByMonth(Long deptId, String startMonth, String endMonth, int pageNum, int pageSize) {

View File

@ -25,6 +25,9 @@ public interface ThDeviceReportMonthMapper {
* 更新
*/
int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth);
@MapKey("dept_id")
List<Map<String, Object>> selectAvgDsByDeptIdAndDate(@Param("deptId") Long deptId, @Param("startYear") int startYear, @Param("startMonth") int startMonth, @Param("endYear") int endYear, @Param("endMonth") int endMonth);
}

View File

@ -21,4 +21,6 @@ public interface ThDeviceReportMonthService {
* 更新
*/
int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth);
List<Map<String, Object>> selectAvgDsByDeptIdAndDate(Long deptId, String startTime, String endTime);
}

View File

@ -33,6 +33,17 @@ public class ThDeviceReportMonthServiceImpl implements ThDeviceReportMonthServic
public int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth) {
return thDeviceReportMonthMapper.updateThDeviceReportMonth(thDeviceReportMonth);
}
@Override
public List<Map<String, Object>> selectAvgDsByDeptIdAndDate(Long deptId, String startDate, String endDate) {
// startDate开始日期 2024-07 拆分出startYear和startMonth,并转为int
int startYear = Integer.parseInt(startDate.split("-")[0]);
int startMonth = Integer.parseInt(startDate.split("-")[1]);
// endDate结束日期 2024-08 拆分出endYear和endMonth
int endYear = Integer.parseInt(endDate.split("-")[0]);
int endMonth = Integer.parseInt(endDate.split("-")[1]);
return camelCaseMapListKey(thDeviceReportMonthMapper.selectAvgDsByDeptIdAndDate(deptId, startYear, startMonth, endYear, endMonth));
}
}

View File

@ -55,4 +55,23 @@
</set>
where id = #{id}
</update>
<select id="selectAvgDsByDeptIdAndDate" parameterType="map" resultType="java.util.Map">
SELECT TO_CHAR(TO_DATE(d.year || '-' || d.month, 'YYYY-MM'), 'YYYY-MM') AS month,
round(AVG(TO_NUMBER(d.avg_value)), 8) AS avg_value
FROM th_device_report_month1 d
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_NUMBER(d.year) * 100 + TO_NUMBER(d.month) &gt;= #{startYear} * 100 + #{startMonth}
AND TO_NUMBER(d.year) * 100 + TO_NUMBER(d.month) &lt;= #{endYear} * 100 + #{endMonth}
GROUP BY d.year, d.month
ORDER BY d.year, d.month
</select>
</mapper>

View File

@ -7,3 +7,11 @@ export function getAvgDsByMonth(params) {
method: 'get',
})
}
export function getAvgDsByDeptIdsAndDate(params) {
return request({
url: '/statistics/getAvgDsByDeptIdsAndDate',
params: params,
method: 'get',
})
}

View File

@ -9,26 +9,7 @@
</div>
</template>
<script>
import * as echarts from "echarts/core";
import {
GridComponent,
DataZoomComponent,
ToolboxComponent,
TooltipComponent,
} from "echarts/components";
import { LineChart } from "echarts/charts";
import { UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";
echarts.use([
ToolboxComponent,
TooltipComponent,
GridComponent,
LineChart,
CanvasRenderer,
UniversalTransition,
DataZoomComponent,
]);
import * as echarts from 'echarts';
export default {
props: {
@ -157,7 +138,7 @@ export default {
// 使
option = Object.assign(option, this.echartsData.option);
}
this.char.setOption(option);
this.char && this.char.setOption(option);
},
},
};

View File

@ -2,11 +2,16 @@
<div class="dept-tree">
<treeselect
v-model="deptId"
:multiple="false"
:multiple="multiple"
:show-count="true"
:flat="multiple"
:limitText="count => `及其它${count}项`"
:auto-deselect-descendants="false"
:auto-select-descendants="false"
:options="deptList"
:normalizer="normalizer"
placeholder="请选择组织部门"
@select="handleDeptSelect"
@input="handleInputChange"
/>
<el-button-group v-if="showQuickGroup">
<el-button v-for="child in firstChildList" :key="child.deptName" plain @click="quickSelect(child)">
@ -32,12 +37,21 @@ export default {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
sameLevel: {
type: Boolean,
default: false,
},
},
data() {
return {
deptId: "",
deptId: null,
//
deptList: [],
originDeptList: [],
firstChildList: [],
normalizer(node) {
return {
@ -52,24 +66,8 @@ export default {
this.initDeptList();
},
methods: {
// async initDeptList() {
// const [err, response] = await to(
// this.getConfigKey("sys.user.defaultFactoryId")
// );
// if (err) {
// console.error(err);
// this.$message.error(",sys.user.defaultFactoryId");
// return;
// }
// if (response.msg && /^[+-]?\d+(\.\d+)?$/.test(response.msg)) {
// this.defaultFactoryId = response.msg;
// await this.getOrganizeTree();
// } else {
// this.$message.error(",sys.user.defaultFactoryId");
// }
// },
quickSelect(child) {
this.deptId = child.deptId;
this.deptId = this.multiple ? [child.deptId] : child.deptId;
this.$emit("deptChange", child);
},
async initDeptList() {
@ -84,17 +82,28 @@ export default {
return;
}
if (response.code === 200) {
this.originDeptList = response.data;
this.deptList = this.handleTree(response.data, "deptId");
this.deptId = this.deptList[0].deptId;
this.firstChildList = this.deptList[0].children;
this.$emit("deptChange", this.deptList[0]);
const rootDept = this.deptList[0];
this.firstChildList = rootDept.children;
this.deptId = this.multiple ? this.firstChildList.map(item => item.deptId) : rootDept.deptId;
this.$emit("deptChange", this.multiple ? [rootDept] : rootDept);
} else {
console.error(response);
this.$message.error(response.msg);
}
},
handleDeptSelect(value) {
this.deptId = value.deptId;
handleInputChange(value) {
if (this.multiple) {
value = value.map((dept) => this.originDeptList.find((d) => d.deptId === dept));
if (this.sameLevel && value.length > 1) {
const lastChild = value[value.length - 1];
value = value.filter((dept) => dept.deptLevel === lastChild.deptLevel);
this.deptId = value.map((dept) => dept.deptId);
}
} else {
value = this.originDeptList.find((dept) => dept.deptId === value);
}
this.$emit("deptChange", value);
},
},

View File

@ -1,119 +1,126 @@
<template>
<div class="comparison-wrapper">
<el-row :gutter="10">
<el-col :span="4">
<dept-tree @deptChange="handleFirstDeptChange" />
</el-col>
<el-col :span="4">
<dept-tree @deptChange="handleSecondDeptChange" />
<el-row :gutter="10" align="center">
<el-col :span="6">
<dept-tree
@deptChange="handleDeptChange"
:multiple="true"
:sameLevel="true"
/>
</el-col>
<el-col :span="6">
<el-date-picker
v-model="dateRange"
type="monthrange"
v-model="dateTimeRange"
type="daterange"
format="yyyy-MM"
value-format="yyyy-MM"
range-separator="至"
start-placeholder="开始月份"
end-placeholder="结束月份">
start-placeholder="开始日期"
end-placeholder="结束日期"
@change="handleDateTimeChange"
>
</el-date-picker>
</el-col>
</el-row>
<el-row :gutter="10">
<span>{{ firstDept.deptName }} 月度读数均值</span>
<base-chart :echartsData="firstChartData" />
</el-row>
<el-row :gutter="10">
<span>{{ secondDept.deptName }} 月度读数均值</span>
<base-chart :echartsData="secondChartData" />
</el-row>
<el-row :gutter="10" class="chart-wrapper">
<base-chart :echartsData="chartData" :height="'80vh'" />
</el-row>
</div>
</template>
<script>
import BaseChart from '@/components/BaseChart/index.vue';
import DeptTree from '@/components/DeptTree/index.vue';
import { getAvgDsByMonth } from '@/api/statistics/comparison.js';
import to from '@/utils/await-to.js';
import { getAvgDsByDeptIdsAndDate } from "@/api/statistics/comparison.js";
import to from "@/utils/await-to.js";
import { debounce } from "@/utils";
import moment from "moment";
import BaseChart from "@/components/BaseChart/index.vue";
export default {
components: {
BaseChart,
DeptTree,
},
data() {
return {
firstDept: {},
secondDept: {},
firstChartData: {},
secondChartData: {},
dateRange: [],
deptIds: "",
deptList: [],
dateTimeRange: [],
chartData: {
id: "comparisonChart",
Xdata: [],
Ydata: [],
option: {},
series: {
data: [],
},
},
queryDebounce: null,
};
},
mounted() {
this.initDateRange();
const f = "YYYY-MM";
// , YYYY-MM
this.dateTimeRange = [
moment().startOf("year").format(f),
moment().format(f),
];
this.queryDebounce = debounce(this.query, 100);
},
methods: {
initDateRange() {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;
this.dateRange = [`${year}-01`, `${year}-${month}`];
handleDateTimeChange() {
this.queryDebounce();
},
async handleFirstDeptChange(dept) {
console.log(dept);
this.firstDept = dept;
const [err, response] = await to(this.query(dept.deptId));
if (err) {
console.error(err);
this.$message.error('查询失败');
handleDeptChange(value) {
this.deptList = value;
this.deptIds = value.map((item) => item.deptId);
this.queryDebounce();
},
async query() {
if (!this.dateTimeRange || this.dateTimeRange.length === 0) {
this.$message.error("请选择时间范围");
return;
}
this.firstChartData = response;
},
async handleSecondDeptChange(dept) {
this.secondDept = dept;
const [err, response] = await to(this.query(dept.deptId));
if (err) {
console.error(err);
this.$message.error('查询失败');
if (!this.deptIds || this.deptIds.length === 0) {
this.$message.error("请选择部门");
return;
}
this.secondChartData = response;
},
query(deptId) {
const [startMonth, endMonth] = this.dateRange;
return new Promise((resolve, reject) => {
getAvgDsByMonth({
deptId,
startMonth,
endMonth,
}).then((res) => {
if (res.code === 200) {
const Xdata = res.rows.map((item) => item.month);
const Ydata = res.rows.map((item) => item.avg_ds.toFixed(2));
resolve({ Xdata, Ydata });
} else {
reject(res);
}
});
});
},
const [err, res] = await to(
getAvgDsByDeptIdsAndDate({
ids: this.deptIds.join(","),
startDate: this.dateTimeRange[0],
endDate: this.dateTimeRange[1],
})
);
if (err) {
this.$message.error("查询失败");
return;
}
if (res.code !== 200 || res.data.length === 0) {
this.$message.error(res.msg);
return;
}
const { data } = res;
this.chartData.series.data = Object.keys(data).map((key) => {
return {
name: this.deptList.find((item) => item.deptId === parseInt(key))?.deptName,
type: "line",
data: data[key].map((item) => item.avgValue.toFixed(2)),
};
});
this.chartData.Xdata = data[Object.keys(data)[0]].map((item) => item.month);
},
},
};
</script>
<style scoped>
.comparison-wrapper {
padding: 20px;
height: 100%;
.el-row {
margin-bottom: 30px;
span {
font-size: 16px;
margin-left: 10px;
}
padding: 10px 20px;
.chart-wrapper {
margin-top: 20px;
}
}
</style>