| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- <template>
- <div class="total-detail-container">
- <!-- 标题和链接区域 -->
- <div class="item-header">
- <div class="title-section">
- <div class="item-title">整体</div>
- <div class="item-link report-link"
- @click="handleReportLinkClick">整体报表</div>
- </div>
- <div class="item-links">
- <div class="item-link"
- v-if="!role.includes('SecurityCheck') && !(role.includes('banzuzhang') && selectedRole == 'individual')"
- @click="handleLinkClick('/pages/capabilityComparison/index')">能力对比</div>
- </div>
- </div>
- <!-- 雷达图区域 -->
- <div class="chart-section">
- <div class="chart-container">
- <div id="radar-chart" class="radar-chart"></div>
- </div>
- </div>
- <!-- 数据展示区域 -->
- <div class="data-section">
- <div v-for="(item, index) in dataItems" :key="index" class="data-item">
- <div class="item-title">{{ item.title }}</div>
- <div class="data-content-section">
- <div class="data-content" v-for="ele in item.list">
- <div class="data-value">{{ ele.value }}</div>
- <div class="data-label">{{ ele.label }}</div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import * as echarts from 'echarts';
- export default {
- name: 'TotalDetail',
- data() {
- return {
- chart: null,
- dataItems: []
- }
- },
- props: {
- homePageWholeData: {
- type: Array,
- default: () => []
- },
- startDate: {
- type: String,
- default: ''
- },
- endDate: {
- type: String,
- default: ''
- },
- timeRange: {
- type: String,
- default: 'year'
- },
- selectedRole: {
- type: String,
- default: ''
- }
- },
- watch: {
- homePageWholeData: {
- handler(newValue) {
- this.updateData(newValue);
- },
- deep: true,
- immediated: true,
- }
- },
- computed: {
- role() {
- return this.$store?.state?.user?.roles
- },
- currentUser() {
- return this.$store.state.user;
- }
- },
- mounted() {
- // this.initChart();
- },
- beforeDestroy() {
- if (this.chart) {
- this.chart.dispose();
- }
- },
- methods: {
- updateData(newValue) {
- console.log(newValue, "newValue")
- this.dataItems = newValue.map(item => {
- return {
- title: item.name + "数据明细",
- list: [
- { label: '人均查获数量', value: item.seizureCount || 0 },
- { label: '人均在岗时长', value: item.workingHours || 0 },
- { label: '巡视检查合格率', value: `${((item.checkPassRate * 100) || 0).toFixed(2)}%` },
- { label: '抽问抽答正确率', value: `${((item.answersAccuracy * 100) || 0).toFixed(2)}%` },
- { label: '培训答题平均分', value: item.learningGrowthScore || 0 }
- ]
- }
- })
- // 同时更新雷达图数据
- this.updateChartWithData();
- },
- handleLinkClick(link) {
- if (link) {
- const roles = this.currentUser.roles;
- const userInfo = this.currentUser.userInfo;
- let obj = {};
- if (roles.includes('SecurityCheck')) {
- obj = {
- id: userInfo.userId,
- name: userInfo.nickName,
- type: 'USER'
- }
- }
- if (roles.includes('banzuzhang')) {
- obj = {
- id: userInfo.teamsId,
- name: userInfo.teamsName,
- type: 'DEPT'
- }
- }
- if (roles.includes('kezhang')) {
- obj = {
- id: userInfo.departmentId,
- name: userInfo.departmentName,
- type: 'DEPT'
- }
- }
- if (roles.includes('test') || roles.includes('zhijianke')) {
- obj = {
- id: userInfo.stationId,
- name: userInfo.stationName,
- type: 'DEPT'
- }
- }
- // 添加时间参数
- const timeParams = {
- startDate: this.startDate,
- endDate: this.endDate,
- timeRange: this.timeRange
- };
- // 合并所有参数
- const allParams = {
- ...obj,
- ...timeParams
- };
- // 构建带参数的URL
- let finalUrl = link;
- if (Object.keys(allParams).length > 0) {
- // 检查URL是否已有参数
- const separator = link.includes('?') ? '&' : '?';
- const queryString = Object.keys(allParams)
- .filter(key => allParams[key]) // 过滤掉空值
- .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(allParams[key])}`)
- .join('&');
- if (queryString) {
- finalUrl = `${link}${separator}${queryString}`;
- }
- }
- uni.navigateTo({
- url: finalUrl
- });
- }
- },
- updateChartWithData() {
- const chartDom = document.getElementById('radar-chart');
- if (!chartDom) {
- console.warn('雷达图容器未找到');
- return;
- }
- this.chart = echarts.init(chartDom);
- // 根据接口数据更新雷达图
- if (this.chart && this.homePageWholeData && this.homePageWholeData.length > 0) {
- // 使用Graph后缀的数据来显示雷达图
- const seriesData = this.homePageWholeData.map(item => ({
- name: item.name,
- value: [
- item.seizureCountGraph || 0,
- item.workingHoursGraph || 0,
- item.checkPassRateGraph || 0,
- item.answersAccuracyGraph || 0,
- item.learningGrowthScoreGraph || 0
- ]
- }));
- // 计算每个指标的最大值,用于雷达图的max值
- const indicators = [
- { name: '查获能力', max: Math.max(...seriesData.map(d => d.value[0])) },
- { name: '在岗时长', max: Math.max(...seriesData.map(d => d.value[1])) },
- { name: '巡视检查合格率', max: Math.max(...seriesData.map(d => d.value[2])) },
- { name: '抽问抽答', max: Math.max(...seriesData.map(d => d.value[3])) },
- { name: '培训答题', max: Math.max(...seriesData.map(d => d.value[4])) }
- ];
- const option = {
- legend: {
- type: 'scroll',
- orient: 'horizontal',
- bottom: 10,
- textStyle: {
- fontSize: 12,
- color: '#666'
- },
- itemWidth: 12,
- itemHeight: 12,
- data: seriesData.map(item => item.name)
- },
- radar: {
- shape: 'circle',
- indicator: indicators,
- splitNumber: 4,
- center: ['50%', '45%'],
- radius: '55%',
- axisName: {
- color: '#666',
- fontSize: 12
- },
- splitLine: {
- lineStyle: {
- color: ['#E6E6E6', '#E6E6E6', '#E6E6E6', '#E6E6E6']
- }
- },
- splitArea: {
- show: true,
- areaStyle: {
- color: ['#F8F8F8', '#FFFFFF']
- }
- },
- axisLine: {
- lineStyle: {
- color: '#E6E6E6'
- }
- }
- },
- series: [
- {
- name: '能力对比',
- type: 'radar',
- data: seriesData.map((item, index) => ({
- value: item.value,
- name: item.name,
- areaStyle: {
- color: this.getChartColor(index, 0.3)
- },
- lineStyle: {
- color: this.getChartColor(index),
- width: 2
- },
- itemStyle: {
- color: this.getChartColor(index)
- }
- }))
- }
- ],
- // 添加点击事件
- tooltip: {
- show: false
- },
- };
- this.chart.setOption(option);
- // 响应式调整
- window.addEventListener('resize', () => {
- this.chart.resize();
- });
- }
- },
- // 获取图表颜色
- getChartColor(index, opacity = 1) {
- const colors = ['#8FA5EC', '#FF9F7F', '#6ECEB2', '#FFD700', '#BA55D3'];
- const color = colors[index % colors.length];
- if (opacity < 1) {
- // 转换为RGBA格式
- const r = parseInt(color.slice(1, 3), 16);
- const g = parseInt(color.slice(3, 5), 16);
- const b = parseInt(color.slice(5, 7), 16);
- return `rgba(${r}, ${g}, ${b}, ${opacity})`;
- }
- return color;
- },
- // 处理雷达图点击事件
- handleRadarChartClick(params) {
- if (params.componentType === 'series' && params.seriesType === 'radar') {
- const clickedData = params.data;
- const seriesIndex = params.seriesIndex;
- const dataIndex = params.dataIndex;
- // 获取对应的数据项
- const dataItem = this.homePageWholeData[dataIndex];
- if (dataItem) {
- // 显示详细数据弹窗
- this.showRadarDataDetail(dataItem);
- }
- }
- },
- // 显示雷达图数据详情
- showRadarDataDetail(dataItem) {
- const labels = ['查获数量', '在岗时长', '巡视检查合格率', '抽问抽答', '培训答题'];
- const values = [
- dataItem.seizureCount || 0,
- dataItem.workingHours || 0,
- dataItem.checkPassRate || 0,
- dataItem.answersAccuracy || 0,
- dataItem.learningGrowthScore || 0
- ];
- let detailHtml = `<div style="font-size: 16px; font-weight: bold; margin-bottom: 12px; text-align: center;">${dataItem.name} - 详细数据</div>`;
- labels.forEach((label, index) => {
- detailHtml += `<div style="display: flex; justify-content: space-between; margin: 8px 0; padding: 4px 0; border-bottom: 1px solid #f0f0f0;">
- <span style="color: #666;">${label}:</span>
- <span style="font-weight: bold; color: #1890ff;">${values[index]}</span>
- </div>`;
- });
- uni.showModal({
- title: '详细数据',
- content: detailHtml,
- showCancel: false,
- confirmText: '关闭',
- confirmColor: '#1890ff'
- });
- },
- // 处理整体报表链接点击
- handleReportLinkClick() {
- // 根据时间范围自动计算开始和结束时间
- const { startDate, endDate } = this.calculateDateRange(this.timeRange);
-
- // 构建跳转参数
- const params = {
- startDate: startDate,
- endDate: endDate,
- };
- // 过滤掉空值
- const queryParams = Object.keys(params)
- .filter(key => params[key] && params[key] !== '')
- .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
- .join('&');
- // 构建跳转URL
- const url = queryParams ?
- `/pages/statisticalReport/index?${queryParams}` :
- '/pages/statisticalReport/index';
- uni.navigateTo({
- url: url
- });
- },
- // 根据时间范围计算开始和结束时间
- calculateDateRange(timeRange) {
- const today = new Date();
- const yesterday = new Date(today);
- yesterday.setDate(today.getDate() - 1);
- let startDate = new Date(yesterday);
- let endDate = new Date(yesterday);
- switch (timeRange) {
- case 'week':
- // 近一周:从7天前到昨天
- startDate.setDate(yesterday.getDate() - 6);
- break;
- case 'month':
- // 近一月:从30天前到昨天
- startDate.setDate(yesterday.getDate() - 29);
- break;
- case 'quarter':
- // 近三月:从90天前到昨天
- startDate.setDate(yesterday.getDate() - 89);
- break;
- case 'halfYear':
- // 近半年:从180天前到昨天
- startDate.setDate(yesterday.getDate() - 179);
- break;
- case 'year':
- // 近一年:从365天前到昨天
- startDate.setDate(yesterday.getDate() - 364);
- break;
- case 'custom':
- // 自定义时间:使用用户选择的日期
- if (this.startDate && this.endDate) {
- startDate = new Date(this.startDate);
- endDate = new Date(this.endDate);
- }
- break;
- default:
- // 默认近一年
- startDate.setDate(yesterday.getDate() - 364);
- }
- return {
- startDate: this.formatDateForInput(startDate),
- endDate: this.formatDateForInput(endDate)
- };
- },
- // 格式化日期为输入框格式
- formatDateForInput(date) {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, '0');
- const day = String(date.getDate()).padStart(2, '0');
- return `${year}-${month}-${day}`;
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .total-detail-container {
- background: #FFFFFF;
- border-radius: 20rpx;
- padding: 30rpx;
- margin-bottom: 30rpx;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
- }
- .item-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 25rpx;
- }
- .title-section {
- display: flex;
- align-items: center;
- gap: 20rpx;
- }
- .item-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333333;
- margin-bottom: 0;
- }
- .item-link {
- font-size: 26rpx;
- color: #1890FF;
- cursor: pointer;
- }
- .report-link {
- margin-left: 0;
- }
- .chart-section {
- margin-bottom: 30rpx;
- }
- .chart-container {
- width: 100%;
- height: 600rpx;
- margin-bottom: 20rpx;
- }
- .radar-chart {
- width: 100%;
- height: 100%;
- }
- .chart-legend {
- display: flex;
- justify-content: center;
- gap: 40rpx;
- }
- .legend-item {
- display: flex;
- align-items: center;
- gap: 10rpx;
- }
- .legend-color {
- width: 20rpx;
- height: 20rpx;
- border-radius: 4rpx;
- }
- .legend-text {
- font-size: 24rpx;
- color: #666;
- }
- .data-section {}
- .data-item {
- background: #EFF2FE;
- border-radius: 15rpx;
- padding: 20rpx;
- text-align: center;
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- margin-bottom: 30rpx;
- }
- .data-content-section {
- display: flex;
- }
- .data-content {
- flex: 1;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
- .data-value {
- font-size: 32rpx;
- font-weight: bold;
- color: #333333;
- margin-bottom: 8rpx;
- }
- .data-label {
- font-size: 24rpx;
- color: #666;
- }
- .rank-section {
- margin-top: 30rpx;
- }
- .rank-item {
- display: flex;
- align-items: center;
- margin-bottom: 10rpx;
- }
- .rank-label {
- width: 80rpx;
- font-size: 26rpx;
- color: #333;
- font-weight: 500;
- }
- .rank-progress {
- flex: 1;
- margin: 0 20rpx;
- }
- .rank-info {
- width: 100rpx;
- text-align: right;
- font-size: 26rpx;
- color: #666;
- }
- </style>
|