diff --git a/.env.development b/.env.development
index e059f52..a0af6a8 100644
--- a/.env.development
+++ b/.env.development
@@ -1,4 +1,4 @@
# 开发环境
# 请求接口地址
VITE_REQUEST_BASE_URL = https://36.112.48.190
-#VITE_REQUEST_BASE_URL = http://10.75.15.247:8080
+#VITE_REQUEST_BASE_URL = http://10.75.15.247:8080
diff --git a/.env.production b/.env.production
index 9338f38..391c2dd 100644
--- a/.env.production
+++ b/.env.production
@@ -1,4 +1,4 @@
# 生产环境
# 请求接口地址
-#VITE_REQUEST_BASE_URL = https://36.112.48.190
-VITE_REQUEST_BASE_URL = http://10.75.15.247:8080
\ No newline at end of file
+VITE_REQUEST_BASE_URL = https://36.112.48.190
+#VITE_REQUEST_BASE_URL = http://10.75.15.247:8080
\ No newline at end of file
diff --git a/api/common.js b/api/common.js
new file mode 100644
index 0000000..ce4c8a5
--- /dev/null
+++ b/api/common.js
@@ -0,0 +1,16 @@
+import {
+ https
+} from '@/utils/http.js';
+/*
+这是后端系统通用的系统类的基础性的api路径,后续的大家分类建js存放
+*/
+
+
+
+export function initDictOption(dictCode) { // 获取部门所有人员信息
+ return https({
+ url: ' /sys/dict/getDictItems',
+ method: 'get',
+ data: dictCode
+ })
+}
\ No newline at end of file
diff --git a/pages/views/renliziyuan/renyuanxinxi/index.vue b/pages/views/renliziyuan/renyuanxinxi/index.vue
index 782e15d..e37c7e6 100644
--- a/pages/views/renliziyuan/renyuanxinxi/index.vue
+++ b/pages/views/renliziyuan/renyuanxinxi/index.vue
@@ -12,33 +12,31 @@
-
+
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/views/renliziyuan/renyuanxinxi/qttongji.vue b/pages/views/renliziyuan/renyuanxinxi/qttongji.vue
index 3afc3cd..4afc050 100644
--- a/pages/views/renliziyuan/renyuanxinxi/qttongji.vue
+++ b/pages/views/renliziyuan/renyuanxinxi/qttongji.vue
@@ -1,80 +1,75 @@
-
-
-
-
-
+
+
+
+
-
-
-
- 选择字段: {{ selectedFieldLabel }}
-
+
+
+
+
-
-
+
+
+
+
+
+
-
+
-
- 序号
-
+ 序号
-
- 姓名
-
+ 姓名
-
- 性别
-
+ 性别
-
- 年龄
-
+ 年龄
-
- 操作
-
+ 操作
-
-
-
+
+
+
- {{index+1}}
+ {{ index + 1 }}
- {{item.xm}}
+ {{ item.xm }}
-
+
+
- {{item.xb_dictText}}
+ {{ item.xb_dictText }}
-
+
+
- {{item.nl}}
+ {{ item.nl }}
@@ -92,71 +87,79 @@
import {
ref,
reactive,
- onMounted
+ 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);
// 新增加载状态
const chart = ref(null);
+ const chartDataCount = ref(0);
const fieldList = ref([{
- label: '性别',
- value: 'xb'
+ text: '性别',
+ value: 'xb',
+ isDict: true,
+ dictCode: 'sex'
},
{
- label: '年龄',
- value: 'nl'
+ text: '政治面貌',
+ value: 'zzmm',
+ isDict: false,
+ dictCode: ''
},
{
- label: '学历',
- value: 'whcd1'
- },
+ text: '民族',
+ value: 'mz',
+ isDict: true,
+ dictCode: 'mz'
+ }
]); // 字段列表
+
+ const dictCode = ref("")
+ const fieldisDict = ref(true);
+
+
const selectedOrgCode = ref(''); // 当前选择的单位 orgCode
const selectedOrgCodeLabel = ref('请选择单位'); // 当前选择的单位名称
const selectedField = ref(''); // 当前选择的字段
const selectedFieldLabel = ref('请选择字段'); // 当前选择的字段名称
+ const orgCodeGroupData = ref([]); //按照orgcode进行分组的数据 含劳动合同号
const chartData = ref({}); // 图表数据
const personnelList = ref([]); // 人员列表 initChart
+ const fieldValues = ref([]);
+ const chartOption = ref({});
- const chartOption = ref({
- tooltip: {
- trigger: 'axis',
- axisPointer: {
- type: 'shadow',
- },
- },
- xAxis: {
- type: 'category',
- data: [],
- },
- yAxis: {
- type: 'value',
- },
- series: [{
- name: '数量',
- type: 'bar',
- data: [],
- }, ],
- })
+ const chartTitle = computed(() => {
+ return selectedOrgCodeLabel.value + '人员(' + selectedFieldLabel.value + ')分组统计';
+ });
+
+ //图标翻页
+ const pageSize = ref(3); // 每页显示的项目数量
+ const currentPage = ref(1); // 当前页码
function detail(record) {
// console.log(record)
uni.navigateTo({
- url: "/pages/views/renliziyuan/renyuanxinxi/detail?data=" + encodeURIComponent(JSON.stringify(record))
- })
+ url: '/pages/views/renliziyuan/renyuanxinxi/detail?data=' + encodeURIComponent(JSON.stringify(record))
+ });
}
-
onMounted(() => {
// #ifdef APP
getHeight();
// #endif
- })
+
+
+ });
// #ifdef APP
const getHeight = () => {
@@ -170,7 +173,7 @@
.select('#top1')
.boundingClientRect((rect1) => {
// 计算上方组件高度总和
- const topComponentsHeight = rect1.height
+ const topComponentsHeight = rect1.height;
// 计算下方组件的高度
bottomHeight.value = screenHeight - topComponentsHeight - 415;
})
@@ -182,39 +185,451 @@
// 初始化图表
const initChart = () => {
setTimeout(async () => {
- if (!chart.value) return
- const myChart = await chart.value.init(echarts)
- myChart.setOption(chartOption.value)
- }, 300)
+ if (!chart.value) return;
+ const myChart = await chart.value.init(echarts);
+ myChart.setOption(chartOption.value);
+ }, 300);
};
- // 更新图表
- const updateChart = () => {
- if (!chart) return;
- const {
- xb,
- number
- } = chartData.value;
- chart.setOption({
- xAxis: {
- data: xb,
- },
- series: [{
- data: number,
- }, ],
+ const prevPage = () => {
+ if (currentPage.value > 1) {
+ currentPage.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 tempChartData = temp.slice(startIndex, endIndex);
+
+ }
+ }
+ // 更具数据生成图标的option
+ const getChartOption = (tempChartData) => {
+ // 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 = temp.slice(startIndex, endIndex);
+ let xData = [];
+ let seriesData = [];
+ // console.log(1, temp);
+ //当前机构下的数据 transformDataForEcharts
+
+ tempChartData.forEach((item) => {
+ xData.push(item.name);
});
+
+ for (let i = 0; i < fieldValues.value.length; i++) {
+ let tempData = [];
+ tempChartData.forEach((item) => {
+ if (item.data[i]) {
+ tempData.push(item.data[i]);
+ } else {
+ tempData.push(0);
+ }
+ });
+ seriesData.push({
+ name: fieldValues.value[i],
+ type: 'bar',
+ data: tempData
+ });
+ }
+ let tempOption = {
+ title: {
+ text: chartTitle.value,
+ padding: [0, 0, 0, 30]
+ },
+ toolbox: {
+ padding: [0, 30, 0, 0],
+ show: true,
+ feature: {
+ //工具配置项
+
+ restore: {
+ show: true //是否显示该工具
+ },
+ saveAsImage: {
+ show: true //是否显示该工具
+ }
+ }
+ },
+ xAxis: {
+ type: 'category',
+ data: xData,
+ axisLabel: {
+ color: '#7F84B5',
+ fontWeight: 300,
+ interval: 0,
+ rotate: 0
+ },
+ padding: [0, 10, 0, 10],
+ axisTick: {
+ show: false //刻度线
+ },
+ axisLine: {
+ show: false //不显示坐标轴线
+ }
+ },
+ yAxis: [{
+ show: true,
+ boundaryGap: false, //解决数据与线不对应问题
+ type: 'value',
+ // name: 'Budget (million USD)',
+ // data: this.yList,
+ minInterval: 1,
+ axisLabel: {
+ interval: 0
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ //背景网格线
+ type: 'dashed'
+ }
+ },
+
+ axisTick: {
+ show: true //刻度线
+ },
+ axisLine: {
+ show: false //不显示坐标轴线
+ }
+ }],
+ series: seriesData,
+
+ legend: {
+ data: fieldValues.value,
+ itemGap: 5,
+ padding: [0, 15, 0, 15],
+ y: 'bottom',
+ itemHeight: 8, //高
+ itemWidth: 18, //宽
+ type: 'scroll'
+ }
+ };
+ return tempOption
+ }
+
+ // 更新图表
+ const updateChart = (tempchartData) => {
+ // 初始化图表
+ setTimeout(async () => {
+ if (!chart.value) return;
+ const myChart = await chart.value.init(echarts);
+ console.log(tempchartData);
+
+
+ myChart.setOption(getChartOption(temp));
+ // 点击钻取事件
+ 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;
+
+ console.log(ldhth);
+
+ if (ldhth && ldhth.length > 0) {
+ fetchPersonnelList(ldhth);
+ }
+ // updateChart(updateData);
+ });
+ }, 300);
};
- // 获取统计数据
+ //根据一个键值查找数据
+ //查找人员劳动合同号
+ function findRyByOrgCode(treeData, targetOrgCode) {
+ // console.log(treeData, targetOrgCode);
+ for (const node of treeData) {
+ // 如果当前节点匹配,直接返回该节点及其子节点
+ if (node.orgCode === targetOrgCode) {
+ return node;
+ }
+ // 递归检查子节点
+ if (node.children && node.children.length > 0) {
+ const found = findNodeByOrgCode(node.children, targetOrgCode);
+ if (found) return found;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 从echart图标的树状数据中根据 orgCode 获取节点及其子节点数据
+ * @param {Array} treeData 树状数据
+ * @param {string} targetOrgCode 目标 orgCode
+ * @returns {Object|null} 匹配的节点及其子节点数据,未找到返回 null
+ */
+ function findNodeByOrgCode(treeData, targetOrgCode) {
+ // console.log(treeData, targetOrgCode);
+ for (const node of treeData) {
+ // 如果当前节点匹配,直接返回该节点及其子节点
+ if (node.name === targetOrgCode) {
+ return node;
+ }
+ // 递归检查子节点
+ if (node.children && node.children.length > 0) {
+ const found = findNodeByOrgCode(node.children, targetOrgCode);
+ if (found) return found;
+ }
+ }
+ return null;
+ }
+
+ //获取所有的fieldValue
+ function collectUniqueKeyValues(tree, key) {
+ const uniqueValues = new Set(); // 使用Set来自动处理唯一性
+
+ function traverse(node) {
+ if (node[key] !== undefined) {
+ uniqueValues.add(node[key]);
+ }
+ if (node.children && Array.isArray(node.children)) {
+ node.children.forEach((child) => traverse(child));
+ }
+ }
+
+ tree.forEach((node) => traverse(node)); // 假设tree是一个数组
+
+ return Array.from(uniqueValues); // 将Set转换为数组
+ }
+
+ // 示例用法
+ // const result = findNodeByOrgCode(echartData, "A01A01A01A01");
+ // console.log(result);
+ /**
+ * 转换数据为支持钻取的ECharts格式
+ * @param {Array} data 原始数据
+ * @param {string} selectOrgCode 当前选择的组织编码
+ * @returns {Object} 包含当前层级数据和子节点信息的对象 符合echart的格式
+ */
+
+ //-----------------------------------------------------------------------------------------
+ function transformData(selectOrgCode, data) {
+ const nodes = new Map();
+ //获取所有的fieldValue 用于图例和钻取和data[]中的数据顺序保持一致 动态建立fieldValue的数据
+ fieldValues.value = collectUniqueKeyValues(data, 'fieldValue');
+ // 获取orgCode的所有层级
+ function getHierarchy(orgCode) {
+ const hierarchy = [];
+ for (let i = selectOrgCode.length; i <= orgCode.length; i += 3) {
+ hierarchy.push(orgCode.substring(0, i));
+ }
+ // console.log('hierarchy', hierarchy);
+ return hierarchy;
+ }
+ // 获取父级orgCode
+ function getParentCode(code) {
+ if (code.length <= 3) return null;
+ return code.substring(0, code.length - 3);
+ }
+ // 动态赋值series的数据长度
+ let tempArrayValue = new Array(fieldValues.value.length).fill(0);
+ // 创建所有节点并建立父子关系
+ data.forEach((entry) => {
+ const hierarchy = getHierarchy(entry.orgCode);
+ hierarchy.forEach((code) => {
+ if (!nodes.has(code)) {
+ nodes.set(code, {
+ orgCode: code,
+ type: 'bar',
+ data: JSON.parse(JSON.stringify(tempArrayValue)), // 初始化data为[0, 0] 动态
+ children: []
+ });
+ }
+ });
+
+ // console.log('fieldValues', fieldValues.value, fieldValues.value.length, hierarchy);
+
+ // 更新当前节点的data
+ const node = nodes.get(entry.orgCode);
+ const fieldValue = parseInt(entry.fieldValue, 10);
+
+ for (let i = 0; i < fieldValues.value.length; i++) {
+ if (fieldValue === parseInt(fieldValues.value[i], 10)) {
+ // console.log(555, i, fieldValue, fieldValues.value[i], entry.number);
+ node.data[i] += entry.number;
+ }
+ }
+
+ // console.log(11, node);
+
+ // 建立父子关系
+ for (let i = 0; i < hierarchy.length - 1; i++) {
+ const parentCode = hierarchy[i];
+ const childCode = hierarchy[i + 1];
+ const parentNode = nodes.get(parentCode);
+ const childNode = nodes.get(childCode);
+ if (!parentNode.children.some((c) => c.orgCode === childCode)) {
+ parentNode.children.push(childNode);
+ }
+ }
+ });
+
+ // 计算非叶子节点的data(子节点之和)
+ function computeData(node) {
+ if (node.children.length === 0) return;
+ node.data = JSON.parse(JSON.stringify(tempArrayValue));
+ node.children.forEach((child) => {
+ computeData(child);
+ for (let i = 0; i < fieldValues.value.length; i++) {
+ // console.log(666, i, node.data[i], child.data[i]);
+ node.data[i] += child.data[i];
+ }
+ });
+ }
+
+ // 获取所有根节点(没有父节点或父节点不存在)
+ const rootNodes = [];
+ nodes.forEach((node, code) => {
+ const parentCode = getParentCode(code);
+ // console.log(parentCode);
+ if (!parentCode || !nodes.has(parentCode)) {
+ rootNodes.push(node);
+ }
+ });
+
+ // 递归计算每个根节点的data
+ rootNodes.forEach((root) => computeData(root));
+ // console.log('rootNodes', rootNodes);
+ // 转换为目标格式
+ function formatTree(node) {
+ return {
+ name: node.orgCode,
+ type: 'bar',
+ data: node.data,
+ children: node.children.map((child) => formatTree(child))
+ };
+ }
+
+ return rootNodes.map((root) => formatTree(root));
+ }
+
+ //-----------------------------------------------------------------------------------------
+
+ //根据 orgCode 的分级格式,递归地汇总本级及其所有下级的数据,并将下级数据放在本级的 children 属性中。 deepseek
+
+ const groupByOrgCode = (orgCode, data) => {
+ // 过滤出本级和所有下级的数据
+ console.log(1, data)
+ const filteredData = data.filter((item) => item.orgCode.startsWith(orgCode));
+ console.log(2, filteredData)
+ // 如果过滤后的数据为空,返回 null
+ if (filteredData.length === 0) {
+ uni.showToast({
+ title: "过滤后数据为空",
+ duration: 1000
+ })
+ return null;
+ }
+
+ // 按照 fieldValue 分组
+ const groupedByFieldValue = {};
+ try {
+ 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(','));
+ });
+ } catch (error) {
+ console.log(error)
+ }
+
+
+ // 构建本级结果
+ const result = {
+ orgCode: orgCode,
+ fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => ({
+ fieldValue: fieldValue,
+ number: groupedByFieldValue[fieldValue].number,
+ ldhth: [...new Set(groupedByFieldValue[fieldValue].ldhth)] // 去重
+ })),
+ children: []
+ };
+
+ // console.log('本级', result);
+
+ // 获取所有下一级的 orgCode
+ const nextLevelOrgCodes = new Set();
+ 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)
+ }
+ // 递归处理下一级数据
+ 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 filter
const fetchStatisticsData = async () => {
if (!selectedOrgCode.value || !selectedField.value) return;
+ let res = []
try {
- const res = await cxcRyDatAstatistics({
+ res = await cxcRyDatAstatistics({
orgCode: selectedOrgCode.value,
field: selectedField.value,
+ dictCode: dictCode.value,
+ fieldisDict: fieldisDict.value
});
- console.log(res)
- chartData.value = res.data;
- updateChart();
+ console.log(res); //deepseek
+ if (res.length = 0) {
+ uni.showToast({
+ title: "查询数据为空"
+ })
+ return
+ } else {
+ console.log(selectedOrgCode.value, res);
+ orgCodeGroupData.value = groupByOrgCode(selectedOrgCode.value, res);
+ console.log(orgCodeGroupData.value);
+ chartData.value = transformData(selectedOrgCode.value, res);
+
+ let temp = []
+ if (chartData.value[0].children.length > 0) {
+ temp = JSON.parse(JSON.stringify(chartData.value[0].children));
+ } else {
+ temp = chartData.value[0]
+ }
+ console.log(temp)
+ chartDataCount.value = temp.length;
+ // console.log(chartData.value);
+ updateChart(temp);
+ }
} catch (error) {
console.error('获取统计数据失败:', error);
}
@@ -226,26 +641,39 @@
const res = await cxcRyDatAstatisticsDetails({
ldhth: ldhthList
});
- console.log(res)
+ console.log(res);
personnelList.value = res.data;
} catch (error) {
console.error('获取人员列表失败:', error);
}
};
-
// 事件处理
- const onOrgCodeChange = (e) => {
- console.log(e)
+ const onOrgCodeChange = (e, data) => {
selectedOrgCode.value = e;
+ console.log(data.value.title);
+ selectedOrgCodeLabel.value = data.value.title;
fetchStatisticsData();
};
const onFieldChange = (e) => {
- const index = e.detail.value;
- selectedField.value = fieldList.value[index].value;
- selectedFieldLabel.value = fieldList.value[index].label;
- fetchStatisticsData();
+ console.log(e);
+ try {
+ selectedField.value = e;
+ for (var index = 0; index < fieldList.value.length; index++) {
+ var element = fieldList.value[index];
+ console.log(element);
+ if (element.value === e) {
+ selectedFieldLabel.value = element.text;
+ dictCode.value = element.dictCode
+ fieldisDict.value = element.isDict
+ }
+ }
+ fetchStatisticsData();
+ } catch (error) {
+ //TODO handle the exception
+ console.log(error);
+ }
};
const onChartClick = (e) => {
@@ -257,92 +685,155 @@
}
};
-
\ No newline at end of file