|
@@ -0,0 +1,1136 @@
|
|
|
+<template>
|
|
|
+ <div class="record-right" v-loading="loading">
|
|
|
+ <!-- 考核表详情 -->
|
|
|
+ <div class="title-container" style="height: 30px; justify-content: space-between;">
|
|
|
+ <div class="title flex-box-ce">
|
|
|
+ 考核详情
|
|
|
+ <div class="flex-box-ce" style="margin-left: 10px;">
|
|
|
+ <el-cascader ref="cascader" v-model="headValue" :options="options" :props="props"
|
|
|
+ :placeholder="placeholder" :no-data-text="noDataText"></el-cascader>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <!-- 正太规则 -->
|
|
|
+ <EditScoreList :scoreList="scoreList" @confirm="onConfrim" />
|
|
|
+
|
|
|
+ <el-button type="primary" @click="exportToExcel('mytable', '结果分析')">导出明细</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+
|
|
|
+ <div class="line"></div>
|
|
|
+
|
|
|
+ <div class="info-box">
|
|
|
+ <div style="width: 100%; display: flex;">
|
|
|
+ <div style="width: 50%; border-right: 1px solid #f1f1f1;">
|
|
|
+ <div style="font-size: 16px; font-weight: 600;">等级分布</div>
|
|
|
+ <div ref="echarts2" class="echarts"></div>
|
|
|
+ </div>
|
|
|
+ <div style="width: 50%; padding: 0 20px; box-sizing: border-box;">
|
|
|
+ <div style="font-size: 16px; font-weight: 600;">正态分布</div>
|
|
|
+ <!-- 考核人员分数列表 -->
|
|
|
+ <div class="score-list">
|
|
|
+ <div class="score-item heartBeat animated">
|
|
|
+ <div class="score-item-title">总人数</div>
|
|
|
+ <div class="score-item-num">{{ userTotal }}</div>
|
|
|
+ <div class="score-item-percent">{{ userComplete }}人已完成</div>
|
|
|
+ </div>
|
|
|
+ <div v-for="item in scoreList" class="score-item heartBeat animated">
|
|
|
+ <div class="score-item-title">{{ item.name }}</div>
|
|
|
+ <div class="score-item-num">{{users.filter(user => user.scoreResult === item.name).length}}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 考核人员列表 -->
|
|
|
+ <div class="title-container" style="margin: 10px 0;">
|
|
|
+ <div class="title">考核人员列表</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-select v-model="deptIds" clearable multiple placeholder="请选择部门"
|
|
|
+ style="width: 300px; margin-bottom: 10px;" @change="changeDeptName">
|
|
|
+ <el-option v-for="item in deptList" :key="item.id" :label="item.name" :value="item.id"></el-option>
|
|
|
+ </el-select>
|
|
|
+
|
|
|
+ <el-table v-if="filterUsers && filterUsers.length > 0" :data="filterUsers" style="width: 100%; "
|
|
|
+ :header-cell-style="{ background: '#f5f7fa' }" :max-height="600">
|
|
|
+ <el-table-column prop="employeeName" label="员工">
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+
|
|
|
+ <el-table-column prop="departments" label="部门" align="center" width="300">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tooltip class="item" effect="dark" placement="top">
|
|
|
+ <div slot="content" style="max-width: 300px; ">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ <div class="oneLine">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="status" label="考核状态">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.status" type="success">
|
|
|
+ 已完成
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else="scope.row.status" type="warning">
|
|
|
+ 进行中
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="level" label="评分">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.level === '未评分'" type="info">
|
|
|
+ 未评分
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else>
|
|
|
+ {{ scope.row.score }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="level" label="评级">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.level === '未评分'" type="info">
|
|
|
+ 未评级
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else>
|
|
|
+ {{ scope.row.level }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="scoreResult" label="正态分布">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag>
|
|
|
+ {{ scope.row.scoreResult }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="操作">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-link type="primary"
|
|
|
+ @click="getDetails(scope.row.reviewId, scope.row.employeeId)">查看详情</el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+
|
|
|
+ <!-- 指标列表 -->
|
|
|
+ <div class="title-container" style="margin: 10px 0;">
|
|
|
+ <div class="title">指标信息</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <el-tabs type="card" v-model="activeName" @tab-click="handleClick">
|
|
|
+ <el-tab-pane label="默认" name="1">
|
|
|
+ <el-table id="mytable" :data="filterTableData1" stripe style="width: 100%" border
|
|
|
+ :header-cell-style="{ background: '#f5f7fa' }" :max-height="600">
|
|
|
+ <el-table-column prop="employeeName" label="员工" align="center"></el-table-column>
|
|
|
+ <el-table-column prop="departments" label="部门" align="center" width="300">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tooltip class="item" effect="dark" placement="top">
|
|
|
+ <div slot="content" style="max-width: 300px; ">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ <div class="oneLine">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="title" label="指标" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tooltip class="item" effect="dark" placement="top">
|
|
|
+ <div v-html="scope.row.title" slot="content" style="max-width:300px"></div>
|
|
|
+ <div class="oneLine">{{ scope.row.title }}</div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="target" label="目标" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <span v-if="scope.row.target !== null">
|
|
|
+ {{ `${scope.row.target} ${scope.row.unit ? scope.row.unit : ''}` }}
|
|
|
+ </span>
|
|
|
+ <span v-else>--</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="result" label="实际值" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div>
|
|
|
+ <span v-if="scope.row.result !== null">
|
|
|
+ {{ `${scope.row.result} ${scope.row.unit ? scope.row.unit : ''}` }}
|
|
|
+ </span>
|
|
|
+ <span v-else>--</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="different" label="差距" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="scope.row.difference > 0" type="success">
|
|
|
+ {{ scope.row.difference }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else-if="scope.row.difference < 0" type="danger">
|
|
|
+ {{ scope.row.difference }}
|
|
|
+ </el-tag>
|
|
|
+ <div v-else>
|
|
|
+ --
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="score" label="评分" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div>
|
|
|
+ {{ scope.row.score || '--' }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="okrs" label="过程跟踪" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-link v-if="scope.row.okrs && scope.row.okrs.length > 0" type="primary"
|
|
|
+ @click="openTargetList(scope.row.okrs)">
|
|
|
+ 指标OKR
|
|
|
+ </el-link>
|
|
|
+ <span v-else class="fontColorC">暂无关联</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ <div style="height: 100px;"></div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="按指标/目标/单位聚合" name="2">
|
|
|
+ <el-table :data="filterTableData2" stripe style="width: 100%" border
|
|
|
+ :header-cell-style="{ background: '#f5f7fa' }" :max-height="600">
|
|
|
+ <el-table-column prop="departments" label="部门" align="center" width="300">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tooltip class="item" effect="dark" placement="top">
|
|
|
+ <div slot="content" style="max-width: 300px; ">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ <div class="oneLine">
|
|
|
+ {{ scope.row.departments | formatDeptName }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="title" label="指标" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tooltip class="item" effect="dark" placement="top">
|
|
|
+ <div v-html="scope.row.title" slot="content" style="max-width:300px"></div>
|
|
|
+ <div class="oneLine">{{ scope.row.title }}</div>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="target" label="目标" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <div>
|
|
|
+ <span v-if="scope.row.target !== null">
|
|
|
+ {{ `${scope.row.target} ${scope.row.unit ? scope.row.unit : ''}` }}
|
|
|
+ </span>
|
|
|
+ <span v-else>--</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="avgResult" label="均值" align="center">
|
|
|
+
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column prop="standardResultRate" label="超出目标比例" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="parseInt(scope.row.standardResultRate) > 0" type="success">
|
|
|
+ {{ scope.row.standardResultRate }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else-if="parseInt(scope.row.standardResultRate) < 0" type="danger">
|
|
|
+ {{ scope.row.standardResultRate }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else type="info">
|
|
|
+ {{ scope.row.standardResultRate }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="standardCount" label="达标数" align="center" />
|
|
|
+ <el-table-column prop="standardRate" label="达标率" align="center">
|
|
|
+ <template slot-scope="scope">
|
|
|
+ <el-tag v-if="parseInt(scope.row.standardRate) > 0" type="success">
|
|
|
+ {{ scope.row.standardRate }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else-if="parseInt(scope.row.standardRate) < 0" type="danger">
|
|
|
+ {{ scope.row.standardRate }}
|
|
|
+ </el-tag>
|
|
|
+ <el-tag v-else type="info">
|
|
|
+ {{ scope.row.standardRate }}
|
|
|
+ </el-tag>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column prop="avgScore" label="平均分" align="center" />
|
|
|
+ </el-table>
|
|
|
+ <div style="height: 100px;"></div>
|
|
|
+
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 关联okr -->
|
|
|
+ <TargetListComp v-if="targetDialogVisible" :dialogVisible="targetDialogVisible" :ids="okrs"
|
|
|
+ @close="closeTargetList">
|
|
|
+ </TargetListComp>
|
|
|
+
|
|
|
+ <!-- 员工绩效详情 -->
|
|
|
+ <el-dialog title="员工绩效详情" :visible.sync="detailDialogVisible" @close="handleClose" :close-on-click-modal="false"
|
|
|
+ :close-on-press-escape="true" center fullscreen :show-close="false">
|
|
|
+ <div style=" width: 100%; height: 100%; position: relative;">
|
|
|
+ <el-button round style="position: absolute; top: -65px; left: 0px; z-index: 99;"
|
|
|
+ @click="detailDialogVisible = false">返回</el-button>
|
|
|
+ <!-- 我的考核 -->
|
|
|
+ <MyPerformance v-if="detailDialogVisible" :reviewId="reviewId" :sendEmployeeId='sendEmployeeId' />
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+
|
|
|
+<script>
|
|
|
+let that;
|
|
|
+
|
|
|
+import { mapGetters } from 'vuex';
|
|
|
+import moment from 'moment';
|
|
|
+import _ from "lodash"
|
|
|
+import ECharts from 'echarts';
|
|
|
+import EditScoreList from './ExamineRecord/RightEamineComp/EditScoreList'
|
|
|
+import TargetListComp from "@/performance/views/assessManagement/TargetListComp.vue"; // 关联OKR弹框
|
|
|
+import MyPerformance from './MyPerformance'; // 我的考核
|
|
|
+import cloneDeep from 'lodash.clonedeep';
|
|
|
+import FileSaver from "file-saver";
|
|
|
+import XLSX from "xlsx";
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ EditScoreList,
|
|
|
+ TargetListComp,
|
|
|
+ MyPerformance
|
|
|
+ },
|
|
|
+
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ reviewPackageId: 0,
|
|
|
+ detailInfo: null,
|
|
|
+ year: '2025',
|
|
|
+ headValue: [],
|
|
|
+ options: [
|
|
|
+ { value: '4', label: '月度', leaf: false, children: [] },
|
|
|
+ { value: '3', label: '季度', leaf: false, children: [] },
|
|
|
+ { value: '2', label: '半年度', leaf: false, children: [] },
|
|
|
+ { value: '1', label: '年度', leaf: false, children: [] },
|
|
|
+ { value: '0', label: '未定义', leaf: false, children: [] },
|
|
|
+ ], //
|
|
|
+ props: {
|
|
|
+ value: 'value',
|
|
|
+ label: 'label',
|
|
|
+ children: 'children',
|
|
|
+ lazy: true,
|
|
|
+ lazyLoad(node, resolve) {
|
|
|
+ that.getAssessTree(node, resolve);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ total: 0,
|
|
|
+ loading: false,
|
|
|
+ tableData: [],
|
|
|
+ deptList: [], // 部门列表 - 树形结构
|
|
|
+ dept_list: [], // 部门列表
|
|
|
+ selected_dept_ids: [], // 选择的部门列表
|
|
|
+ placeholder: "",
|
|
|
+ chooseChildren: [],
|
|
|
+ noDataText: '暂无数据',
|
|
|
+ loading: false,
|
|
|
+ activeName: "1",
|
|
|
+ reviewPackageId: "",
|
|
|
+ title: "默认标题",
|
|
|
+ detailDialogVisible: false,
|
|
|
+ reviewId: '',
|
|
|
+ sendEmployeeId: "",
|
|
|
+ startTime: "",
|
|
|
+ endTime: "",
|
|
|
+ deptIds: [],
|
|
|
+ rank: "",
|
|
|
+ rankList: [],
|
|
|
+ deptList: [],
|
|
|
+ scoreList: [],
|
|
|
+ users: [], //考核人员列表
|
|
|
+ filterUsers: [],
|
|
|
+ tableData1: [], // 考核中的指标列表,
|
|
|
+ tableData2: [], // 按单位/目标/聚合指标列表,
|
|
|
+ filterTableData1: [],
|
|
|
+ filterTableData2: [],
|
|
|
+ distributionId: "",
|
|
|
+ level_enable: false,
|
|
|
+ packages: [],
|
|
|
+ userTotal: 0,
|
|
|
+ userComplete: 0,
|
|
|
+ userIncomplete: 0,
|
|
|
+ infos: [],
|
|
|
+ gradeLevels: [],
|
|
|
+ cateIds: [], // 选择的考核分类
|
|
|
+ targetDialogVisible: false,
|
|
|
+ okrs: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ detailInfo(v) {
|
|
|
+ this.initData();
|
|
|
+ },
|
|
|
+ deptName(v) {},
|
|
|
+ year(val) {
|
|
|
+ this.getRecords()
|
|
|
+ },
|
|
|
+ headValue(val) {
|
|
|
+ if (this.chooseChildren && this.chooseChildren.length > 0) {
|
|
|
+ let obj = this.chooseChildren.find(child => child.value == this.headValue[1])
|
|
|
+ if (obj) {
|
|
|
+ let value = ''
|
|
|
+ if (this.headValue[0] && this.headValue[0] == '0') value = "未定义 / "
|
|
|
+ if (this.headValue[0] && this.headValue[0] == '1') value = "年度 / "
|
|
|
+ if (this.headValue[0] && this.headValue[0] == '2') value = "半年度 / "
|
|
|
+ if (this.headValue[0] && this.headValue[0] == '3') value = "季度 / "
|
|
|
+ if (this.headValue[0] && this.headValue[0] == '4') value = "月度 / "
|
|
|
+ this.placeholder = obj.label || ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.getResultAnalyze()
|
|
|
+ },
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ ...mapGetters(['user_info']),
|
|
|
+ calcScoreList() {
|
|
|
+ let scoreSet = new Set(this.users.map(item => Number(item.score)))
|
|
|
+
|
|
|
+ let scores = [...scoreSet].sort((a, b) => b - a);
|
|
|
+ let rate = 1;
|
|
|
+ let scoreCount = scores.length; // 总人数
|
|
|
+ let scoreIndex = 0;
|
|
|
+ let scoreResult = {};
|
|
|
+
|
|
|
+ this.scoreList.forEach(item => {
|
|
|
+
|
|
|
+ let scale = item.scale / 100;
|
|
|
+ let count = Math.round((scoreCount - scoreIndex) * scale / rate);
|
|
|
+ rate -= scale;
|
|
|
+ if (count <= 0) return;
|
|
|
+
|
|
|
+ for (let i = scoreIndex; i < (scoreIndex + count); i++) {
|
|
|
+ scoreResult[scores[i]] = item.name;
|
|
|
+ }
|
|
|
+ scoreIndex += count;
|
|
|
+ });
|
|
|
+ return this.users.map(item => {
|
|
|
+ let result = { ...item };
|
|
|
+ result.scoreResult = scoreResult[item.score] || '--'
|
|
|
+ return result;
|
|
|
+ }).sort((a, b) => b.score - a.score);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ filters: {
|
|
|
+ formatDate(val) {
|
|
|
+ if (val) return moment(val).format('YYYY-MM-DD')
|
|
|
+ else return "--"
|
|
|
+ },
|
|
|
+ formatDeptName(val) {
|
|
|
+ let str = '';
|
|
|
+ if (val && val.length > 0) {
|
|
|
+ val.forEach(dept => {
|
|
|
+ str += dept.name + ","
|
|
|
+ })
|
|
|
+ str = str.substr(0, str.length - 1)
|
|
|
+ } else {
|
|
|
+ str = "--"
|
|
|
+ }
|
|
|
+ return str
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ if (this.detailInfo) this.initData();
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ that = this;
|
|
|
+ this.getRecords('4'); // 优先获取当月最新考核数据 递归周期类型,获取考核数据,优先按月,季,半年度,年度来调用
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+
|
|
|
+ exportToExcel(tableId, fileName) {
|
|
|
+ // exportToExcel(tableId, fileName)
|
|
|
+ this.downloadLoading = true
|
|
|
+ const xlsxParam = { raw: true };
|
|
|
+ const wb = XLSX.utils.table_to_book(document.getElementById(tableId), xlsxParam);
|
|
|
+
|
|
|
+ // 遍历工作表中的所有单元格,处理换行
|
|
|
+ const ws = wb.Sheets[wb.SheetNames[0]]; // 工作簿1
|
|
|
+ for (const cell in ws) {
|
|
|
+ if (ws[cell].v && typeof ws[cell].v === 'string') {
|
|
|
+ ws[cell].v = ws[cell].v.replace(/\n/g, '\n');
|
|
|
+ ws[cell].s = {
|
|
|
+ alignment: {
|
|
|
+ wrapText: true // 启用自动换行
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' });
|
|
|
+ try {
|
|
|
+ FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), fileName + '.xlsx');
|
|
|
+ } catch (e) {
|
|
|
+ console.error(e, wbout);
|
|
|
+ }
|
|
|
+ this.downloadLoading = false;
|
|
|
+ },
|
|
|
+
|
|
|
+ getAssessTree(node, resolve) {
|
|
|
+ if (this.options.length == 0) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const { value } = node;
|
|
|
+
|
|
|
+ this.chooseChildren = node.children // 用来回显选择的文本
|
|
|
+ node.children = []
|
|
|
+ let url = `/performance/statistics/cycle/info/${this.user_info.site_id}/${value}`
|
|
|
+ this.$axiosUser("get", url, {}).then(res => {
|
|
|
+ let { data: { data: { items, cycleType } } } = res
|
|
|
+ if (items && items.length > 0) {
|
|
|
+ items.forEach(item => {
|
|
|
+ item.leaf = true;
|
|
|
+ item.label = item.remark
|
|
|
+ })
|
|
|
+ resolve(items)
|
|
|
+ } else {
|
|
|
+ resolve([])
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }).finally(() => {
|
|
|
+ // this.tableDataLoad = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getRecords(cycle) {
|
|
|
+ if (cycle < 0) {
|
|
|
+ cycle = 0
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.loading = true
|
|
|
+ // 周期种类 0-未定义 1-年度 2-半年度 3-季度 4-月度
|
|
|
+ let url = `/performance/statistics/cycle/info/${this.user_info.site_id}/${cycle}`
|
|
|
+ this.$axiosUser("get", url, {}).then(res => {
|
|
|
+ this.loading = false;
|
|
|
+ let { data: { data: { items, cycleType } } } = res
|
|
|
+ if (items && items.length > 0) {
|
|
|
+ items.forEach(item => {
|
|
|
+ item.leaf = true
|
|
|
+ item.label = item.remark
|
|
|
+ })
|
|
|
+ let index = parseInt(4 - cycle)
|
|
|
+ this.options[index].children = items
|
|
|
+
|
|
|
+ this.headValue = [cycle + '', this.options[index].children[[0]].value]
|
|
|
+ // if (this.headValue[1]) this.placeholder = this.options[parseInt(cycle)].children[[0]].label || ''
|
|
|
+ } else {
|
|
|
+ this.getRecords(parseInt(cycle) - 1) // 递归周期类型,获取考核数据,优先按月,季,半年度,年度来调用
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ getResultAnalyze() {
|
|
|
+ this.reviewPackageId = 0
|
|
|
+ let url = `/performance/statistics/cycle/${this.user_info.site_id}/${this.headValue[0]}`
|
|
|
+ if (!this.headValue[1]) return
|
|
|
+ this.$axiosUser("get", url, { value: this.headValue[1] }).then(res => {
|
|
|
+ this.detailInfo = res.data.data
|
|
|
+ this.reviewPackageId = 1
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ // 关闭绩效弹框回调事件
|
|
|
+ handleClose() { },
|
|
|
+
|
|
|
+ changeDeptName(v) {
|
|
|
+ this.filterUsers = this.users.filter((item) => {
|
|
|
+ const departmentMatch = this.deptIds.length === 0 || this.deptIds.some((depId) => item.departments.some(dep => dep.id == depId));
|
|
|
+ return departmentMatch;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.filterTableData1 = this.tableData1.filter((item) => {
|
|
|
+ const departmentMatch = this.deptIds.length === 0 || this.deptIds.some((depId) => item.departments.some(dep => dep.id == depId));
|
|
|
+ return departmentMatch;
|
|
|
+ });
|
|
|
+
|
|
|
+ this.filterTableData2 = this.tableData2.filter((item) => {
|
|
|
+ const departmentMatch = this.deptIds.length === 0 || this.deptIds.some((depId) => item.departments.some(dep => dep.id == depId));
|
|
|
+ return departmentMatch;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ async initData() {
|
|
|
+ this.loading = true
|
|
|
+ this.activeName = '1'
|
|
|
+ this.deptIds = [];
|
|
|
+ this.deptList = [];
|
|
|
+ this.users = [];
|
|
|
+ this.filterUsers = [];
|
|
|
+ this.isShow = false
|
|
|
+ this.tableData1 = [];
|
|
|
+ this.tableData2 = [];
|
|
|
+ this.filterTableData1 = [];
|
|
|
+ this.filterTableData2 = [];
|
|
|
+ let { indicators, startTime, endTime, distribution: { items }, users } = this.detailInfo
|
|
|
+ await this.getAllSet();
|
|
|
+ this.tableData1 = [];
|
|
|
+ this.tableData2 = [];
|
|
|
+ this.startTime = startTime;
|
|
|
+ this.endTime = endTime;
|
|
|
+ this.scoreList = items;
|
|
|
+ this.distributionId = this.scoreList[0].id
|
|
|
+ this.users = users;
|
|
|
+ this.tableData1 = indicators;
|
|
|
+ this.tableData1.forEach(item => {
|
|
|
+ this.users.forEach(user => {
|
|
|
+ if (user.employeeId == item.employeeId) {
|
|
|
+ item.departments = user.departments
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (item.target && item.result) {
|
|
|
+ item.difference = item.result - item.target
|
|
|
+ } else {
|
|
|
+ item.difference = '--'
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.filterTableData1 = this.tableData1
|
|
|
+ this.userTotal = 0;
|
|
|
+ this.userComplete = 0;
|
|
|
+ this.userIncomplete = 0;
|
|
|
+ let distribution = [];
|
|
|
+ let userScores = []
|
|
|
+ this.scoreList.forEach(item => {
|
|
|
+ item.level = item.name;
|
|
|
+ item.ratio = item.scale / 100
|
|
|
+ distribution.push(item)
|
|
|
+ })
|
|
|
+
|
|
|
+ if (this.users && this.users.length > 0) {
|
|
|
+ this.users.forEach(user => {
|
|
|
+ this.userTotal++;
|
|
|
+ this.userComplete += user.status === 1 ? 1 : 0;
|
|
|
+ user.level = this.findGrade(user.score, this.gradeLevels);
|
|
|
+ // this.rankList.push(user.level || '未评分')
|
|
|
+ userScores.push(user.score)
|
|
|
+ })
|
|
|
+ this.infos = [
|
|
|
+ { label: "总人数", num: this.userTotal },
|
|
|
+ { label: "已完成", num: this.userComplete },
|
|
|
+ { label: "未评分", num: this.userIncomplete },
|
|
|
+ ]
|
|
|
+ let scoreResult = this.assignLevels(userScores, distribution);
|
|
|
+
|
|
|
+ this.users.forEach(item => {
|
|
|
+ scoreResult.forEach(result => {
|
|
|
+ if (result.scores.includes(item.score)) {
|
|
|
+ item.scoreResult = result.level
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.isShow = true
|
|
|
+ this.filterUsers = cloneDeep(this.users)
|
|
|
+ this.initDeptList();
|
|
|
+ this.getResult();
|
|
|
+ }
|
|
|
+
|
|
|
+ this.loading = false
|
|
|
+ },
|
|
|
+
|
|
|
+ initDeptList() {
|
|
|
+ if (this.users && this.users.length > 0) {
|
|
|
+ this.users.forEach(user => {
|
|
|
+ if (user.departments && user.departments.length > 0) {
|
|
|
+ user.departments.forEach(dep => {
|
|
|
+ this.deptList.push({ id: dep.id, name: dep.name })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.deptList = Array.from(new Set(this.deptList.map(JSON.stringify))).map(JSON.parse);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ getResult() {
|
|
|
+ let xData = [], yData = []
|
|
|
+ this.gradeLevels.forEach(item => {
|
|
|
+ xData.push(item.name)
|
|
|
+ yData.push(this.users.filter(user => user.level === item.name).length)
|
|
|
+ })
|
|
|
+ let option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'axis',
|
|
|
+ axisPointer: {
|
|
|
+ // 坐标轴指示器,坐标轴触发有效
|
|
|
+ type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ xAxis: {
|
|
|
+ type: 'category',
|
|
|
+ data: xData
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ type: 'value',
|
|
|
+ minInterval: 1
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ data: yData,
|
|
|
+ type: 'bar',
|
|
|
+ itemStyle: {
|
|
|
+ normal: {
|
|
|
+ //这里是重点
|
|
|
+ color: function (params) {
|
|
|
+ //注意,如果颜色太少的话,后面颜色不会自动循环,最好多定义几个颜色
|
|
|
+ var colorList = ['#409EFF', '#4ECB73', '#36CBCB', '#F2637B', '#FBD437', '#749f83', '#ca8622'];
|
|
|
+ var index;
|
|
|
+ //给大于颜色数量的柱体添加循环颜色的判断
|
|
|
+ if (params.dataIndex >= colorList.length) {
|
|
|
+ index = params.dataIndex - colorList.length;
|
|
|
+ return colorList[index];
|
|
|
+ }
|
|
|
+ return colorList[params.dataIndex];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ barMaxWidth: 30
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ var myChart = ECharts.init(this.$refs.echarts2);
|
|
|
+ myChart.setOption(option);
|
|
|
+ window.onresize = myChart.resize;
|
|
|
+ },
|
|
|
+
|
|
|
+ getDetails(reviewId, employeeId) {
|
|
|
+ this.reviewId = reviewId
|
|
|
+ this.sendEmployeeId = employeeId
|
|
|
+ this.detailDialogVisible = true
|
|
|
+ // this.$bus.$emit('changeCurrentId', { currentId: '2', reviewId, employeeId })
|
|
|
+ },
|
|
|
+ changeCateIds(cateIds) {
|
|
|
+ this.cateIds = cateIds
|
|
|
+ this.$bus.$emit("finishEdit", this.reviewPackageId)
|
|
|
+ },
|
|
|
+ changeTitle(title) {
|
|
|
+ this.title = title;
|
|
|
+ this.$bus.$emit("finishEdit", this.reviewPackageId)
|
|
|
+ },
|
|
|
+
|
|
|
+ changeDate(data) {
|
|
|
+ let { startTime, endTime } = data
|
|
|
+ this.startTime = startTime
|
|
|
+ this.endTime = endTime
|
|
|
+ this.$bus.$emit("finishEdit", this.reviewPackageId)
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 获取全局等级设置
|
|
|
+ async getAllSet() {
|
|
|
+ let res = await this.$axiosUser('get', 'api/pro/per/user/base_config')
|
|
|
+ let data = res.data.data;
|
|
|
+ let levels = data.level_scope.levels;
|
|
|
+ let gradeLevels = [];
|
|
|
+ let max = 0;//最大值
|
|
|
+ if (levels && levels.length > 0) {
|
|
|
+ levels.forEach((item, index) => {
|
|
|
+ var obj;
|
|
|
+ if (index == 0) {
|
|
|
+ obj = { name: item.name, max: Number(item.value), min: 0 };
|
|
|
+ } else {
|
|
|
+ obj = { name: item.name, max: Number(item.value), min: max };//当不是第一个等级时,最小值为上一个的最大值
|
|
|
+ }
|
|
|
+ max = item.value;
|
|
|
+ gradeLevels.push(obj);
|
|
|
+ })
|
|
|
+ this.gradeLevels = gradeLevels
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 查找分数对应的等级
|
|
|
+ findGrade(score, gradeLevels) {
|
|
|
+ for (let i = 0; i < gradeLevels.length; i++) {
|
|
|
+ if (score && score >= gradeLevels[i].min && score && score <= gradeLevels[i].max) {
|
|
|
+ return gradeLevels[i].name; // 返回对应的等级描述
|
|
|
+ } else if (score && score <= gradeLevels[0].min) {
|
|
|
+ return gradeLevels[0].name; // 返回对应的等级描述
|
|
|
+ } else if (score && score >= gradeLevels[gradeLevels.length - 1].max) {
|
|
|
+ return gradeLevels[gradeLevels.length - 1].name; // 返回对应的等级描述
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "未评分"; // 如果分数不在任何范围内
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ assignLevels(scores, levelConfigs) {
|
|
|
+ // 降序排序并去重(假设分数不重复,可省略去重)
|
|
|
+ const sortedScores = [...scores].sort((a, b) => b - a);
|
|
|
+ const total = sortedScores.length;
|
|
|
+ if (total === 0) return [];
|
|
|
+
|
|
|
+ // 归一化处理比例
|
|
|
+ const totalRatio = levelConfigs.reduce((sum, cfg) => sum + cfg.ratio, 0);
|
|
|
+ const normalized = levelConfigs.map(cfg => cfg.ratio / totalRatio);
|
|
|
+
|
|
|
+ // 计算每个等级的初始人数
|
|
|
+ let counts = normalized.map(ratio => Math.floor(total * ratio));
|
|
|
+ let remainder = total - counts.reduce((sum, c) => sum + c, 0);
|
|
|
+
|
|
|
+ // 分配剩余人数,按优先级顺序
|
|
|
+ let idx = 0;
|
|
|
+ while (remainder > 0 && idx < counts.length) {
|
|
|
+ counts[idx]++;
|
|
|
+ remainder--;
|
|
|
+ idx++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 构建结果:按人数切割数组
|
|
|
+ let start = 0;
|
|
|
+ return counts.map((count, i) => {
|
|
|
+ const end = start + count;
|
|
|
+ const levelScores = sortedScores.slice(start, end);
|
|
|
+ start = end;
|
|
|
+ return {
|
|
|
+ level: levelConfigs[i].level,
|
|
|
+ scores: levelScores
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ onConfrim(items) {
|
|
|
+ if (!(items && items.length > 0)) return
|
|
|
+ this.userTotal = 0;
|
|
|
+ this.userComplete = 0;
|
|
|
+ this.userIncomplete = 0;
|
|
|
+ let distribution = [];
|
|
|
+ let userScores = []
|
|
|
+ this.filterUsers = []
|
|
|
+ this.loading = true
|
|
|
+ this.scoreList = items
|
|
|
+ this.scoreList.forEach(item => {
|
|
|
+ item.level = item.name;
|
|
|
+ item.ratio = item.scale / 100
|
|
|
+ distribution.push(item)
|
|
|
+ })
|
|
|
+
|
|
|
+ if (this.users && this.users.length > 0) {
|
|
|
+ this.users.forEach(user => {
|
|
|
+ this.userTotal++;
|
|
|
+ this.userComplete += user.status === 1 ? 1 : 0;
|
|
|
+ user.level = this.findGrade(user.score, this.gradeLevels);
|
|
|
+ // this.rankList.push(user.level || '未评分')
|
|
|
+ userScores.push(user.score)
|
|
|
+ })
|
|
|
+ this.infos = [
|
|
|
+ { label: "总人数", num: this.userTotal },
|
|
|
+ { label: "已完成", num: this.userComplete },
|
|
|
+ { label: "未评分", num: this.userIncomplete },
|
|
|
+ ]
|
|
|
+ let scoreResult = this.assignLevels(userScores, distribution);
|
|
|
+
|
|
|
+ this.users.forEach(item => {
|
|
|
+ scoreResult.forEach(result => {
|
|
|
+ if (result.scores.includes(item.score)) {
|
|
|
+ item.scoreResult = result.level
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ this.filterUsers = cloneDeep(this.users)
|
|
|
+ this.loading = false
|
|
|
+ console.log(this.filterUsers);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 选项卡点击事件
|
|
|
+ handleClick(tab, event) {
|
|
|
+ this.tableData2 = []
|
|
|
+ if (this.activeName == 2) {
|
|
|
+ let groups = _.groupBy(this.tableData1, item => `${item.title}(_)${item.target === null || item.target === '' ? 'null' : item.target}(_)${item.unit === null || item.unit === '' ? 'null' : item.unit}`);
|
|
|
+ Object.keys(groups).forEach(key => {
|
|
|
+ let group = {
|
|
|
+ title: '',
|
|
|
+ target: '',
|
|
|
+ unit: '',
|
|
|
+ departments: [],
|
|
|
+ userCount: 0,
|
|
|
+ scoredCount: 0,
|
|
|
+ standardCount: 0,
|
|
|
+ failCount: 0,
|
|
|
+ standardRate: '--',
|
|
|
+ totalScore: 0,
|
|
|
+ totalResult: 0,
|
|
|
+ avgScore: 0,
|
|
|
+ avgResult: 0,
|
|
|
+ standardResultRate: '--'
|
|
|
+ };
|
|
|
+ groups[key].forEach(indicator => {
|
|
|
+ group.title = indicator.title; // 指标名称
|
|
|
+ group.target = indicator.target; // 目标
|
|
|
+ group.unit = indicator.unit; // 单位
|
|
|
+ group.departments = indicator.departments; // 单位
|
|
|
+ let standardCount = indicator.difference !== '--' && indicator.difference >= 0 ? 1 : 0; //
|
|
|
+ group.userCount += 1;
|
|
|
+ group.scoredCount += indicator.score !== null ? 1 : 0;
|
|
|
+ group.standardCount += standardCount;
|
|
|
+ group.failCount += standardCount === 1 ? 0 : 1;
|
|
|
+ if (indicator.score !== null) group.totalScore += indicator.score;
|
|
|
+ if (indicator.result !== null) group.totalResult += indicator.result;
|
|
|
+ });
|
|
|
+ group.standardCount = group.standardCount;
|
|
|
+ if (group.userCount > 0) {
|
|
|
+ let rate = Math.floor(group.standardCount / group.userCount * 100 * 0.01);
|
|
|
+ let avgScore = Math.floor(group.totalScore / group.userCount * 100 * 0.01);
|
|
|
+ let avgResult = Math.floor(group.totalResult / group.userCount * 100 * 0.01);
|
|
|
+ group.standardRate = rate > 0 ? `${rate}%` : '--';
|
|
|
+ group.avgScore = avgScore !== 0 ? avgScore : '--';
|
|
|
+ group.avgResult = avgResult !== 0 ? avgResult : '--';
|
|
|
+
|
|
|
+ if (group.target !== null && group.avgResult !== '--') {
|
|
|
+ let standardResultRate = Math.floor((group.avgResult - group.target) / group.target * 100 * 0.01 * 100);
|
|
|
+ group.standardResultRate = standardResultRate !== 0 ? `${standardResultRate}%` : '--';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.tableData2.push(group);
|
|
|
+ this.filterTableData2 = this.tableData2
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ closeTargetList() {
|
|
|
+ this.targetDialogVisible = false
|
|
|
+ },
|
|
|
+
|
|
|
+ openTargetList(okrs) {
|
|
|
+ if (okrs && okrs.length > 0) {
|
|
|
+ this.okrs = okrs
|
|
|
+ this.targetDialogVisible = true
|
|
|
+ } else {
|
|
|
+ return this.$message.error("暂无关联okr")
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.oneLine {
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+
|
|
|
+<style scoped="scoped" lang="scss">
|
|
|
+.record-right {
|
|
|
+ width: 100%;
|
|
|
+ border-radius: 5px;
|
|
|
+ background: #fff;
|
|
|
+ padding: 10px 20px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+ .info-box {
|
|
|
+ width: 100%;
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ /* 设置滚动条的宽度和背景色 */
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块的样式 */
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ border-radius: 6px;
|
|
|
+ background-color: #c1c1c1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块hover样式 */
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
+ background-color: #a8a8a8;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条轨道的样式 */
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
+ box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
|
|
|
+ border-radius: 6px;
|
|
|
+ background: #ededed;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ .echarts {
|
|
|
+ height: 350px;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ .title-container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .searchBox {
|
|
|
+ width: 300px;
|
|
|
+
|
|
|
+ .search-title {
|
|
|
+ border-bottom: 1px solid #f1f1f1;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ padding: 0 10px;
|
|
|
+ padding-bottom: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-weight: 700;
|
|
|
+ font-size: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .line {
|
|
|
+ width: 100%;
|
|
|
+ height: 1px;
|
|
|
+ background: #f1f1f1;
|
|
|
+ margin: 10px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .score-list {
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 20px;
|
|
|
+
|
|
|
+ .score-item {
|
|
|
+ flex: 0 0 calc((100% - 100px) / 4);
|
|
|
+ height: 100px;
|
|
|
+ padding: 10px;
|
|
|
+ margin: 0 20px 20px 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-radius: 6px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-around;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #999;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
|
|
|
+
|
|
|
+ &-title {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #409EFF;
|
|
|
+ }
|
|
|
+
|
|
|
+ &-num {
|
|
|
+ color: #000;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:nth-child(5n) {
|
|
|
+ /* 去除第5n个的margin-right */
|
|
|
+ margin-right: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条的宽度和背景色 */
|
|
|
+ ::v-deep .el-table__body-wrapper::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+ height: 6px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块的样式 */
|
|
|
+ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb {
|
|
|
+ border-radius: 6px;
|
|
|
+ background-color: #c1c1c1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块hover样式 */
|
|
|
+ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb:hover {
|
|
|
+ background-color: #a8a8a8;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条轨道的样式 */
|
|
|
+ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {
|
|
|
+ box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
|
|
|
+ border-radius: 6px;
|
|
|
+ background: #ededed;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .user-info {
|
|
|
+ width: 100%;
|
|
|
+ height: 200px;
|
|
|
+ overflow: hidden;
|
|
|
+ overflow-x: auto;
|
|
|
+
|
|
|
+ /* 设置滚动条的宽度和背景色 */
|
|
|
+ &::-webkit-scrollbar {
|
|
|
+ width: 10px;
|
|
|
+ height: 10px;
|
|
|
+ background-color: #f9f9f9;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块的样式 */
|
|
|
+ &::-webkit-scrollbar-thumb {
|
|
|
+ border-radius: 6px;
|
|
|
+ background-color: #c1c1c1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条滑块hover样式 */
|
|
|
+ &::-webkit-scrollbar-thumb:hover {
|
|
|
+ background-color: #a8a8a8;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 设置滚动条轨道的样式 */
|
|
|
+ &::-webkit-scrollbar-track {
|
|
|
+ box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1);
|
|
|
+ border-radius: 6px;
|
|
|
+ background: #ededed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .info-card {
|
|
|
+ width: 220px;
|
|
|
+ height: 100%;
|
|
|
+ margin-right: 20px;
|
|
|
+ border: 1px solid #f1f1f1;
|
|
|
+ padding: 5px 10px;
|
|
|
+ border-radius: 6px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
|
|
|
+
|
|
|
+ .info {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ height: 36px;
|
|
|
+
|
|
|
+ .info-label {
|
|
|
+ width: 100px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|