✨ feat: 对比分析功能前后端;优化部门数组件
This commit is contained in:
parent
56e0b23e1e
commit
9f411c3b0c
|
@ -19,6 +19,7 @@ import org.springframework.web.bind.annotation.*;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -58,6 +59,16 @@ public class OilStatisticsController extends BaseController {
|
||||||
return getDataTable(result);
|
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")
|
@GetMapping("/getDeviceAvgByMonth")
|
||||||
public TableDataInfo getDeviceAvgByMonth(Long deptId, String startMonth, String endMonth, int pageNum, int pageSize) {
|
public TableDataInfo getDeviceAvgByMonth(Long deptId, String startMonth, String endMonth, int pageNum, int pageSize) {
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ public interface ThDeviceReportMonthMapper {
|
||||||
* 更新
|
* 更新
|
||||||
*/
|
*/
|
||||||
int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,4 +21,6 @@ public interface ThDeviceReportMonthService {
|
||||||
* 更新
|
* 更新
|
||||||
*/
|
*/
|
||||||
int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth);
|
int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth);
|
||||||
|
|
||||||
|
List<Map<String, Object>> selectAvgDsByDeptIdAndDate(Long deptId, String startTime, String endTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,17 @@ public class ThDeviceReportMonthServiceImpl implements ThDeviceReportMonthServic
|
||||||
public int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth) {
|
public int updateThDeviceReportMonth(ThDeviceReportMonth thDeviceReportMonth) {
|
||||||
return thDeviceReportMonthMapper.updateThDeviceReportMonth(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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,4 +55,23 @@
|
||||||
</set>
|
</set>
|
||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</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) >= #{startYear} * 100 + #{startMonth}
|
||||||
|
AND TO_NUMBER(d.year) * 100 + TO_NUMBER(d.month) <= #{endYear} * 100 + #{endMonth}
|
||||||
|
|
||||||
|
GROUP BY d.year, d.month
|
||||||
|
ORDER BY d.year, d.month
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
@ -7,3 +7,11 @@ export function getAvgDsByMonth(params) {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAvgDsByDeptIdsAndDate(params) {
|
||||||
|
return request({
|
||||||
|
url: '/statistics/getAvgDsByDeptIdsAndDate',
|
||||||
|
params: params,
|
||||||
|
method: 'get',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -9,26 +9,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from "echarts/core";
|
import * as echarts from 'echarts';
|
||||||
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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -157,7 +138,7 @@ export default {
|
||||||
// 使用对象合并的方式让父组件可以对配置项可以单独设置
|
// 使用对象合并的方式让父组件可以对配置项可以单独设置
|
||||||
option = Object.assign(option, this.echartsData.option);
|
option = Object.assign(option, this.echartsData.option);
|
||||||
}
|
}
|
||||||
this.char.setOption(option);
|
this.char && this.char.setOption(option);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,11 +2,16 @@
|
||||||
<div class="dept-tree">
|
<div class="dept-tree">
|
||||||
<treeselect
|
<treeselect
|
||||||
v-model="deptId"
|
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"
|
:options="deptList"
|
||||||
:normalizer="normalizer"
|
:normalizer="normalizer"
|
||||||
placeholder="请选择组织部门"
|
placeholder="请选择组织部门"
|
||||||
@select="handleDeptSelect"
|
@input="handleInputChange"
|
||||||
/>
|
/>
|
||||||
<el-button-group v-if="showQuickGroup">
|
<el-button-group v-if="showQuickGroup">
|
||||||
<el-button v-for="child in firstChildList" :key="child.deptName" plain @click="quickSelect(child)">
|
<el-button v-for="child in firstChildList" :key="child.deptName" plain @click="quickSelect(child)">
|
||||||
|
@ -32,12 +37,21 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
sameLevel: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
deptId: "",
|
deptId: null,
|
||||||
// 部门树数据
|
// 部门树数据
|
||||||
deptList: [],
|
deptList: [],
|
||||||
|
originDeptList: [],
|
||||||
firstChildList: [],
|
firstChildList: [],
|
||||||
normalizer(node) {
|
normalizer(node) {
|
||||||
return {
|
return {
|
||||||
|
@ -52,24 +66,8 @@ export default {
|
||||||
this.initDeptList();
|
this.initDeptList();
|
||||||
},
|
},
|
||||||
methods: {
|
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) {
|
quickSelect(child) {
|
||||||
this.deptId = child.deptId;
|
this.deptId = this.multiple ? [child.deptId] : child.deptId;
|
||||||
this.$emit("deptChange", child);
|
this.$emit("deptChange", child);
|
||||||
},
|
},
|
||||||
async initDeptList() {
|
async initDeptList() {
|
||||||
|
@ -84,17 +82,28 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
|
this.originDeptList = response.data;
|
||||||
this.deptList = this.handleTree(response.data, "deptId");
|
this.deptList = this.handleTree(response.data, "deptId");
|
||||||
this.deptId = this.deptList[0].deptId;
|
const rootDept = this.deptList[0];
|
||||||
this.firstChildList = this.deptList[0].children;
|
this.firstChildList = rootDept.children;
|
||||||
this.$emit("deptChange", this.deptList[0]);
|
this.deptId = this.multiple ? this.firstChildList.map(item => item.deptId) : rootDept.deptId;
|
||||||
|
this.$emit("deptChange", this.multiple ? [rootDept] : rootDept);
|
||||||
} else {
|
} else {
|
||||||
console.error(response);
|
console.error(response);
|
||||||
this.$message.error(response.msg);
|
this.$message.error(response.msg);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleDeptSelect(value) {
|
handleInputChange(value) {
|
||||||
this.deptId = value.deptId;
|
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);
|
this.$emit("deptChange", value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,119 +1,126 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="comparison-wrapper">
|
<div class="comparison-wrapper">
|
||||||
<el-row :gutter="10">
|
<el-row :gutter="10" align="center">
|
||||||
<el-col :span="4">
|
<el-col :span="6">
|
||||||
<dept-tree @deptChange="handleFirstDeptChange" />
|
<dept-tree
|
||||||
</el-col>
|
@deptChange="handleDeptChange"
|
||||||
<el-col :span="4">
|
:multiple="true"
|
||||||
<dept-tree @deptChange="handleSecondDeptChange" />
|
:sameLevel="true"
|
||||||
|
/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="dateRange"
|
v-model="dateTimeRange"
|
||||||
type="monthrange"
|
type="daterange"
|
||||||
|
format="yyyy-MM"
|
||||||
|
value-format="yyyy-MM"
|
||||||
range-separator="至"
|
range-separator="至"
|
||||||
start-placeholder="开始月份"
|
start-placeholder="开始日期"
|
||||||
end-placeholder="结束月份">
|
end-placeholder="结束日期"
|
||||||
|
@change="handleDateTimeChange"
|
||||||
|
>
|
||||||
</el-date-picker>
|
</el-date-picker>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseChart from '@/components/BaseChart/index.vue';
|
import { getAvgDsByDeptIdsAndDate } from "@/api/statistics/comparison.js";
|
||||||
import DeptTree from '@/components/DeptTree/index.vue';
|
import to from "@/utils/await-to.js";
|
||||||
import { getAvgDsByMonth } from '@/api/statistics/comparison.js';
|
import { debounce } from "@/utils";
|
||||||
import to from '@/utils/await-to.js';
|
import moment from "moment";
|
||||||
|
import BaseChart from "@/components/BaseChart/index.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
BaseChart,
|
BaseChart,
|
||||||
DeptTree,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
firstDept: {},
|
deptIds: "",
|
||||||
secondDept: {},
|
deptList: [],
|
||||||
firstChartData: {},
|
dateTimeRange: [],
|
||||||
secondChartData: {},
|
chartData: {
|
||||||
dateRange: [],
|
id: "comparisonChart",
|
||||||
|
Xdata: [],
|
||||||
|
Ydata: [],
|
||||||
|
option: {},
|
||||||
|
series: {
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
queryDebounce: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
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: {
|
methods: {
|
||||||
initDateRange() {
|
handleDateTimeChange() {
|
||||||
const now = new Date();
|
this.queryDebounce();
|
||||||
const year = now.getFullYear();
|
|
||||||
const month = now.getMonth() + 1;
|
|
||||||
this.dateRange = [`${year}-01`, `${year}-${month}`];
|
|
||||||
},
|
},
|
||||||
async handleFirstDeptChange(dept) {
|
handleDeptChange(value) {
|
||||||
console.log(dept);
|
this.deptList = value;
|
||||||
this.firstDept = dept;
|
this.deptIds = value.map((item) => item.deptId);
|
||||||
const [err, response] = await to(this.query(dept.deptId));
|
this.queryDebounce();
|
||||||
if (err) {
|
},
|
||||||
console.error(err);
|
async query() {
|
||||||
this.$message.error('查询失败');
|
if (!this.dateTimeRange || this.dateTimeRange.length === 0) {
|
||||||
|
this.$message.error("请选择时间范围");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.firstChartData = response;
|
if (!this.deptIds || this.deptIds.length === 0) {
|
||||||
},
|
this.$message.error("请选择部门");
|
||||||
async handleSecondDeptChange(dept) {
|
|
||||||
this.secondDept = dept;
|
|
||||||
const [err, response] = await to(this.query(dept.deptId));
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
this.$message.error('查询失败');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.secondChartData = response;
|
const [err, res] = await to(
|
||||||
},
|
getAvgDsByDeptIdsAndDate({
|
||||||
query(deptId) {
|
ids: this.deptIds.join(","),
|
||||||
const [startMonth, endMonth] = this.dateRange;
|
startDate: this.dateTimeRange[0],
|
||||||
return new Promise((resolve, reject) => {
|
endDate: this.dateTimeRange[1],
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.comparison-wrapper {
|
.comparison-wrapper {
|
||||||
padding: 20px;
|
padding: 10px 20px;
|
||||||
height: 100%;
|
|
||||||
.el-row {
|
.chart-wrapper {
|
||||||
margin-bottom: 30px;
|
margin-top: 20px;
|
||||||
span {
|
|
||||||
font-size: 16px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue