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.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) {

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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));
}
} }

View File

@ -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) &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> </mapper>

View File

@ -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',
})
}

View File

@ -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);
}, },
}, },
}; };

View File

@ -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);
}, },
}, },

View File

@ -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>