rpa机器人
This commit is contained in:
parent
ae798bf252
commit
5dee166b6f
|
|
@ -0,0 +1,36 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询持证类型树
|
||||
export function getTreeDataType(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getTreeDataType',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询公司工程树
|
||||
export function getTreeDataPro(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getTreeDataPro',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询持证统计列表
|
||||
export function listProjects(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getCertificateTypeList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 获取工种下拉列表
|
||||
export const getPostTypeSelectListAPI = () => {
|
||||
return request({
|
||||
url: '/bmw/postType/listAll',
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询持证类型树
|
||||
export function getCategoryChartAPI(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getCategoryChart',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询公司工程树
|
||||
export function getStatusChartAPI(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getStatusChart',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询持证统计列表
|
||||
export function getCertificateWarningListAPI(query) {
|
||||
return request({
|
||||
url: '/bmw/certificateStatistics/getCertificateWarningList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 558 B |
Binary file not shown.
|
After Width: | Height: | Size: 508 B |
Binary file not shown.
|
After Width: | Height: | Size: 561 B |
|
|
@ -0,0 +1,517 @@
|
|||
<template>
|
||||
<div class="app-container" style="display: flex;">
|
||||
<!-- 左侧树形导航 -->
|
||||
<div class="sidebar">
|
||||
<!-- 树类型切换标签 -->
|
||||
<div class="tree-tabs">
|
||||
<div
|
||||
:class="['tab-item', { active: activeTreeType === 'certificate' }]"
|
||||
@click="switchTreeType('certificate')"
|
||||
>
|
||||
持证类型
|
||||
</div>
|
||||
<div
|
||||
:class="['tab-item', { active: activeTreeType === 'project' }]"
|
||||
@click="switchTreeType('project')"
|
||||
>
|
||||
公司工程
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 树搜索 -->
|
||||
<div class="tree-search">
|
||||
<el-input
|
||||
v-model="treeSearchKeyword"
|
||||
placeholder="请输入关键字"
|
||||
size="small"
|
||||
clearable
|
||||
>
|
||||
<el-button
|
||||
slot="append"
|
||||
icon="el-icon-search"
|
||||
@click="handleTreeSearch"
|
||||
>
|
||||
搜索
|
||||
</el-button>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<!-- 树形控件 -->
|
||||
<div class="tree-container">
|
||||
<el-tree
|
||||
v-if="activeTreeType === 'certificate'"
|
||||
ref="certificateTree"
|
||||
:data="certificateTreeData"
|
||||
:props="treeProps"
|
||||
:default-expand-all="false"
|
||||
:expand-on-click-node="false"
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
@node-click="handleTreeNodeClick"
|
||||
>
|
||||
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||||
<span>{{ data.title }}</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
|
||||
<el-tree
|
||||
v-if="activeTreeType === 'project'"
|
||||
ref="projectTree"
|
||||
:data="projectTreeData"
|
||||
:props="treeProps"
|
||||
:default-expand-all="false"
|
||||
:expand-on-click-node="false"
|
||||
:filter-node-method="filterNode"
|
||||
node-key="id"
|
||||
@node-click="handleTreeNodeClick"
|
||||
>
|
||||
<span class="custom-tree-node" slot-scope="{ node, data }">
|
||||
<span>{{ data.title }}</span>
|
||||
</span>
|
||||
</el-tree>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧内容区 -->
|
||||
<div class="main-content">
|
||||
<!-- 搜索表单 -->
|
||||
|
||||
<el-form :inline="true" :model="searchForm" size="small">
|
||||
<el-form-item label="关键字">
|
||||
<el-input
|
||||
v-model="searchForm.keyword"
|
||||
placeholder="姓名/身份证号"
|
||||
clearable
|
||||
style="width: 200px;"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="岗位类型">
|
||||
<el-select v-model="searchForm.postId" placeholder="请选择" clearable style="width: 150px;">
|
||||
<el-option v-for="dict in postTypeList" :key="dict.id" :label="dict.postName"
|
||||
:value="dict.id"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="证书状态">
|
||||
<el-select v-model="searchForm.certificateState" placeholder="请选择" clearable style="width: 150px;">
|
||||
<el-option label="--证件状态--" value=""/>
|
||||
<el-option label="有效" value="1"/>
|
||||
<el-option label="失效" value="2"/>
|
||||
<el-option label="复审临期(3个月)" value="3"/>
|
||||
<el-option label="复审临期(1个月)" value="4"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="在职状态">
|
||||
<el-select v-model="searchForm.onState" placeholder="请选择" clearable style="width: 150px;">
|
||||
<el-option label="全部" value=""/>
|
||||
<el-option label="在职" value="1"/>
|
||||
<el-option label="离职" value="2"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
|
||||
<el-button icon="el-icon-refresh-left" @click="handleReset">重置</el-button>
|
||||
<el-button type="success" icon="el-icon-download" @click="handleExport">导出</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="tableData"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" fixed="left" />
|
||||
<el-table-column prop="username" label="姓名" width="100" align="center" fixed="left" />
|
||||
<el-table-column prop="idNumber" label="身份证号" width="220" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.showFullId ? scope.row.idNumber : maskIdNumber(scope.row.idNumber) }}</span>
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
:icon="scope.row.showFullId ? 'el-icon-view' : 'el-icon-view'"
|
||||
@click="toggleIdVisibility(scope.row)"
|
||||
style="margin-left: 5px;"
|
||||
>
|
||||
{{ scope.row.showFullId ? '隐藏' : '显示' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="phone" label="手机号" width="140" align="center"/>
|
||||
<el-table-column prop="postName" label="工种" width="120" align="center"/>
|
||||
<el-table-column prop="einTime" label="进场时间" width="160" align="center"/>
|
||||
<el-table-column prop="exitTime" label="退场时间" width="160" align="center"/>
|
||||
<el-table-column prop="workType" label="持证类别" width="110" align="center"/>
|
||||
<el-table-column prop="workOperation" label="操作项目" width="150" align="center"/>
|
||||
<el-table-column prop="reviewDate" label="应复审日期" min-width="150" align="center"/>
|
||||
<el-table-column label="证件状态" min-width="150" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span
|
||||
:style="{ color: getStatusColor(scope.row.validStartDate, scope.row.validEndDate) }"
|
||||
>
|
||||
{{ getCertificateStatus(scope.row.validStartDate, scope.row.validEndDate) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="证件有效期" min-width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>
|
||||
{{ formatDateRange(scope.row.validStartDate, scope.row.validEndDate) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="issuingAuthority" label="签发机关" min-width="150" align="center"/>
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
v-if="scope.row.certificatePhoto && scope.row.certificatePhoto !== 'null' && scope.row.certificatePhoto !== ''"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="handleView(scope.row)"
|
||||
>
|
||||
查看详情
|
||||
</el-button>
|
||||
<span v-else style="color: #999;">暂无数据</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="searchForm.pageNum"
|
||||
:limit.sync="searchForm.pageSize"
|
||||
@pagination="loadTableData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getTreeDataType, getTreeDataPro, listProjects,getPostTypeSelectListAPI} from "@/api/rpa/statistics";
|
||||
|
||||
export default {
|
||||
name: 'CertificateStatisticsList',
|
||||
dicts: ['rpa_robot'],
|
||||
data() {
|
||||
return {
|
||||
// 树类型:certificate-持证类型,project-公司工程
|
||||
activeTreeType: 'certificate',
|
||||
|
||||
// 树搜索关键字
|
||||
treeSearchKeyword: '',
|
||||
|
||||
// 树配置
|
||||
treeProps: {
|
||||
children: 'children',
|
||||
label: 'title'
|
||||
},
|
||||
|
||||
// 持证类型树数据
|
||||
certificateTreeData: [],
|
||||
|
||||
// 公司工程树数据
|
||||
projectTreeData: [],
|
||||
|
||||
// 当前选中的树节点
|
||||
selectedTreeNode: null,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 搜索表单
|
||||
searchForm: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keyword: '',
|
||||
postId: '',
|
||||
certificateState: '',
|
||||
onState: '',
|
||||
name:'',
|
||||
proId:'',
|
||||
subComId:'',
|
||||
},
|
||||
|
||||
// 表格数据
|
||||
tableData: [],
|
||||
|
||||
// 加载状态
|
||||
loading: false,
|
||||
postTypeList:[],
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// 初始化加载树数据和表格数据
|
||||
this.loadCertificateTreeData()
|
||||
this.loadProjectTreeData()
|
||||
this.loadTableData()
|
||||
this.loadPostTypeList();
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
loadPostTypeList() {
|
||||
getPostTypeSelectListAPI().then(response => {
|
||||
this.postTypeList = response.rows
|
||||
})
|
||||
},
|
||||
|
||||
// 切换树类型
|
||||
switchTreeType(type) {
|
||||
this.activeTreeType = type
|
||||
this.treeSearchKeyword = ''
|
||||
this.selectedTreeNode = null
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 树搜索
|
||||
handleTreeSearch() {
|
||||
const tree = this.activeTreeType === 'certificate'
|
||||
? this.$refs.certificateTree
|
||||
: this.$refs.projectTree
|
||||
|
||||
if (tree) {
|
||||
tree.filter(this.treeSearchKeyword)
|
||||
}
|
||||
},
|
||||
|
||||
// 树节点过滤方法
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.title.indexOf(value) !== -1
|
||||
},
|
||||
|
||||
// 加载持证类型树数据
|
||||
loadCertificateTreeData() {
|
||||
// 模拟证书类型树数据
|
||||
getTreeDataType().then(response => {
|
||||
this.certificateTreeData = response
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
// 加载持证类型树数据
|
||||
loadProjectTreeData() {
|
||||
// 模拟证书类型树数据
|
||||
getTreeDataPro().then(response => {
|
||||
this.projectTreeData = response
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
// 树节点点击
|
||||
handleTreeNodeClick(data) {
|
||||
this.selectedTreeNode = data
|
||||
console.log("selectedTreeNode",this.selectedTreeNode)
|
||||
this.searchForm.name = data.name;
|
||||
if(data.nodeType ==2){
|
||||
this.searchForm.subComId = data.id;
|
||||
this.searchForm.proId = '';
|
||||
}
|
||||
|
||||
if(data.nodeType ==3){
|
||||
this.searchForm.proId = data.id;
|
||||
this.searchForm.subComId = '';
|
||||
}
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 加载表格数据
|
||||
loadTableData() {
|
||||
this.loading = true
|
||||
listProjects(this.searchForm).then((response) => {
|
||||
this.tableData = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 查询
|
||||
handleSearch() {
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 重置
|
||||
handleReset() {
|
||||
this.searchForm = {
|
||||
keyword: '',
|
||||
postId: '',
|
||||
certificateState: '',
|
||||
onState: '',
|
||||
name:'',
|
||||
proId:'',
|
||||
subComId:'',
|
||||
}
|
||||
this.loadTableData()
|
||||
},
|
||||
|
||||
// 导出
|
||||
handleExport() {
|
||||
this.download(
|
||||
'bmw/certificateStatistics/exportOwnData',
|
||||
{
|
||||
...this.searchForm,
|
||||
},
|
||||
`rpa持证统计_${new Date().getTime()}.xlsx`,
|
||||
)
|
||||
},
|
||||
|
||||
// 身份证号脱敏
|
||||
maskIdNumber(idNumber) {
|
||||
if (!idNumber || idNumber.length < 8) return idNumber
|
||||
return idNumber.substring(0, 6) + '********' + idNumber.substring(14)
|
||||
},
|
||||
|
||||
// 切换身份证显示/隐藏
|
||||
toggleIdVisibility(row) {
|
||||
this.$set(row, 'showFullId', !row.showFullId)
|
||||
},
|
||||
|
||||
// 获取当前时间字符串(年-月-日 时:分:秒)
|
||||
getCurrentDateTime() {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = now.getDate().toString().padStart(2, '0');
|
||||
const hours = now.getHours().toString().padStart(2, '0');
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = now.getSeconds().toString().padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
},
|
||||
|
||||
// 比较两个日期大小
|
||||
compare(time1, time2) {
|
||||
if (!time1 || !time2) return -1;
|
||||
const t1 = new Date(time1).getTime();
|
||||
const t2 = new Date(time2).getTime();
|
||||
if (t1 > t2) return 0;
|
||||
if (t1 < t2) return 1;
|
||||
return 2;
|
||||
},
|
||||
|
||||
// 判断证件状态
|
||||
getCertificateStatus(startDate, endDate) {
|
||||
const now = this.getCurrentDateTime();
|
||||
const time1 = this.compare(now, startDate); // now > start?
|
||||
const time2 = this.compare(now, endDate); // now < end?
|
||||
|
||||
if (time1 === 0 && time2 === 1) {
|
||||
return '有效';
|
||||
}
|
||||
return '失效';
|
||||
},
|
||||
|
||||
// 设置颜色
|
||||
getStatusColor(startDate, endDate) {
|
||||
const status = this.getCertificateStatus(startDate, endDate);
|
||||
return status === '有效' ? 'green' : '#757575';
|
||||
},
|
||||
|
||||
// 格式化有效期区间
|
||||
formatDateRange(start, end) {
|
||||
const format = (dateStr) => {
|
||||
if (!dateStr || dateStr === 'null') return '';
|
||||
// 只取日期部分(去掉时间)
|
||||
return dateStr.split(' ')[0];
|
||||
};
|
||||
const s = format(start);
|
||||
const e = format(end);
|
||||
return `${s} ~ ${e}`;
|
||||
},
|
||||
|
||||
// 查看详情
|
||||
handleView(row) {
|
||||
const url = '/data/' + certificatePhoto
|
||||
window.open(url)
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background-color: #fff;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tree-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
flex: 1;
|
||||
padding: 12px 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
background-color: #fafafa;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tab-item:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
color: #409eff;
|
||||
background-color: #fff;
|
||||
font-weight: 500;
|
||||
border-bottom: 2px solid #409eff;
|
||||
}
|
||||
|
||||
.tree-search {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
padding-left: 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.sidebar {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,564 @@
|
|||
<template>
|
||||
<div id="content" class="app-container" style="display: flex;">
|
||||
<!-- 左侧图表区域 -->
|
||||
<div class="chart-section">
|
||||
<div class="chart-container">
|
||||
<h2>证件类别统计</h2>
|
||||
<h6>取前三个证件类型</h6>
|
||||
<div id="categoryChart" class="chart"></div>
|
||||
|
||||
<h2 style="margin-top: 40px;">证件状态统计</h2>
|
||||
<div id="statusChart" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧内容区域 -->
|
||||
<div class="content-section">
|
||||
<!-- 搜索表单 -->
|
||||
<div class="search-header">
|
||||
<el-form :inline="true" :model="searchForm" class="search-form">
|
||||
<h2 style="display: inline-block; margin-right: 20px;">证件预警</h2>
|
||||
|
||||
<el-form-item>
|
||||
<el-date-picker
|
||||
v-model="searchForm.monthRange"
|
||||
type="monthrange"
|
||||
range-separator="~"
|
||||
start-placeholder="开始月份"
|
||||
end-placeholder="结束月份"
|
||||
value-format="yyyy-MM"
|
||||
:clearable="false"
|
||||
style="width: 240px;">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select v-model="searchForm.onState" placeholder="--在职状态--" clearable style="width: 140px;">
|
||||
<el-option label="在职" value="1"></el-option>
|
||||
<el-option label="离职" value="2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-select v-model="searchForm.riskWarning" placeholder="--风险预警--" clearable style="width: 140px;">
|
||||
<el-option label="即将过期" value="即将过期"></el-option>
|
||||
<el-option label="当月过期" value="当月过期"></el-option>
|
||||
<el-option label="已过期" value="已过期"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" size="small" @click="handleSearch">搜索</el-button>
|
||||
<el-button size="small" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<div class="table-container">
|
||||
<el-table
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" fixed="left" />
|
||||
<el-table-column prop="username" label="姓名" width="100" fixed="left"></el-table-column>
|
||||
<el-table-column prop="idNumber" label="身份证号" width="220" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.showFullId ? scope.row.idNumber : maskIdNumber(scope.row.idNumber) }}</span>
|
||||
<el-button
|
||||
type="text"
|
||||
size="mini"
|
||||
:icon="scope.row.showFullId ? 'el-icon-view' : 'el-icon-view'"
|
||||
@click="toggleIdVisibility(scope.row)"
|
||||
style="margin-left: 5px;"
|
||||
>
|
||||
{{ scope.row.showFullId ? '隐藏' : '显示' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="einTime" label="入场时间" width="160"></el-table-column>
|
||||
<el-table-column prop="exitTime" label="出场时间" width="160"></el-table-column>
|
||||
<el-table-column prop="workType" label="持证类别" min-width="120"></el-table-column>
|
||||
<el-table-column prop="workOperation" label="操作项目" min-width="200"></el-table-column>
|
||||
<el-table-column prop="reviewDate" label="应复审日期" width="110"></el-table-column>
|
||||
<el-table-column label="证件有效期" min-width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<span>
|
||||
{{ formatDateRange(scope.row.validStartDate, scope.row.validEndDate) }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="风险预警" width="120">
|
||||
<template slot-scope="scope">
|
||||
<div class="risk-warning-cell">
|
||||
<img v-if="scope.row.riskWarning === '已过期'" src="@/assets/images/redWarning.png" width="28" height="22"/>
|
||||
<img v-else-if="scope.row.riskWarning === '当月过期'" src="@/assets/images/grWarning.png" width="28" height="22"/>
|
||||
<img v-else-if="scope.row.riskWarning === '即将过期'" src="@/assets/images/yeWarning.png" width="28" height="22"/>
|
||||
<span style="margin-left: 8px;">{{ scope.row.riskWarning }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
v-if="scope.row.certificatePhoto"
|
||||
type="text"
|
||||
size="small"
|
||||
@click="viewCertificate(scope.row.certificatePhoto)">
|
||||
详情
|
||||
</el-button>
|
||||
<span v-else>暂无数据</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="searchForm.pageNum"
|
||||
:limit.sync="searchForm.pageSize"
|
||||
@pagination="fetchTableData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import {getCategoryChartAPI, getStatusChartAPI, getCertificateWarningListAPI} from "@/api/rpa/warning";
|
||||
|
||||
export default {
|
||||
name: 'CertificateWarningList',
|
||||
data() {
|
||||
// 获取当前月份作为默认值
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = now.getMonth() + 1
|
||||
const currentMonth = year + '-' + (month < 10 ? '0' + month : month)
|
||||
|
||||
return {
|
||||
searchForm: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
monthRange: [currentMonth, currentMonth],
|
||||
startTime:'',
|
||||
endTime:'',
|
||||
onState: '',
|
||||
riskWarning: ''
|
||||
},
|
||||
tableData: [],
|
||||
loading: false,
|
||||
// 总条数
|
||||
total: 0,
|
||||
categoryChart: null,
|
||||
statusChart: null,
|
||||
eyeVisible: {}, // 控制眼睛图标显示
|
||||
idNumberVisible: {}, // 控制身份证号显示状态
|
||||
idNumberCache: {} // 缓存身份证号显示状态
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initCharts()
|
||||
this.getCategoryChart()
|
||||
this.getStatusChart()
|
||||
this.fetchTableData()
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化图表
|
||||
initCharts() {
|
||||
this.categoryChart = echarts.init(document.getElementById('categoryChart'))
|
||||
this.statusChart = echarts.init(document.getElementById('statusChart'))
|
||||
},
|
||||
|
||||
// 获取证件类别统计图表
|
||||
getCategoryChart() {
|
||||
getCategoryChartAPI().then(response => {
|
||||
const data = response;
|
||||
const colors = ['#ff9eb2', '#7ec2ff', '#ffd663', '#37e2d2', '#9896ff']
|
||||
let totalSum = 0
|
||||
let formattedData = []
|
||||
if (data && data.length > 0) {
|
||||
totalSum = data.reduce((sum, item) => sum + Number(item.total), 0)
|
||||
|
||||
formattedData = data.map((item, index) => ({
|
||||
value: Number(item.total),
|
||||
name: item.name,
|
||||
percentage: ((Number(item.total) / totalSum) * 100).toFixed(2),
|
||||
itemStyle: {color: colors[index % colors.length]}
|
||||
}))
|
||||
}
|
||||
|
||||
const options = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)',
|
||||
position: 'mouse'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: '2%',
|
||||
top: 'middle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemGap: 15,
|
||||
icon: 'circle',
|
||||
formatter: (name) => {
|
||||
const item = formattedData.find(item => item.name === name)
|
||||
const num = item ? item.percentage : 0
|
||||
return `${name} ${item ? item.value : 0} 个 ${num}%`
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
center: ['40%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff'
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'center',
|
||||
formatter: () => {
|
||||
return `{total|${totalSum}}\n{name|证件总数}`
|
||||
},
|
||||
rich: {
|
||||
total: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#333'
|
||||
},
|
||||
name: {
|
||||
fontSize: 14,
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
data: formattedData
|
||||
}]
|
||||
}
|
||||
|
||||
this.categoryChart.setOption(options)
|
||||
|
||||
// 点击图表打开统计页面
|
||||
this.categoryChart.on('click', (params) => {
|
||||
this.openStatistics(params.name)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('获取证件类别统计失败:', error)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取证件状态统计图表
|
||||
getStatusChart() {
|
||||
getStatusChartAPI().then(response => {
|
||||
const data = response
|
||||
let chartData = []
|
||||
let totalNum = 0
|
||||
|
||||
if (data && data.length > 0) {
|
||||
const {effective, beOverdue, expiringSoon} = data[0]
|
||||
const effectiveNum = Number(effective) || 0
|
||||
const beOverdueNum = Number(beOverdue) || 0
|
||||
const expiringSoonNum = Number(expiringSoon) || 0
|
||||
totalNum = effectiveNum + beOverdueNum + expiringSoonNum
|
||||
|
||||
chartData = [
|
||||
{
|
||||
value: effectiveNum,
|
||||
name: '有效',
|
||||
percentage: totalNum > 0 ? ((effectiveNum / totalNum) * 100).toFixed(2) : 0,
|
||||
itemStyle: {color: '#37e2d2'}
|
||||
},
|
||||
{
|
||||
value: beOverdueNum,
|
||||
name: '过期',
|
||||
percentage: totalNum > 0 ? ((beOverdueNum / totalNum) * 100).toFixed(2) : 0,
|
||||
itemStyle: {color: '#ff9eb2'}
|
||||
},
|
||||
{
|
||||
value: expiringSoonNum,
|
||||
name: '即将过期',
|
||||
percentage: totalNum > 0 ? ((expiringSoonNum / totalNum) * 100).toFixed(2) : 0,
|
||||
itemStyle: {color: '#ffd663'}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const options = {
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: {c} ({d}%)',
|
||||
position: 'mouse'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
right: '2%',
|
||||
top: 'middle',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
itemGap: 15,
|
||||
icon: 'circle',
|
||||
formatter: (name) => {
|
||||
const item = chartData.find(item => item.name === name)
|
||||
const num = item ? item.percentage : 0
|
||||
return `${name} ${item ? item.value : 0} 个 ${num}%`
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
series: [{
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
center: ['40%', '50%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff'
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'center',
|
||||
formatter: () => {
|
||||
return `{total|${totalNum}}\n{name|证件总数}`
|
||||
},
|
||||
rich: {
|
||||
total: {
|
||||
fontSize: 28,
|
||||
fontWeight: 'bold',
|
||||
color: '#333'
|
||||
},
|
||||
name: {
|
||||
fontSize: 14,
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
data: chartData
|
||||
}]
|
||||
}
|
||||
|
||||
this.statusChart.setOption(options)
|
||||
|
||||
// 点击图表打开统计页面
|
||||
this.statusChart.on('click', (params) => {
|
||||
this.openStatistics(params.name)
|
||||
})
|
||||
}).catch(error => {
|
||||
console.error('获取证件状态统计失败:', error)
|
||||
})
|
||||
},
|
||||
|
||||
// 获取表格数据
|
||||
fetchTableData() {
|
||||
this.loading = true
|
||||
// 处理月份范围
|
||||
if (this.searchForm.monthRange && this.searchForm.monthRange.length === 2) {
|
||||
this.searchForm.startTime = this.searchForm.monthRange[0]
|
||||
this.searchForm.endTime = this.searchForm.monthRange[1]
|
||||
}
|
||||
getCertificateWarningListAPI(this.searchForm).then((response) => {
|
||||
this.tableData = response.rows
|
||||
console.log(this.tableData)
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 搜索
|
||||
handleSearch() {
|
||||
this.fetchTableData()
|
||||
},
|
||||
|
||||
// 重置
|
||||
handleReset() {
|
||||
const now = new Date()
|
||||
const year = now.getFullYear()
|
||||
const month = now.getMonth() + 1
|
||||
const currentMonth = year + '-' + (month < 10 ? '0' + month : month)
|
||||
|
||||
this.searchForm = {
|
||||
monthRange: [currentMonth, currentMonth],
|
||||
onState: '',
|
||||
riskWarning: '',
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
startTime:'',
|
||||
endTime:'',
|
||||
}
|
||||
this.fetchTableData()
|
||||
},
|
||||
|
||||
// 获取身份证号(脱敏或完整)
|
||||
getIdNumber(row, index) {
|
||||
if (!row.idNumber) return ''
|
||||
|
||||
// 如果已经切换过显示状态,使用缓存的状态
|
||||
if (this.idNumberCache[index]) {
|
||||
return row.idNumber
|
||||
}
|
||||
|
||||
// 默认脱敏显示
|
||||
return row.idNumber.slice(0, 4) + '*********' + row.idNumber.slice(14)
|
||||
},
|
||||
|
||||
// 显示眼睛图标
|
||||
showEye(index) {
|
||||
this.$set(this.eyeVisible, index, true)
|
||||
},
|
||||
|
||||
// 隐藏眼睛图标
|
||||
hideEye(index) {
|
||||
this.$set(this.eyeVisible, index, false)
|
||||
},
|
||||
|
||||
// 切换身份证号显示
|
||||
toggleIdNumber(index, idNumber) {
|
||||
this.$set(this.idNumberCache, index, !this.idNumberCache[index])
|
||||
this.$forceUpdate()
|
||||
},
|
||||
|
||||
// 查看证件详情
|
||||
viewCertificate(certificatePhoto) {
|
||||
const url = '/data/' + certificatePhoto
|
||||
window.open(url)
|
||||
},
|
||||
|
||||
// 打开统计页面
|
||||
openStatistics(name) {
|
||||
this.$router.push('/rpa/statistics');
|
||||
},
|
||||
|
||||
// 身份证号脱敏
|
||||
maskIdNumber(idNumber) {
|
||||
if (!idNumber || idNumber.length < 8) return idNumber
|
||||
return idNumber.substring(0, 6) + '********' + idNumber.substring(14)
|
||||
},
|
||||
|
||||
// 切换身份证显示/隐藏
|
||||
toggleIdVisibility(row) {
|
||||
this.$set(row, 'showFullId', !row.showFullId)
|
||||
},
|
||||
|
||||
// 格式化有效期区间
|
||||
formatDateRange(start, end) {
|
||||
const format = (dateStr) => {
|
||||
if (!dateStr || dateStr === 'null') return '';
|
||||
// 只取日期部分(去掉时间)
|
||||
return dateStr.split(' ')[0];
|
||||
};
|
||||
const s = format(start);
|
||||
const e = format(end);
|
||||
return `${s} ~ ${e}`;
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-section {
|
||||
width: 33.33%;
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.chart-container h2 {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.chart-container h6 {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.search-header {
|
||||
background-color: #fff;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.id-number-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.eye-icon {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
color: #409EFF;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.eye-icon:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
|
||||
.risk-warning-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.risk-warning-cell img {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media (max-width: 768px) {
|
||||
.chart-section {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue