cxc-szcx-uniapp/pages/views/renliziyuan/renyuanxinxi/qttongji.vue
2025-02-19 12:50:03 +08:00

985 lines
26 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<view class="container" id="top1">
<uni-row style="margin-bottom: 10px">
<uni-col :span="5"><uni-title :title="'选择单位'" align="left" type="h4"></uni-title></uni-col>
<uni-col :span="19">
<trq-depart-select v-model="selectedOrgCode" returnCodeOrID="orgCode"
@change="onOrgCodeChange"></trq-depart-select>
</uni-col>
</uni-row>
<uni-row style="margin-bottom: 10px">
<uni-col :span="5"><uni-title :title="'选择字段'" align="left" type="h4"></uni-title></uni-col>
<uni-col :span="12">
<uni-data-select v-model="selectedField" :localdata="fieldList"
@change="onFieldChange"></uni-data-select>
</uni-col>
<uni-col style="margin-left:5px" :span="6" v-if="selectedField==='zjmc'"><button type="primary"
size="mini" @click="showPopup=!showPopup">筛选</button></uni-col>
</uni-row>
</view>
<!-- ECharts图表 -->
<view class="chart-container">
<l-echart ref="chart" @finished="initChart" />
</view>
<!-- 翻页按钮 -->
<view style="display: flex; justify-content: center; margin-top: 10px">
<button @click="prevPage" :disabled="currentPage === 1" size="mini">上一页</button>
<button @click="nextPage" :disabled="currentPage * pageSize >= chartDataCount.value"
size="mini">下一页</button>
</view>
<!-- 数据表格 -->
<uni-row style="margin-top: 10px; margin-left: 20px; margin-right: 20px" v-if="personnelList.length > 0">
<uni-col :span="2">
<view class="titleStyle">序号</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">姓名</view>
</uni-col>
<uni-col :span="5">
<view class="titleStyle">基层单位</view>
</uni-col>
<uni-col :span="5" v-if="selectedField.value !== 'zjmc'">
<view class="titleStyle">基层班组</view>
</uni-col>
<uni-col :span="5" v-else>
<view class="titleStyle">岗位</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">年龄</view>
</uni-col>
<uni-col :span="4">
<view class="titleStyle">操作</view>
</uni-col>
</uni-row>
<scroll-view scroll-y :style="{ height: bottomHeight + 'px' }">
<uni-row style="margin-bottom: 10px; margin-left: 20px; margin-right: 20px; font-size: 12px">
<view v-for="(item, index) in personnelList">
<uni-col :span="2">
<view class="dataStyle">
{{ index + 1 }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
{{ item.xm }}
</view>
</uni-col>
<uni-col :span="5">
<view class="dataStyle1">
{{ item.jcdw }}
</view>
</uni-col>
<uni-col :span="5" v-if="selectedField.value != 'zjmc'">
<view class="dataStyle1">
{{ item.jcxd }}
</view>
</uni-col>
<uni-col :span="4" v-else>
<view class="dataStyle">
{{ item.sdgw }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
{{ item.nl }}
</view>
</uni-col>
<uni-col :span="4">
<view class="dataStyle">
<span @click="detail(item)" style="color: red;">详情</span>
<!-- <button size="mini" type="primary" @click="detail(item)">详情</button> -->
</view>
</uni-col>
</view>
</uni-row>
</scroll-view>
<uni-popup ref="showPopup" type="bottom" border-radius="10px 10px 0 0">
<uni-card>
<uni-title :title="'已选证书:'" align="left" type="h4"></uni-title>
<view style="color: red;font-weight: 300;margin-bottom: 10px;">{{dictData}}</view>
<scroll-view scroll-y style="height: 40vh;">
<view>
<cxc-szcx-dictSelect :dictCode="dictCode" @change="dictChange"></cxc-szcx-dictSelect>
</view>
</scroll-view>
</uni-card>
</uni-popup>
</view>
</template>
<script setup>
import {
ref,
reactive,
onMounted,
computed
} from 'vue';
import * as echarts from 'echarts/dist/echarts.min'; // 引入ECharts的H5版本
import {
cxcRyDatAstatistics,
cxcRyDatAstatisticsCertificate,
cxcRyDatAstatisticsDetails
} from '@/api/renyuan.js';
// 存储下方组件的高度 tableData
const bottomHeight = ref(0);
// 新增加载状态
const chart = ref(null);
const chartDataCount = ref(0);
const fieldList = ref([{
text: '取证情况',
value: 'zjmc',
isDict: false,
dictCode: 'gzrlzy',
},
{
text: '岗位类别',
value: 'gwlb',
isDict: false,
dictCode: ''
},
{
text: '性别',
value: 'xb',
isDict: true,
dictCode: 'sex'
},
{
text: '政治面貌',
value: 'zzmm',
isDict: true,
dictCode: 'zzmm'
},
{
text: '民族',
value: 'mz',
isDict: true,
dictCode: 'mz'
}
]); // 字段列表
const dictCode = ref('');
const dictData = ref('');
const showPopup = ref(null);
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 fieldTexts = ref([]); //字段值
const chartOption = ref({});
const orgType = ref(''); //记录单位层级 by 闵
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))
});
}
onMounted(() => {
getHeight();
});
const dictChange = (e) => {
console.log(e)
dictData.value = e
fetchStatisticsData()
}
const getHeight = () => {
// 获取屏幕高度
const systemInfo = uni.getSystemInfoSync();
const screenHeight = systemInfo.screenHeight;
// 创建选择器查询对象
const query = uni.createSelectorQuery();
// 获取上方组件的高度
query
.select('#top1')
.boundingClientRect((rect1) => {
// 计算上方组件高度总和
const topComponentsHeight = rect1.height;
// 计算下方组件的高度
bottomHeight.value = screenHeight - topComponentsHeight - 415;
})
.exec();
};
// 初始化 ECharts length departChange
// 初始化图表
const initChart = () => {
setTimeout(async () => {
if (!chart.value) return;
const myChart = await chart.value.init(echarts);
myChart.setOption(chartOption.value);
}, 300);
};
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;
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, tempChartData);
//当前机构下的数据 transformDataForEcharts
let legendData = [];
for (let i = 0; i < fieldValues.value.length; i++) {
legendData.push(fieldValues.value[i].fieldText);
}
tempChartData.forEach((item) => {
xData.push(item.name);
});
for (let i = 0; i < fieldValues.value.length; i++) {
let tempData = [];
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].fieldText,
type: 'bar',
label: {
show: true, // 显示数值标签
position: 'top' // 数值标签位置
},
data: tempData
});
}
console.log(2, legendData, xData, seriesData);
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: legendData,
itemGap: 1,
padding: [0, 0, 0, 0],
y: 'bottom',
itemHeight: 8, //高
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.seriesIndex].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.orgText === 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 collectUniqueKeyFieldValues(tree) {
const uniqueMap = new Map();
tree.forEach((item) => {
const {
fieldValue,
fieldText
} = item;
const key = `${fieldValue}-${fieldText}`;
if (!uniqueMap.has(key)) {
uniqueMap.set(key, {
fieldValue,
fieldText
});
}
});
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;
}
}
// 查找指定 orgCode 对应的 orgText 的方法
findOrgText(orgCode) {
return this.orgCodeToOrgTextMap[orgCode];
}
}
// 示例用法
// 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 = collectUniqueKeyFieldValues(data);
// console.log(fieldValues.value);
const orgMapper = new OrgCodeMapper(data); //用于快速查找orgtext
// console.log(orgMapper.findOrgText('A01A01A01A01'));
// 获取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);
// 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 = entry.fieldValue;
for (let i = 0; i < fieldValues.value.length; i++) {
if (fieldValue === fieldValues.value[i].fieldValue) {
// 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)
return rootNodes;
// console.log('rootNodes', rootNodes);
// // 转换为目标格式
// 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) => {
// console.log(root);
// formatTree(root);
// });
}
//-----------------------------------------------------------------------------------------
//根据 orgCode 的分级格式,递归地汇总本级及其所有下级的数据,并将下级数据放在本级的 children 属性中。 deepseek
const groupByOrgCode = (orgCode, data) => {
// 过滤出本级和所有下级的数据
console.log("aaaa")
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 = {};
try {
filteredData.forEach((item) => {
// console.log(item);
if (!groupedByFieldValue[item.fieldValue]) {
groupedByFieldValue[item.fieldValue] = {
orgCode: item.orgCode,
orgText: item.orgText,
fieldText: item.fieldText,
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));
// 构建本级结果
console.log("aaaa")
const result = {
orgCode: orgCode,
orgText: orgMapper.findOrgText(orgCode),
fieldValues: Object.keys(groupedByFieldValue).map((fieldValue) => {
const {
fieldText,
orgCode,
orgText
} = groupedByFieldValue[fieldValue] || {};
return {
fieldValue: fieldValue,
fieldText: fieldText,
orgCode: orgCode,
orgText: orgText,
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 () => {
console.log(selectedOrgCode)
if (!selectedOrgCode.value || !selectedField.value) return;
let res = [];
chartData.value = [];
try {
//这里添加一个层级字段,并避免 厂机关A01A01A01 orgType by 闵
var tempOrgType = '1';
if(selectedOrgCode.value.includes('A01A01A01')){
tempOrgType = '1';
}else{
tempOrgType = orgType
}
if (selectedField.value === 'zjmc') {
console.log(dictCode.value);
console.log(dictData.value);
res = await cxcRyDatAstatisticsCertificate({
orgCode: selectedOrgCode.value,
field: selectedField.value,
dictCode: dictCode.value,
fieldisDict: fieldisDict.value,
typeOfWorkList: dictData.value,
orgType: tempOrgType.value
});
} else {
res = await cxcRyDatAstatistics({
orgCode: selectedOrgCode.value,
field: selectedField.value,
dictCode: dictCode.value,
fieldisDict: fieldisDict.value,
orgType: tempOrgType.value
});
}
// console.log(res); //deepseek
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));
chartDataCount.value = chartData.value.length;
console.log(chartData.value);
// updateChart(chartData.value);
} else {
var tempArr = [];
tempArr.push(temp[0])
chartData.value =tempArr;
}
updateChart(chartData.value);
}
} catch (error) {
console.error('获取统计数据失败:', error);
}
};
// 获取人员列表 delimiter
const fetchPersonnelList = async (ldhthList) => {
personnelList.value = [];
try {
const res = await cxcRyDatAstatisticsDetails({
ldhth: ldhthList
});
console.log(res);
if (res.success) {
personnelList.value = res.result;
}
} catch (error) {
console.error('获取人员列表失败:', error);
}
};
// 事件处理
const onOrgCodeChange = (e, data) => {
personnelList.value = [];
selectedOrgCode.value = e;
console.log(e)
console.log(data);
orgType.value = data.value.orgType; //赋值层级 by 闵
selectedOrgCodeLabel.value = data.value.title;
fetchStatisticsData();
};
const onFieldChange = (e) => {
personnelList.value = [];
// 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;
}
}
if (selectedField.value === 'zjmc') {
showPopup.value.open()
} else {
fetchStatisticsData();
}
} catch (error) {
//TODO handle the exception
console.log(error);
}
};
const onChartClick = (e) => {
personnelList.value = [];
const {
ldhth
} = chartData.value;
if (ldhth && ldhth.length > 0) {
fetchPersonnelList(ldhth);
}
};
</script>
<style scoped>
/* 颜色变量 */
:root {
--primary-blue: #409eff;
--deep-blue: #2c7be5;
--light-blue: #ecf5ff;
--gradient-start: #6b8cff;
--gradient-end: #4364f7;
--hover-blue: #66b1ff;
}
/* 全局容器 */
.container {
margin: 10px 10px;
padding: 10px;
background: linear-gradient(145deg, #f5f9ff, var(--light-blue));
border-radius: 12px;
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
border: 1px solid rgba(64, 158, 255, 0.1);
}
/* 图表容器 */
.chart-container {
height: 250px;
margin: 10px 0;
border-radius: 12px;
overflow: hidden;
background: #ffffff;
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.12);
border: 1px solid rgba(64, 158, 255, 0.08);
}
/* 表格标题行 */
.titleStyle {
font-size: 10px;
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: 10px;
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;
}
/* 内容样式 */
.dataStyle1 {
font-size: 8px;
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;
}
/* 滚动区域 */
scroll-view {
background: #ffffff;
border-radius: 0 0 8px 8px;
box-shadow: 0 4px 12px rgba(0, 35, 111, 0.08);
}
/* 输入框聚焦效果 */
.trq-depart-select:focus-within {
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
border-color: var(--primary-blue);
}
/* 加载动画优化 */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.container>* {
animation: fadeIn 0.6s cubic-bezier(0.23, 1, 0.32, 1);
}
/* 自定义滚动条美化 */
::-webkit-scrollbar {
width: 4px;
background: rgba(64, 158, 255, 0.05);
}
::-webkit-scrollbar-thumb {
background: linear-gradient(45deg, var(--primary-blue), var(--deep-blue));
border-radius: 6px;
border: 1px solid white;
}
/* 筛选行间距优化 */
.filter-row {
margin: 15px 0;
padding: 10px 0;
border-radius: 8px;
}
/* 响应式调整优化 */
@media (max-width: 768px) {
.chart-container {
height: 250px;
border-radius: 10px;
}
}
/* 数据行高亮效果 */
.data-row:nth-child(even) {
background: rgba(236, 245, 255, 0.3);
}
.data-row:hover {
box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.1);
}
</style>