diff --git a/pages/views/renliziyuan/renyuanxinxi/qttongji.vue b/pages/views/renliziyuan/renyuanxinxi/qttongji.vue index 51e4491..a465508 100644 --- a/pages/views/renliziyuan/renyuanxinxi/qttongji.vue +++ b/pages/views/renliziyuan/renyuanxinxi/qttongji.vue @@ -22,9 +22,9 @@ - - - + + + @@ -37,7 +37,7 @@ 姓名 - 性别 + 基层单位 年龄 @@ -62,7 +62,7 @@ - {{ item.xb_dictText }} + {{ item.jcxd }} @@ -85,6 +85,8 @@ import { ref, reactive, onMounted, computed } from 'vue'; import * as echarts from 'echarts'; import { cxcRyDatAstatistics, cxcRyDatAstatisticsDetails } from '@/api/renyuan.js'; +import { initDictOption } from '@/api/common.js'; + // 存储下方组件的高度 tableData const bottomHeight = ref(0); // 新增加载状态 @@ -93,17 +95,27 @@ const chartDataCount = ref(0); const fieldList = ref([ { text: '性别', - value: 'xb' + value: 'xb', + isDict: true, + dictCode: 'sex' }, { - text: '年龄', - value: 'nl' + text: '政治面貌', + value: 'zzmm', + isDict: true, + dictCode: 'zzmm' }, { - text: '学历', - value: 'rylb1' + text: '民族', + value: 'mz', + isDict: true, + dictCode: 'mz' } ]); // 字段列表 + +const dictCode = ref(''); +const fieldisDict = ref(true); + const selectedOrgCode = ref(''); // 当前选择的单位 orgCode const selectedOrgCodeLabel = ref('请选择单位'); // 当前选择的单位名称 const selectedField = ref(''); // 当前选择的字段 @@ -111,7 +123,8 @@ const selectedFieldLabel = ref('请选择字段'); // 当前选择的字段名 const orgCodeGroupData = ref([]); //按照orgcode进行分组的数据 含劳动合同号 const chartData = ref({}); // 图表数据 const personnelList = ref([]); // 人员列表 initChart -const fieldValues = ref([]); +const fieldValues = ref([]); //字段值 +const fieldTexts = ref([]); //字段值 const chartOption = ref({}); const chartTitle = computed(() => { @@ -165,56 +178,69 @@ const initChart = () => { }, 300); }; -// 更新图表 -const updateChart = (tempchartData) => { - // 初始化图表 - setTimeout(async () => { - if (!chart.value) return; - const myChart = await chart.value.init(echarts); - console.log(tempchartData); - let temp = JSON.parse(JSON.stringify(tempchartData[0].children)); - chartDataCount.value = temp.length; +const prevPage = () => { + if (currentPage.value > 1) { + currentPage.value--; + } + updateChart(chartData.value); +}; + +const nextPage = () => { + if (currentPage.value * pageSize.value < chartDataCount.value) { + currentPage.value++; // 计算当前页数据的起始和结束索引 const startIndex = (currentPage.value - 1) * pageSize.value; const endIndex = startIndex + pageSize.value; - // 截取当前页的数据 - const pageData = temp.slice(startIndex, endIndex); + updateChart(chartData.value); + // const tempChartData = temp.slice(startIndex, endIndex); + } +}; +// 更具数据生成图标的option +const getChartOption = (ChartData) => { + // let temp = JSON.parse(JSON.stringify(tempchartData[0].children)); + // chartDataCount.value = temp.length; + // 计算当前页数据的起始和结束索引 + const startIndex = (currentPage.value - 1) * pageSize.value; + const endIndex = startIndex + pageSize.value; + // 截取当前页的数据 + const tempChartData = ChartData.slice(startIndex, endIndex); + try { let xData = []; let seriesData = []; - // console.log(1, temp); + console.log(1, tempChartData); //当前机构下的数据 transformDataForEcharts - pageData.forEach((item) => { + let legendData = []; + for (let i = 0; i < fieldValues.value.length; i++) { + legendData.push(fieldValues.value[i].filedText); + } + + tempChartData.forEach((item) => { xData.push(item.name); }); for (let i = 0; i < fieldValues.value.length; i++) { let tempData = []; - pageData.forEach((item) => { + tempChartData.forEach((item) => { + console.log(item); if (item.data[i]) { tempData.push(item.data[i]); } else { tempData.push(0); } }); - seriesData.push({ name: fieldValues.value[i], type: 'bar', data: tempData }); + seriesData.push({ + name: fieldValues.value[i].filedText, + type: 'bar', + label: { + show: true, // 显示数值标签 + position: 'top' // 数值标签位置 + }, + data: tempData + }); } - - function prevPage() { - if (currentPage.value > 1) { - currentPage.value--; - updateChart(chartData.value); - } - } - function nextPage() { - if (currentPage.value * pageSize.value < chartDataCount) { - currentPage.value++; - updateChart(chartData.value); - } - } - - console.log(xData, seriesData, fieldValues.value); - myChart.setOption({ + console.log(2, legendData, xData, seriesData); + let tempOption = { title: { text: chartTitle.value, padding: [0, 0, 0, 30] @@ -280,7 +306,7 @@ const updateChart = (tempchartData) => { series: seriesData, legend: { - data: fieldValues.value, + data: legendData, itemGap: 5, padding: [0, 15, 0, 15], y: 'bottom', @@ -288,16 +314,32 @@ const updateChart = (tempchartData) => { itemWidth: 18, //宽 type: 'scroll' } - }); + }; + return tempOption; + } catch (error) { + console.log(error); + } +}; +// 更新图表 +const updateChart = (tempchartData) => { + // 初始化图表 + setTimeout(async () => { + if (!chart.value) return; + const myChart = await chart.value.init(echarts); + console.log(tempchartData); + let tempOption = getChartOption(tempchartData); + + myChart.setOption(tempOption); // 点击钻取事件 myChart.on('click', (params) => { console.log(params.name, params.seriesIndex, params.dataIndex); console.log(orgCodeGroupData.value); - let updateData = findRyByOrgCode(orgCodeGroupData.value.children, params.name); - // console.log(updateData); - const ldhth = updateData.fieldValues[params.dataIndex].ldhth; + let updateData = findRyByOrgCode(orgCodeGroupData.value.children, params.name); + console.log(updateData); + + const ldhth = updateData.fieldValues[params.seriesIndex].ldhth; console.log(ldhth); @@ -314,7 +356,7 @@ function findRyByOrgCode(treeData, targetOrgCode) { // console.log(treeData, targetOrgCode); for (const node of treeData) { // 如果当前节点匹配,直接返回该节点及其子节点 - if (node.orgCode === targetOrgCode) { + if (node.orgText === targetOrgCode) { return node; } // 递归检查子节点 @@ -349,21 +391,41 @@ function findNodeByOrgCode(treeData, targetOrgCode) { } //获取所有的fieldValue -function collectUniqueKeyValues(tree, key) { - const uniqueValues = new Set(); // 使用Set来自动处理唯一性 +function collectUniqueKeyFieldValues(tree) { + const uniqueMap = new Map(); + tree.forEach((item) => { + const { fieldValue, filedText } = item; + const key = `${fieldValue}-${filedText}`; - function traverse(node) { - if (node[key] !== undefined) { - uniqueValues.add(node[key]); + if (!uniqueMap.has(key)) { + uniqueMap.set(key, { + fieldValue, + filedText + }); } - if (node.children && Array.isArray(node.children)) { - node.children.forEach((child) => traverse(child)); + }); + + const result = Array.from(uniqueMap.values()); + return result; +} + +// 封装一个类来管理组织代码和组织名称的映射 +class OrgCodeMapper { + constructor(data) { + // 初始化一个空对象用于存储映射关系 + this.orgCodeToOrgTextMap = {}; + // 遍历传入的数据数组 + for (let i = 0; i < data.length; i++) { + const item = data[i]; + // 将 orgCode 作为键,orgText 作为值存入映射对象 + this.orgCodeToOrgTextMap[item.orgCode] = item.orgText; } } - tree.forEach((node) => traverse(node)); // 假设tree是一个数组 - - return Array.from(uniqueValues); // 将Set转换为数组 + // 查找指定 orgCode 对应的 orgText 的方法 + findOrgText(orgCode) { + return this.orgCodeToOrgTextMap[orgCode]; + } } // 示例用法 @@ -380,7 +442,10 @@ function collectUniqueKeyValues(tree, key) { function transformData(selectOrgCode, data) { const nodes = new Map(); //获取所有的fieldValue 用于图例和钻取和data[]中的数据顺序保持一致 动态建立fieldValue的数据 - fieldValues.value = collectUniqueKeyValues(data, 'fieldValue'); + fieldValues.value = collectUniqueKeyFieldValues(data); + // console.log(fieldValues.value); + const orgMapper = new OrgCodeMapper(data); //用于快速查找orgtext + // console.log(orgMapper.findOrgText('A01A01A01A01')); // 获取orgCode的所有层级 function getHierarchy(orgCode) { const hierarchy = []; @@ -400,25 +465,30 @@ function transformData(selectOrgCode, data) { // 创建所有节点并建立父子关系 data.forEach((entry) => { const hierarchy = getHierarchy(entry.orgCode); + // console.log(entry); hierarchy.forEach((code) => { + // console.log(code); + let tempOrgText = orgMapper.findOrgText(code) === undefined ? '' : orgMapper.findOrgText(code); + // console.log(tempOrgText); if (!nodes.has(code)) { nodes.set(code, { orgCode: code, + name: tempOrgText, type: 'bar', data: JSON.parse(JSON.stringify(tempArrayValue)), // 初始化data为[0, 0] 动态 children: [] }); } }); - + // console.log(nodes); // console.log('fieldValues', fieldValues.value, fieldValues.value.length, hierarchy); // 更新当前节点的data const node = nodes.get(entry.orgCode); - const fieldValue = parseInt(entry.fieldValue, 10); + const fieldValue = entry.fieldValue; for (let i = 0; i < fieldValues.value.length; i++) { - if (fieldValue === parseInt(fieldValues.value[i], 10)) { + if (fieldValue === fieldValues.value[i].fieldValue) { // console.log(555, i, fieldValue, fieldValues.value[i], entry.number); node.data[i] += entry.number; } @@ -463,18 +533,24 @@ function transformData(selectOrgCode, data) { // 递归计算每个根节点的data rootNodes.forEach((root) => computeData(root)); + return rootNodes; // console.log('rootNodes', rootNodes); - // 转换为目标格式 - function formatTree(node) { - return { - name: node.orgCode, - type: 'bar', - data: node.data, - children: node.children.map((child) => formatTree(child)) - }; - } + // // 转换为目标格式 + // function formatTree(node) { + // // console.log(node); + // return { + // orgCode: node.orgCode, + // name: node.name, + // type: 'bar', + // data: node.data, + // children: node.children.map((child) => formatTree(child)) + // }; + // } - return rootNodes.map((root) => formatTree(root)); + // return rootNodes.map((root) => { + // console.log(root); + // formatTree(root); + // }); } //----------------------------------------------------------------------------------------- @@ -483,36 +559,56 @@ function transformData(selectOrgCode, data) { const groupByOrgCode = (orgCode, data) => { // 过滤出本级和所有下级的数据 - const filteredData = data.filter((item) => item.orgCode.startsWith(orgCode)); + const filteredData = data.filter((item) => item.orgCode.startsWith(orgCode)); + const orgMapper = new OrgCodeMapper(data); // 如果过滤后的数据为空,返回 null if (filteredData.length === 0) { + uni.showToast({ + title: '过滤后数据为空', + duration: 1000 + }); return null; } - + // console.log(0, filteredData); // 按照 fieldValue 分组 const groupedByFieldValue = {}; - filteredData.forEach((item) => { - // console.log(item.orgCode, 11, groupedByFieldValue[item.fieldValue]); - if (!groupedByFieldValue[item.fieldValue]) { - groupedByFieldValue[item.fieldValue] = { - number: 0, - ldhth: [] - }; - } - // console.log(item.orgCode, 22, groupedByFieldValue[item.fieldValue]); - groupedByFieldValue[item.fieldValue].number += item.number; - groupedByFieldValue[item.fieldValue].ldhth.push(...item.ldhth.split(',')); - }); - + try { + filteredData.forEach((item) => { + // console.log(item); + if (!groupedByFieldValue[item.fieldValue]) { + groupedByFieldValue[item.fieldValue] = { + orgCode: item.orgCode, + orgText: item.orgText, + filedText: item.filedText, + number: 0, + ldhth: [] + }; + } + // console.log(item.orgCode, 22, groupedByFieldValue[item.fieldValue]); + groupedByFieldValue[item.fieldValue].number += item.number; + groupedByFieldValue[item.fieldValue].ldhth.push(...item.ldhth.split(',')); + }); + } catch (error) { + console.log(error); + } + console.log(1, orgMapper.findOrgText(orgCode)); // 构建本级结果 + const result = { orgCode: orgCode, - fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => ({ - fieldValue: fieldValue, - number: groupedByFieldValue[fieldValue].number, - ldhth: [...new Set(groupedByFieldValue[fieldValue].ldhth)] // 去重 - })), + orgText: orgMapper.findOrgText(orgCode), + fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => { + const { filedText, orgCode, orgText } = groupedByFieldValue[fieldValue] || {}; + return { + fieldValue: fieldValue, + filedText: filedText, + orgCode: orgCode, + orgText: orgText, + number: groupedByFieldValue[fieldValue].number, + ldhth: [...new Set(groupedByFieldValue[fieldValue].ldhth)] // 去重 + }; + }), children: [] }; @@ -520,38 +616,68 @@ const groupByOrgCode = (orgCode, data) => { // 获取所有下一级的 orgCode const nextLevelOrgCodes = new Set(); - filteredData.forEach((item) => { - if (item.orgCode !== orgCode && item.orgCode.startsWith(orgCode)) { - const nextLevelOrgCode = item.orgCode.substring(0, orgCode.length + 3); - nextLevelOrgCodes.add(nextLevelOrgCode); - } - }); - + try { + filteredData.forEach((item) => { + if (item.orgCode !== orgCode && item.orgCode.startsWith(orgCode)) { + const nextLevelOrgCode = item.orgCode.substring(0, orgCode.length + 3); + nextLevelOrgCodes.add(nextLevelOrgCode); + } + }); + } catch (error) { + console.log(error); + } // 递归处理下一级数据 - nextLevelOrgCodes.forEach((nextLevelOrgCode) => { - const child = groupByOrgCode(nextLevelOrgCode, data); - if (child) { - result.children.push(child); - } - }); + try { + nextLevelOrgCodes.forEach((nextLevelOrgCode) => { + const child = groupByOrgCode(nextLevelOrgCode, data); + if (child) { + result.children.push(child); + } + }); + } catch (error) { + console.log(error); + } // console.log('全部', result); return result; }; -// 获取统计数据 then +// 获取统计数据 then filter const fetchStatisticsData = async () => { if (!selectedOrgCode.value || !selectedField.value) return; + let res = []; + chartData.value = []; try { - const res = await cxcRyDatAstatistics({ + res = await cxcRyDatAstatistics({ orgCode: selectedOrgCode.value, - field: selectedField.value + field: selectedField.value, + dictCode: dictCode.value, + fieldisDict: fieldisDict.value }); // console.log(res); //deepseek - orgCodeGroupData.value = groupByOrgCode(selectedOrgCode.value, res); - chartData.value = transformData(selectedOrgCode.value, res); - // console.log(chartData.value); - updateChart(chartData.value); + if (res.success) { + // console.log(selectedOrgCode.value, res); + if (res.result.length < 1) { + uni.showToast({ + title: '查询数据为空' + }); + return; + } + //按单位进行分组 + orgCodeGroupData.value = groupByOrgCode(selectedOrgCode.value, res.result); + // console.log(orgCodeGroupData.value); + //将数据转换成echart格式 + const temp = transformData(selectedOrgCode.value, res.result); + + if (temp[0].children.length > 0) { + chartData.value = JSON.parse(JSON.stringify(temp[0].children)); + } else { + chartData.value = temp[0]; + } + chartDataCount.value = chartData.value.length; + // console.log(chartData.value); + updateChart(chartData.value); + } } catch (error) { console.error('获取统计数据失败:', error); } @@ -559,12 +685,15 @@ const fetchStatisticsData = async () => { // 获取人员列表 delimiter const fetchPersonnelList = async (ldhthList) => { + personnelList.value = []; try { const res = await cxcRyDatAstatisticsDetails({ ldhth: ldhthList }); console.log(res); - personnelList.value = res.data; + if (res.success) { + personnelList.value = res.result; + } } catch (error) { console.error('获取人员列表失败:', error); } @@ -573,24 +702,24 @@ const fetchPersonnelList = async (ldhthList) => { // 事件处理 const onOrgCodeChange = (e, data) => { selectedOrgCode.value = e; - console.log(data.value.title); + // console.log(data.value.title); selectedOrgCodeLabel.value = data.value.title; fetchStatisticsData(); }; const onFieldChange = (e) => { - console.log(e); + // console.log(e); try { selectedField.value = e; for (var index = 0; index < fieldList.value.length; index++) { var element = fieldList.value[index]; - console.log(element); + // console.log(element); if (element.value === e) { selectedFieldLabel.value = element.text; + dictCode.value = element.dictCode; + fieldisDict.value = element.isDict; } } - - console.log(selectedFieldLabel); fetchStatisticsData(); } catch (error) { //TODO handle the exception @@ -628,7 +757,7 @@ const onChartClick = (e) => { /* 图表容器 */ .chart-container { - height: 50vh; + height: 200px; margin: 20rpx 0; border-radius: 24rpx; overflow: hidden; @@ -638,47 +767,35 @@ const onChartClick = (e) => { } /* 表格标题行 */ + .titleStyle { - font-size: 28rpx; - font-weight: 600; - color: #ffffff; - background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end)); - padding: 28rpx 0; - border-radius: 16rpx 16rpx 0 0; - box-shadow: 0 4rpx 12rpx rgba(67, 100, 247, 0.2); - letter-spacing: 1rpx; + font-size: 12px; + color: #747474; + line-height: 30px; + height: 30px; + background: #f2f9fc; + text-align: center; + vertical-align: middle; + border-left: 1px solid #919191; + border-bottom: 1px solid #919191; } -/* 数据行 */ +/* 内容样式 */ .dataStyle { - font-size: 28rpx; - color: #3a466b; - padding: 32rpx 0; - background: #ffffff; - border-bottom: 2rpx solid #f0f6ff; - transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); -} - -.dataStyle:hover { - background: #f8fbff; - transform: translateY(-2rpx); -} - -/* 操作按钮 */ -button[type='primary'] { - background: linear-gradient(135deg, var(--primary-blue), var(--deep-blue)); - border: none; - border-radius: 12rpx; - padding: 12rpx 32rpx; - font-size: 26rpx; - box-shadow: 0 6rpx 16rpx rgba(64, 158, 255, 0.3); - transition: all 0.25s ease; -} - -button[type='primary']:active { - transform: scale(0.96); - box-shadow: 0 4rpx 8rpx rgba(64, 158, 255, 0.3); - background: linear-gradient(135deg, var(--deep-blue), var(--primary-blue)); + max-font-size: 14px; + /* 最大字体限制 */ + min-font-size: 10px; + /* 最小字体限制 */ + font-size: 12px; + color: #00007f; + line-height: 30px; + height: 30px; + font-weight: 500; + text-align: center; + vertical-align: middle; + border-bottom: 1px solid #919191; + border-left: 1px solid #919191; + text-overflow: ellipsis; } /* 滚动区域 */ @@ -700,6 +817,7 @@ scroll-view { opacity: 0; transform: translateY(20rpx); } + to { opacity: 1; transform: translateY(0); @@ -732,7 +850,7 @@ scroll-view { /* 响应式调整优化 */ @media (max-width: 768px) { .chart-container { - height: 55vh; + height: 200px; border-radius: 20rpx; } @@ -740,11 +858,6 @@ scroll-view { font-size: 26rpx; padding: 24rpx 0; } - - button[type='primary'] { - padding: 10rpx 24rpx; - font-size: 24rpx; - } } /* 数据行高亮效果 */