| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701 |
- <template>
- <div class="performance-analysis">
- <!-- 头部导航 -->
- <div class="header">
- <div class="header-left">
- <el-button link class="back-btn" @click="handleBack">
- <el-icon>
- <ArrowLeft />
- </el-icon>
- <span>返回AI助手</span>
- </el-button>
- </div>
- <!-- <div class="header-right">
- <el-button class="export-btn" @click="handleExport">
- <el-icon>
- <Download />
- </el-icon>
- <span>导出文档</span>
- </el-button>
- </div> -->
- </div>
- <!-- 查询表单区域 -->
- <div class="query-form">
- <div class="form-container">
- <div class="custom-form horizontal-form">
- <div class="form-row">
- <div class="form-item">
- <div class="form-label">时间范围</div>
- <div class="form-content">
- <div class="button-group">
- <div v-for="option in dateRangeOptions" :key="option.value" class="custom-button"
- :class="{ active: queryForm.dateRangeType === option.value }"
- @click="handleDateRangeTypeChange(option.value)">
- {{ option.label }}
- </div>
- </div>
- <div class="month-range-picker" v-if="queryForm.dateRangeType == 'CUSTOM'">
- <el-date-picker v-model="queryForm.startMonth" type="month" placeholder="开始月份" class="date-picker"
- :disabled-date="disabledStartMonth" />
- <span class="range-separator">至</span>
- <el-date-picker v-model="queryForm.endMonth" type="month" placeholder="结束月份" class="date-picker"
- :disabled-date="disabledEndMonth" />
- </div>
- </div>
- </div>
- <div class="form-item">
- <div class="form-label">绩效维度</div>
- <div class="form-content">
- <div class="button-group">
- <div v-for="option in performanceDimensionOptions" :key="option.value" class="custom-button"
- :class="{ active: queryForm.performanceDimension === option.value }"
- @click="queryForm.performanceDimension = option.value">
- {{ option.label }}
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- <!-- 绩效分析内容区域 -->
- <div class="analysis-content">
- <!-- 大队和科室分析 - 双列面板 -->
- <div class="two-panel-layout">
- <!-- 大队分析 -->
- <div class="panel-item" :class="{ 'loading-overlay': brigadeLoading }">
- <div class="panel-header">
- <h3>大队</h3>
- </div>
- <!-- 折线图 -->
- <div class="chart-container">
- <div ref="brigadeChartRef" class="echarts-chart"></div>
- </div>
- <div class="panel-header">
- <h3>明细</h3>
- <span>得分(环比)</span>
- </div>
- <!-- 明细表格 -->
- <div class="table-container">
- <el-table :data="brigadeTableData" style="width: 100%" size="small">
- <el-table-column prop="time" label="" width="150" />
- <el-table-column v-for="column in brigadeTableColumn" :key="column.column" :prop="column.column"
- :label="column.name" />
- </el-table>
- </div>
- </div>
- <!-- 科室分析 -->
- <div class="panel-item" :class="{ 'loading-overlay': departmentLoading }">
- <div class="panel-header">
- <h3>科室</h3>
- </div>
- <!-- 折线图 -->
- <div class="chart-container">
- <div ref="departmentChartRef" class="echarts-chart"></div>
- </div>
- <div class="panel-header">
- <h3>明细</h3>
- <span>得分(环比)</span>
- </div>
- <!-- 明细表格 -->
- <div class="table-container">
- <el-table :data="departmentTableData" style="width: 100%" size="small">
- <el-table-column prop="time" label="" width="150" />
- <el-table-column v-for="column in departmentTableColumn" :key="column.column" :prop="column.column"
- :label="column.name" />
- </el-table>
- </div>
- </div>
- </div>
- <!-- 班组分析和个人分析 - 双列面板 -->
- <div class="two-panel-layout">
- <!-- 班组分析 -->
- <div class="panel-item" :class="{ 'loading-overlay': teamLoading }">
- <div class="panel-header">
- <h3>班组</h3>
- <div class="panel-tabs">
- <div class="button-group small">
- <div v-for="option in tabOptions" :key="option.value" class="custom-button"
- :class="{ active: teamTab === option.value }" @click="handleTeamTabChange(option.value)">
- {{ option.label }}
- </div>
- </div>
- <div class="sort-section">
- <span class="divider">|</span>
- <el-button link @click="toggleTeamSort" class="sort-btn">
- <img v-if="teamSortOrder === 'desc'" src="@/assets/images/down.png" alt="降序"
- style="width: 16px; height: 16px;" />
- <img v-else src="@/assets/images/up.png" alt="升序" style="width: 16px; height: 16px;" />
- </el-button>
- </div>
- </div>
- </div>
- <!-- 折线图 -->
- <div class="chart-container">
- <div ref="teamChartRef" class="echarts-chart"></div>
- </div>
- <div class="panel-header">
- <h3>明细</h3>
- <span>得分(环比)</span>
- </div>
- <!-- 明细表格 -->
- <div class="table-container">
- <el-table :data="teamTableData" style="width: 100%" size="small">
- <el-table-column prop="time" label="" width="120" />
- <el-table-column v-for="column in teamTableColumn" :key="column.column" :prop="column.column"
- :label="column.name">
- <template #header="{ column }">
- <el-tooltip :content="getTeamColumnTooltip(column.property)" placement="top">
- <span>{{ column.label }}</span>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- <!-- 个人分析 -->
- <div class="panel-item" :class="{ 'loading-overlay': personalLoading }">
- <div class="panel-header">
- <h3>个人</h3>
- <div class="panel-tabs">
- <div class="button-group small">
- <div v-for="option in personalTabOptions" :key="option.value" class="custom-button"
- :class="{ active: personalTab === option.value }" @click="handlePersonalTabChange(option.value)">
- {{ option.label }}
- </div>
- </div>
- <div class="sort-section">
- <span class="divider">|</span>
- <el-button link @click="togglePersonalSort" class="sort-btn">
- <img v-if="personalSortOrder === 'desc'" src="@/assets/images/down.png" alt="降序"
- style="width: 16px; height: 16px;" />
- <img v-else src="@/assets/images/up.png" alt="升序" style="width: 16px; height: 16px;" />
- </el-button>
- </div>
- </div>
- </div>
- <!-- 折线图 -->
- <div class="chart-container">
- <div ref="personalChartRef" class="echarts-chart"></div>
- </div>
- <div class="panel-header">
- <h3>明细</h3>
- <span>得分(环比)</span>
- </div>
- <!-- 明细表格 -->
- <div class="table-container">
- <el-table :data="personalTableData" style="width: 100%" size="small">
- <el-table-column prop="time" label="" width="120" />
- <el-table-column v-for="column in personalTableColumn" :key="column.column" :prop="column.column"
- :label="column.name">
- <template #header="{ column }">
- <el-tooltip :content="getPersonalColumnTooltip(column.property)" placement="top">
- <span>{{ column.label }}</span>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import { ref, onMounted, onUnmounted, watch } from 'vue'
- import { ArrowLeft, Download, Loading } from '@element-plus/icons-vue'
- import { ElMessage, ElLoading } from 'element-plus'
- import { useEcharts } from '@/hooks/chart.js'
- import { getCalculateByTime, getCalculateByTimeList } from '@/api/assistant/assistant.js'
- // 定义emit事件
- const emit = defineEmits(['back'])
- // 查询表单数据
- const queryForm = ref({
- dateRangeType: 'THREE_MONTHS',
- dateRange: [],
- startMonth: null,
- endMonth: null,
- performanceDimension: 'SCORE'
- })
- // 标签页数据
- const teamTab = ref('SCORE')
- const personalTab = ref('SCORE')
- // 排序状态
- const teamSortOrder = ref('desc') // desc: 倒序, asc: 正序
- const personalSortOrder = ref('desc') // desc: 倒序, asc: 正序
- // 加载状态
- const loading = ref(false)
- const brigadeLoading = ref(false)
- const departmentLoading = ref(false)
- const teamLoading = ref(false)
- const personalLoading = ref(false)
- // 真实数据
- const realData = ref({
- brigade: [],
- brigadeList: [],
- team: [],
- teamList: [],
- personal: [],
- personalList: [],
- department: [],
- departmentList: []
- })
- // 时间范围选项
- const dateRangeOptions = [
- { value: 'THREE_MONTHS', label: '近三个月' },
- { value: 'SIX_MONTHS', label: '近六个月' },
- { value: 'CUSTOM', label: '自定义' }
- ]
- // 日期限制计算属性
- const disabledDate = (date) => {
- const now = new Date()
- const currentYear = now.getFullYear()
- const currentMonth = now.getMonth()
- // 禁用当月的所有日期
- if (date.getFullYear() === currentYear && date.getMonth() === currentMonth) {
- return true
- }
- // 禁用未来的日期
- if (date.getTime() > now.getTime()) {
- return true
- }
- return false
- }
- // 开始月份限制计算属性
- const disabledStartMonth = (date) => {
- const now = new Date()
- const currentYear = now.getFullYear()
- const currentMonth = now.getMonth()
- // 禁用当月
- if (date.getFullYear() === currentYear && date.getMonth() === currentMonth) {
- return true
- }
- // 禁用未来月份
- if (date.getFullYear() > currentYear || (date.getFullYear() === currentYear && date.getMonth() > currentMonth)) {
- return true
- }
- // 如果已经选择了结束月份,开始月份不能晚于或等于结束月份
- if (queryForm.value.endMonth) {
- const endDate = new Date(queryForm.value.endMonth)
- if (date.getFullYear() > endDate.getFullYear() ||
- (date.getFullYear() === endDate.getFullYear() && date.getMonth() >= endDate.getMonth())) {
- return true
- }
- }
- return false
- }
- // 结束月份限制计算属性
- const disabledEndMonth = (date) => {
- const now = new Date()
- const currentYear = now.getFullYear()
- const currentMonth = now.getMonth()
- // 禁用当月
- if (date.getFullYear() === currentYear && date.getMonth() === currentMonth) {
- return true
- }
- // 禁用未来月份
- if (date.getFullYear() > currentYear || (date.getFullYear() === currentYear && date.getMonth() > currentMonth)) {
- return true
- }
- // 如果已经选择了开始月份,结束月份不能早于或等于开始月份
- if (queryForm.value.startMonth) {
- const startDate = new Date(queryForm.value.startMonth)
- if (date.getFullYear() < startDate.getFullYear() ||
- (date.getFullYear() === startDate.getFullYear() && date.getMonth() <= startDate.getMonth())) {
- return true
- }
- }
- return false
- }
- // 绩效维度选项
- const performanceDimensionOptions = [
- { value: 'SCORE', label: '总分' },
- { value: 'EFFICIENCY', label: '查获效率' },
- { value: 'QUALIFIED', label: '巡检合格率' },
- { value: 'TRAINING', label: '培训得分' }
- ]
- // 班组标签页选项
- const tabOptions = [
- { value: 'SCORE', label: '分数' },
- { value: 'PROGRESS', label: '进步' },
- ]
- // 个人标签页选项
- const personalTabOptions = [
- { value: 'SCORE', label: '分数' },
- { value: 'PROGRESS', label: '进步' },
- ]
- // 图表容器引用
- const brigadeChartRef = ref(null)
- const departmentChartRef = ref(null)
- const teamChartRef = ref(null)
- const personalChartRef = ref(null)
- // 图表实例
- const { setOption: setBrigadeOption, dispose: disposeBrigade } = useEcharts(brigadeChartRef)
- const { setOption: setDepartmentOption, dispose: disposeDepartment } = useEcharts(departmentChartRef)
- const { setOption: setteamListOption, dispose: disposeTeam } = useEcharts(teamChartRef)
- const { setOption: setPersonalOption, dispose: disposePersonal } = useEcharts(personalChartRef)
- // 颜色数组
- const colorList = ['#6BA364', '#3AACFF', '#EABF5A', '#557DDB', '#71C5D1']
- // 监听时间范围和绩效维度的改变
- watch([() => queryForm.value.dateRangeType, () => queryForm.value.startMonth, () => queryForm.value.endMonth, () => queryForm.value.performanceDimension], () => {
- fetchData()
- })
- // 表格数据
- const brigadeTableData = ref([
- ])
- const departmentTableData = ref([
- ])
- const teamTableData = ref([
- ])
- const personalTableData = ref([
- ])
- // 大队图表配置
- const brigadeChartOptions = {
- tooltip: {
- trigger: 'axis'
- },
- legend: {
- show: true,
- icon: 'rect',
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: []
- },
- yAxis: {
- type: 'value',
- name: '得分',
- min: 80,
- interval: 5
- },
- series: [
- ]
- }
- // 科室图表配置
- const departmentChartOptions = {
- tooltip: {
- trigger: 'axis'
- },
- legend: {
- show: true,
- icon: 'rect',
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: []
- },
- yAxis: {
- type: 'value',
- name: '得分',
- min: 80,
- interval: 5
- },
- series: [
- ]
- }
- // 班组明细图表配置
- const teamListChartOptions = {
- tooltip: {
- trigger: 'axis'
- },
- legend: {
- show: true,
- icon: 'rect',
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: []
- },
- yAxis: {
- type: 'value',
- name: '得分',
- min: 80,
- interval: 5
- },
- series: []
- }
- // 个人图表配置
- const personalChartOptions = {
- tooltip: {
- trigger: 'axis'
- },
- legend: {
- show: true,
- icon: 'rect',
- },
- grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
- containLabel: true
- },
- xAxis: {
- type: 'category',
- boundaryGap: false,
- data: []
- },
- yAxis: {
- type: 'value',
- name: '得分',
- min: 80,
- interval: 5
- },
- series: []
- }
- // 返回按钮点击事件
- const handleBack = () => {
- emit('back')
- }
- // 计算预设时间范围的开始月和结束月
- const calculatePresetDateRange = (dateRangeType) => {
- const endDate = new Date()
- endDate.setDate(0) // 设置为上个月最后一天,不包括本月
- let startDate = new Date(endDate)
- if (dateRangeType === 'THREE_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 2)
- } else if (dateRangeType === 'SIX_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 5)
- }
- console.log(new Date(startDate.getFullYear(), startDate.getMonth(), 1), 2222)
- // 返回开始月和结束月的月份对象
- return {
- startMonth: new Date(startDate.getFullYear(), startDate.getMonth(), 1),
- endMonth: new Date(endDate.getFullYear(), endDate.getMonth(), 1)
- }
- }
- // 安全的日期格式化函数
- const formatDate = (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}`
- }
- // 获取班组表格列头的tooltip内容
- const getTeamColumnTooltip = (columnProperty) => {
- // 查找当前行的数据,获取对应的科室名称
- const currentRow = teamTableData.value[0] // 取第一行数据作为参考
- if (currentRow && currentRow[`${columnProperty}DeptName`]) {
- return currentRow[`${columnProperty}DeptName`]
- }
- return ''
- }
- // 获取个人表格列头的tooltip内容
- const getPersonalColumnTooltip = (columnProperty) => {
- // 查找当前行的数据,获取对应的className
- const currentRow = personalTableData.value[0] // 取第一行数据作为参考
- if (currentRow && currentRow[`${columnProperty}ClassName`] && currentRow && currentRow[`${columnProperty}DeptName`]) {
- return `${currentRow[`${columnProperty}DeptName`]}/${currentRow[`${columnProperty}ClassName`]}`
- }
- return ''
- }
- // 处理时间范围类型切换
- const handleDateRangeTypeChange = (dateRangeType) => {
- // 如果切换到自定义时间范围,并且之前是预设时间范围,则自动填充开始月和结束月
- if (dateRangeType === 'CUSTOM' && (queryForm.value.dateRangeType === 'THREE_MONTHS' || queryForm.value.dateRangeType === 'SIX_MONTHS')) {
- const presetRange = calculatePresetDateRange(queryForm.value.dateRangeType)
- queryForm.value.startMonth = presetRange.startMonth
- queryForm.value.endMonth = presetRange.endMonth
- }
- // 更新时间范围类型
- queryForm.value.dateRangeType = dateRangeType
- }
- // 绩效维度映射
- const performanceDimensionMap = {
- 'SCORE': 'totalScore',
- 'EFFICIENCY': 'seizureEfficiency',
- 'QUALIFIED': 'inspectionPassRate',
- 'TRAINING': 'trainingScore'
- }
- // 维度类型映射
- const dimensionTypeMap = {
- 'SCORE': 1,
- 'PROGRESS': 2
- }
- // 排序映射
- const sortOrderMap = {
- 'desc': 2,
- 'asc': 1
- }
- // 构建科室API参数 (没有dimensionType参数)
- const buildDepartmentApiParams = () => {
- const params = {
- resultField: performanceDimensionMap[queryForm.value.performanceDimension],
- sortOrder: 1
- }
- // 处理时间范围
- if (queryForm.value.dateRangeType === 'CUSTOM' && queryForm.value.startMonth && queryForm.value.endMonth) {
- // 处理自定义月份范围选择
- const startDate = new Date(queryForm.value.startMonth)
- const endDate = new Date(queryForm.value.endMonth)
- console.log(queryForm.value.startMonth, queryForm.value.endMonth, startDate, endDate, startDate.getFullYear(), startDate.getMonth())
- // debugger
- // 开始月的第一天
- const startTime = new Date(startDate.getFullYear(), startDate.getMonth(), 1)
- // 结束月的最后一天
- const endTime = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0)
- params.startTime = formatDate(startTime)
- params.endTime = formatDate(endTime)
- } else {
- // 处理预设时间范围
- const endDate = new Date()
- endDate.setDate(0) // 设置为上个月最后一天,不包括本月
- let startDate = new Date(endDate)
- if (queryForm.value.dateRangeType === 'THREE_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 2)
- } else if (queryForm.value.dateRangeType === 'SIX_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 5)
- }
- params.startTime = formatDate(startDate)
- params.endTime = formatDate(endDate)
- }
- return params
- }
- // 构建班组API参数 (包含dimensionType和sortOrder)
- const buildTeamApiParams = () => {
- const params = {
- resultField: performanceDimensionMap[queryForm.value.performanceDimension],
- sortOrder: sortOrderMap[teamSortOrder.value],
- dimensionType: dimensionTypeMap[teamTab.value]
- }
- // 处理时间范围
- if (queryForm.value.dateRangeType === 'CUSTOM' && queryForm.value.startMonth && queryForm.value.endMonth) {
- // 处理自定义月份范围选择
- const startDate = new Date(queryForm.value.startMonth)
- const endDate = new Date(queryForm.value.endMonth)
- // 开始月的第一天
- const startTime = new Date(startDate.getFullYear(), startDate.getMonth(), 1)
- // 结束月的最后一天
- const endTime = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0)
- params.startTime = formatDate(startTime)
- params.endTime = formatDate(endTime)
- } else {
- // 处理预设时间范围
- const endDate = new Date()
- endDate.setDate(0) // 设置为上个月最后一天,不包括本月
- let startDate = new Date(endDate)
- if (queryForm.value.dateRangeType === 'THREE_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 2)
- } else if (queryForm.value.dateRangeType === 'SIX_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 5)
- }
- // 开始时间增加1天
- startDate.setDate(startDate.getDate() + 1)
- params.startTime = formatDate(startDate)
- params.endTime = formatDate(endDate)
- }
- return params
- }
- // 构建个人API参数 (包含dimensionType和sortOrder)
- const buildPersonalApiParams = () => {
- const params = {
- resultField: performanceDimensionMap[queryForm.value.performanceDimension],
- sortOrder: sortOrderMap[personalSortOrder.value],
- dimensionType: dimensionTypeMap[personalTab.value]
- }
- // 处理时间范围
- if (queryForm.value.dateRangeType === 'CUSTOM' && queryForm.value.startMonth && queryForm.value.endMonth) {
- // 处理自定义月份范围选择
- const startDate = new Date(queryForm.value.startMonth)
- const endDate = new Date(queryForm.value.endMonth)
- // 开始月的第一天
- const startTime = new Date(startDate.getFullYear(), startDate.getMonth(), 1)
- // 结束月的最后一天
- const endTime = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0)
- params.startTime = formatDate(startTime)
- params.endTime = formatDate(endTime)
- } else {
- // 处理预设时间范围
- const endDate = new Date()
- endDate.setDate(0) // 设置为上个月最后一天,不包括本月
- let startDate = new Date(endDate)
- if (queryForm.value.dateRangeType === 'THREE_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 2)
- } else if (queryForm.value.dateRangeType === 'SIX_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 5)
- }
- // 开始时间增加1天
- startDate.setDate(startDate.getDate() + 1)
- params.startTime = formatDate(startDate)
- params.endTime = formatDate(endDate)
- }
- return params
- }
- // 构建大队API参数 (dimension = 4,没有dimensionType参数)
- const buildBrigadeApiParams = () => {
- const params = {
- resultField: performanceDimensionMap[queryForm.value.performanceDimension],
- sortOrder: 1
- }
- // 处理时间范围
- if (queryForm.value.dateRangeType === 'CUSTOM' && queryForm.value.startMonth && queryForm.value.endMonth) {
- // 处理自定义月份范围选择
- const startDate = new Date(queryForm.value.startMonth)
- const endDate = new Date(queryForm.value.endMonth)
- // 开始月的第一天
- const startTime = new Date(startDate.getFullYear(), startDate.getMonth(), 1)
- // 结束月的最后一天
- const endTime = new Date(endDate.getFullYear(), endDate.getMonth() + 1, 0)
- params.startTime = formatDate(startTime)
- params.endTime = formatDate(endTime)
- } else {
- // 处理预设时间范围
- const endDate = new Date()
- endDate.setDate(0) // 设置为上个月最后一天,不包括本月
- let startDate = new Date(endDate)
- if (queryForm.value.dateRangeType === 'THREE_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 2)
- } else if (queryForm.value.dateRangeType === 'SIX_MONTHS') {
- startDate.setMonth(endDate.getMonth() - 5)
- }
- params.startTime = formatDate(startDate)
- params.endTime = formatDate(endDate)
- }
- return params
- }
- // 数据请求函数
- // 获取大队数据
- const fetchBrigadeData = async () => {
- brigadeLoading.value = true
- try {
- // 大队数据 (dimension = 4,没有dimensionType参数)
- const brigadeChartParams = buildBrigadeApiParams()
- brigadeChartParams.dimension = 4
- const brigadeTableParams = buildBrigadeApiParams()
- brigadeTableParams.dimension = 4
- // 并行请求大队图表和表格数据
- const [brigadeChartResponse, brigadeTableResponse] = await Promise.all([
- getCalculateByTime(brigadeChartParams),
- getCalculateByTimeList(brigadeTableParams)
- ])
- // 设置大队数据
- if (brigadeChartResponse.data) {
- realData.value.brigade = brigadeChartResponse.data || []
- }
- if (brigadeTableResponse.data) {
- realData.value.brigadeList = brigadeTableResponse.data || []
- }
- // 请求完成后直接更新大队数据
- updateBrigadeData()
- } catch (error) {
- console.error('大队数据请求失败:', error)
- ElMessage.error('大队数据加载失败')
- } finally {
- brigadeLoading.value = false
- }
- }
- // 获取科室数据
- const fetchDepartmentData = async () => {
- departmentLoading.value = true
- try {
- // 科室数据 (dimension = 3,没有dimensionType参数)
- const departmentChartParams = buildDepartmentApiParams()
- departmentChartParams.dimension = 3
- const departmentTableParams = buildDepartmentApiParams()
- departmentTableParams.dimension = 3
- // 并行请求科室图表和表格数据
- const [departmentChartResponse, departmentTableResponse] = await Promise.all([
- getCalculateByTime(departmentChartParams),
- getCalculateByTimeList(departmentTableParams)
- ])
- // 设置科室数据
- if (departmentChartResponse.data) {
- realData.value.department = departmentChartResponse.data || []
- }
- if (departmentTableResponse.data) {
- realData.value.departmentList = departmentTableResponse.data || []
- }
- // 请求完成后直接更新科室数据
- updateDepartmentData()
- } catch (error) {
- console.error('科室数据请求失败:', error)
- ElMessage.error('科室数据加载失败')
- } finally {
- departmentLoading.value = false
- }
- }
- // 获取班组数据
- const fetchTeamData = async () => {
- teamLoading.value = true
- try {
- // 班组数据 (dimension = 2,包含dimensionType和sortOrder)
- const teamChartParams = buildTeamApiParams()
- teamChartParams.dimension = 2
- const teamTableParams = buildTeamApiParams()
- teamTableParams.dimension = 2
- // 并行请求班组图表和表格数据
- const [teamChartResponse, teamTableResponse] = await Promise.all([
- getCalculateByTime(teamChartParams),
- getCalculateByTimeList(teamTableParams)
- ])
- // 设置班组数据
- if (teamChartResponse.data) {
- realData.value.team = teamChartResponse.data || []
- }
- if (teamTableResponse.data) {
- realData.value.teamList = teamTableResponse.data || []
- }
- // 请求完成后直接更新班组数据
- updateTeamData()
- } catch (error) {
- console.error('班组数据请求失败:', error)
- ElMessage.error('班组数据加载失败')
- } finally {
- teamLoading.value = false
- }
- }
- // 获取个人数据
- const fetchPersonalData = async () => {
- personalLoading.value = true
- try {
- // 个人数据 (dimension = 1,包含dimensionType和sortOrder)
- const personalChartParams = buildPersonalApiParams()
- personalChartParams.dimension = 1
- const personalTableParams = buildPersonalApiParams()
- personalTableParams.dimension = 1
- // 并行请求个人图表和表格数据
- const [personalChartResponse, personalTableResponse] = await Promise.all([
- getCalculateByTime(personalChartParams),
- getCalculateByTimeList(personalTableParams)
- ])
- // 设置个人数据
- if (personalChartResponse.data) {
- realData.value.personal = personalChartResponse.data || []
- }
- if (personalTableResponse.data) {
- realData.value.personalList = personalTableResponse.data || []
- }
- // 请求完成后直接更新个人数据
- updatePersonalData()
- } catch (error) {
- console.error('个人数据请求失败:', error)
- ElMessage.error('个人数据加载失败')
- } finally {
- personalLoading.value = false
- }
- }
- const fetchData = async () => {
- loading.value = true
- try {
- // 并行请求大队、科室、班组和个人数据
- // 数据更新已经在各个数据请求函数中完成
- await Promise.all([
- fetchBrigadeData(),
- fetchDepartmentData(),
- fetchTeamData(),
- fetchPersonalData()
- ])
- } catch (error) {
- console.error('数据请求失败:', error)
- ElMessage.error('数据加载失败')
- } finally {
- loading.value = false
- }
- }
- // 表格列定义
- const brigadeTableColumn = ref([])
- const departmentTableColumn = ref([])
- const teamTableColumn = ref([])
- const personalTableColumn = ref([])
- const getColumnData = (arr, column) => {
- let res = arr.map(item => {
- const { dataItems } = item;
- let items = [...dataItems];
- let findAll = items.map(ele => {
- let getColumn = column.find(e => e.name === ele.name)
- return {
- ...ele,
- [getColumn.column]: ele.displayValue,
- [`${getColumn.column}DeptName`]: ele?.deptName || '',
- [`${getColumn.column}ClassName`]: ele?.className || ''
- }
- })
- // 将对象数组转换为扁平的对象
- const flattenedObject = findAll.reduce((acc, obj) => {
- return { ...acc, ...obj };
- }, {});
- return {
- time: item.timeLabel,
- ...flattenedObject
- }
- })
- return res
- }
- // 更新大队数据(包含图表和表格)
- const updateBrigadeData = () => {
- // 更新大队图表
- if (realData.value.brigade) {
- const xAxisData = realData.value.brigade.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.brigade.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setBrigadeOption({
- ...brigadeChartOptions,
- xAxis: { ...brigadeChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- // 更新大队表格数据
- if (realData.value.brigadeList) {
- const timeDataList = realData.value.brigadeList.timeDataList;
- brigadeTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- brigadeTableColumn.value.push({ name: item.name, column: `brigade${index}` })
- })
- }
- brigadeTableData.value = getColumnData(timeDataList, brigadeTableColumn.value)
- }
- }
- // 更新科室数据(包含图表和表格)
- const updateDepartmentData = () => {
- // 更新科室图表
- if (realData.value.department) {
- const xAxisData = realData.value.department.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.department.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setDepartmentOption({
- ...departmentChartOptions,
- xAxis: { ...departmentChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- // 更新科室表格数据
- if (realData.value.departmentList) {
- console.log(realData.value.departmentList, 'realData.value.departmentList');
- const timeDataList = realData.value.departmentList.timeDataList;
- departmentTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- departmentTableColumn.value.push({ name: item.name, column: `depart${index}` })
- })
- }
- departmentTableData.value = getColumnData(timeDataList, departmentTableColumn.value)
- console.log(departmentTableData.value, 'departmentTableData');
- }
- }
- // 更新班组数据(包含图表和表格)
- const updateTeamData = () => {
- // 更新班组图表
- if (realData.value.team && realData.value.team.timeDataList) {
- const xAxisData = realData.value.team.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.team.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setteamListOption({
- ...teamListChartOptions,
- xAxis: { ...teamListChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- // 更新班组表格数据
- if (realData.value.teamList) {
- const timeDataList = realData.value.teamList.timeDataList;
- teamTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- teamTableColumn.value.push({ name: item.name, column: `team${index}` })
- })
- }
- teamTableData.value = getColumnData(timeDataList, teamTableColumn.value)
- console.log(teamTableData.value, 'teamTableData');
- }
- }
- // 更新个人数据(包含图表和表格)
- const updatePersonalData = () => {
- // 更新个人图表
- if (realData.value.personal && realData.value.personal.timeDataList) {
- const xAxisData = realData.value.personal.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.personal.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setPersonalOption({
- ...personalChartOptions,
- xAxis: { ...personalChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- // 更新个人表格数据
- if (realData.value.personalList) {
- const timeDataList = realData.value.personalList.timeDataList;
- personalTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- personalTableColumn.value.push({ name: item.name, column: `personal${index}` })
- })
- }
- personalTableData.value = getColumnData(timeDataList, personalTableColumn.value)
- }
- }
- // 更新班组图表数据
- const updateTeamChartData = () => {
- if (realData.value.team && realData.value.team.timeDataList) {
- const xAxisData = realData.value.team.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.team.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setteamListOption({
- ...teamListChartOptions,
- xAxis: { ...teamListChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- }
- // 更新个人图表数据
- const updatePersonalChartData = () => {
- if (realData.value.personal && realData.value.personal.timeDataList) {
- const xAxisData = realData.value.personal.timeAxis;
- let seriesData = [];
- let timeDataList = realData.value.personal.timeDataList;
- let arr = {};
- timeDataList.forEach(item => {
- item.dataItems.forEach(ele => {
- if (!arr[ele.name]) {
- arr[ele.name] = [];
- }
- arr[ele.name].push(ele.value);
- })
- })
- Object.keys(arr).forEach((item, index) => {
- seriesData.push({
- name: item,
- type: 'line',
- symbol: 'circle',
- symbolSize: 6,
- data: arr[item],
- itemStyle: { color: colorList[index % colorList.length] },
- lineStyle: { color: colorList[index % colorList.length], width: 2 }
- })
- })
- setPersonalOption({
- ...personalChartOptions,
- xAxis: { ...personalChartOptions.xAxis, data: xAxisData },
- series: seriesData
- })
- }
- }
- // 更新班组表格数据
- const updateTeamTableData = () => {
- if (realData.value.teamList) {
- const timeDataList = realData.value.teamList.timeDataList;
- teamTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- teamTableColumn.value.push({ name: item.name, column: `team${index}` })
- })
- }
- teamTableData.value = getColumnData(timeDataList, teamTableColumn.value)
- }
- }
- // 更新个人表格数据
- const updatePersonalTableData = () => {
- if (realData.value.personalList) {
- const timeDataList = realData.value.personalList.timeDataList;
- personalTableColumn.value = []
- if (timeDataList && timeDataList.length > 0 && timeDataList[0].dataItems) {
- timeDataList[0].dataItems.forEach((item, index) => {
- personalTableColumn.value.push({ name: item.name, column: `personal${index}` })
- })
- }
- personalTableData.value = getColumnData(timeDataList, personalTableColumn.value)
- }
- }
- // 标签页切换处理
- const handleTeamTabChange = async (value) => {
- teamTab.value = value
- teamLoading.value = true
- try {
- await fetchTeamData()
- updateTeamData()
- } catch (error) {
- console.error('班组标签页切换失败:', error)
- ElMessage.error('班组数据加载失败')
- } finally {
- teamLoading.value = false
- }
- }
- const handlePersonalTabChange = async (value) => {
- personalTab.value = value
- personalLoading.value = true
- try {
- await fetchPersonalData()
- updatePersonalData()
- } catch (error) {
- console.error('个人标签页切换失败:', error)
- ElMessage.error('个人数据加载失败')
- } finally {
- personalLoading.value = false
- }
- }
- // 切换排序顺序
- const toggleTeamSort = async () => {
- teamSortOrder.value = teamSortOrder.value === 'desc' ? 'asc' : 'desc'
- teamLoading.value = true
- try {
- await fetchTeamData()
- updateTeamData()
- } catch (error) {
- console.error('班组排序切换失败:', error)
- ElMessage.error('班组数据加载失败')
- } finally {
- teamLoading.value = false
- }
- }
- const togglePersonalSort = async () => {
- personalSortOrder.value = personalSortOrder.value === 'desc' ? 'asc' : 'desc'
- personalLoading.value = true
- try {
- await fetchPersonalData()
- updatePersonalData()
- } catch (error) {
- console.error('个人排序切换失败:', error)
- ElMessage.error('个人数据加载失败')
- } finally {
- personalLoading.value = false
- }
- }
- // 初始化图表
- const initCharts = () => {
- if (teamChartRef.value && teamChartRef.value.offsetHeight > 0) {
- setDepartmentOption(departmentChartOptions)
- }
- if (teamChartRef.value && teamChartRef.value.offsetHeight > 0) {
- setteamListOption(teamListChartOptions)
- }
- if (personalChartRef.value && personalChartRef.value.offsetHeight > 0) {
- setPersonalOption(personalChartOptions)
- }
- }
- // 组件挂载
- onMounted(() => {
- initCharts()
- setTimeout(() => {
- initCharts()
- }, 200)
- // 初始加载数据
- fetchData()
- })
- // 组件卸载时销毁图表
- onUnmounted(() => {
- disposeBrigade()
- disposeDepartment()
- disposeTeam()
- disposePersonal()
- })
- </script>
- <style lang="scss" scoped>
- .littleTitle {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin: 0;
- }
- .performance-analysis {
- width: 100%;
- min-height: 100vh;
- background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
- padding: 20px;
- }
- .header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0 16px 16px 16px;
- }
- .back-btn {
- color: #3D3D3D;
- font-size: 14px;
- }
- .back-btn:hover {
- color: #3D3D3D;
- }
- .export-btn {
- background-color: transparent;
- }
- .export-btn:hover {
- background-color: rgba(0, 0, 0, 0.05);
- }
- .query-form {
- background: white;
- border-radius: 8px;
- padding: 12px 18px;
- margin-bottom: 16px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- }
- .form-container {
- width: 60%;
- }
- .custom-form .form-row {
- display: flex;
- align-items: flex-start;
- gap: 40px;
- }
- .custom-form .form-item {
- display: flex;
- align-items: center;
- gap: 6px;
- flex: 1;
- }
- .custom-form .form-label {
- width: 80px;
- font-size: 14px;
- color: #3D3D3D;
- font-size: 15px;
- text-align: left;
- flex-shrink: 0;
- }
- .form-content {
- display: flex;
- align-items: center;
- gap: 16px;
- flex: 1;
- }
- .button-group {
- display: flex;
- gap: 8px;
- }
- .button-group.small {
- gap: 4px;
- }
- .custom-button {
- padding: 8px 16px;
- border: 1px solid #2879FF;
- border-radius: 4px;
- background-color: #FFFFFF;
- color: #2879FF;
- font-size: 14px;
- cursor: pointer;
- transition: all 0.3s ease;
- text-align: center;
- user-select: none;
- }
- .button-group.small .custom-button {
- padding: 4px 12px;
- font-size: 12px;
- }
- .custom-button:hover {
- background-color: #f0f7ff;
- }
- .custom-button.active {
- background-color: #2879FF;
- color: #FFFFFF;
- }
- .custom-button.active:hover {
- background-color: #1e6fd9;
- }
- .date-picker {
- min-width: 300px;
- }
- .month-range-picker {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .month-range-picker .date-picker {
- min-width: 140px;
- }
- .range-separator {
- color: #606266;
- font-size: 14px;
- white-space: nowrap;
- }
- .analysis-content {
- display: flex;
- flex-direction: column;
- gap: 16px;
- }
- .two-panel-layout {
- display: flex;
- gap: 16px;
- }
- .panel-item {
- flex: 1;
- background: white;
- border-radius: 8px;
- padding: 20px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- gap: 16px;
- }
- .panel-item.full-width {
- width: 100%;
- }
- .panel-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding-bottom: 0;
- span {
- color: #666666;
- font-size: 13px;
- }
- }
- .panel-header h3 {
- font-size: 16px;
- font-weight: 600;
- color: #333;
- margin: 0;
- }
- .panel-tabs {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .sort-section {
- display: flex;
- align-items: center;
- gap: 4px;
- }
- .divider {
- color: #E4E7ED;
- font-weight: normal;
- }
- .sort-btn {
- padding: 0;
- margin: 0;
- width: 20px;
- height: 20px;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .sort-btn:hover {
- background-color: #f5f7fa;
- border-radius: 2px;
- }
- .chart-container {
- min-height: 250px;
- height: 280px;
- position: relative;
- box-sizing: border-box;
- overflow: hidden;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
- }
- .table-container {
- flex: 1;
- border: 1px solid #E4E7ED;
- border-radius: 4px;
- }
- .table-container :deep(.el-table__body tr:nth-child(even)) {
- background-color: #F8F8F8;
- }
- .table-container :deep(.el-table__header th),
- .table-container :deep(.el-table__body td) {
- font-weight: 500;
- font-size: 13px;
- color: #333333;
- }
- .echarts-chart {
- width: 100% !important;
- height: 100% !important;
- min-height: 200px;
- display: block;
- }
- /* 加载状态样式 */
- .loading-container {
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- padding: 20px;
- background: white;
- border-radius: 8px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
- margin-bottom: 16px;
- color: #409EFF;
- font-size: 14px;
- }
- .loading-overlay {
- position: relative;
- }
- .loading-overlay::after {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(255, 255, 255, 0.7);
- border-radius: 8px;
- z-index: 10;
- }
- .loading-overlay::before {
- content: '';
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- width: 40px;
- height: 40px;
- border: 3px solid #f3f3f3;
- border-top: 3px solid #409EFF;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- z-index: 11;
- }
- @keyframes spin {
- 0% {
- transform: translate(-50%, -50%) rotate(0deg);
- }
- 100% {
- transform: translate(-50%, -50%) rotate(360deg);
- }
- }
- /* 响应式设计 */
- @media (max-width: 1200px) {
- .two-panel-layout {
- flex-direction: column;
- }
- }
- @media (max-width: 768px) {
- .performance-analysis {
- padding: 16px;
- }
- .header {
- flex-direction: column;
- gap: 16px;
- align-items: flex-start;
- }
- .header-right {
- align-self: flex-end;
- }
- .form-row {
- flex-direction: column;
- align-items: flex-start;
- }
- .form-content {
- flex-direction: column;
- align-items: flex-start;
- }
- }
- </style>
|