470 lines
11 KiB
Vue
470 lines
11 KiB
Vue
<template>
|
||
<view class="padding page">
|
||
<scroll-view scroll-x class="tab-scroll">
|
||
<view class="tab-list">
|
||
<view class="tab-item" :class="{ 'tab-active': activeIndex === index }"
|
||
v-for="(item, index) in warningList" :key="index" @click="switchTab(index)">
|
||
{{ item.name }}
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
<!-- 查询条件 -->
|
||
<view class="bg-white radius padding margin-top search-card">
|
||
<view class="section-header">
|
||
<image class="section-icon" src="/static/yujin/yujin_sousuo.png" mode="aspectFit"></image>
|
||
<view class="text-black text-bold">查询条件</view>
|
||
</view>
|
||
<!-- 日期选择行 -->
|
||
<view class="date-row margin-top">
|
||
<view class="date-item">
|
||
<view class="date-label">开始日期</view>
|
||
<view class="date-picker" @click="showStartDatePicker = true">
|
||
<text :class="searchForm.startDate ? 'date-value' : 'date-placeholder'">
|
||
{{ searchForm.startDate || '请选择' }}
|
||
</text>
|
||
<text class="cuIcon-unfold"></text>
|
||
</view>
|
||
<up-datetime-picker
|
||
:show="showStartDatePicker"
|
||
v-model="startDateValue"
|
||
mode="date"
|
||
@confirm="onStartDateConfirm"
|
||
@cancel="showStartDatePicker = false"
|
||
@close="showStartDatePicker = false"
|
||
></up-datetime-picker>
|
||
</view>
|
||
<view class="date-item">
|
||
<view class="date-label">结束日期</view>
|
||
<view class="date-picker" @click="showEndDatePicker = true">
|
||
<text :class="searchForm.endDate ? 'date-value' : 'date-placeholder'">
|
||
{{ searchForm.endDate || '请选择' }}
|
||
</text>
|
||
<text class="cuIcon-unfold"></text>
|
||
</view>
|
||
<up-datetime-picker
|
||
:show="showEndDatePicker"
|
||
v-model="endDateValue"
|
||
mode="date"
|
||
@confirm="onEndDateConfirm"
|
||
@cancel="showEndDatePicker = false"
|
||
@close="showEndDatePicker = false"
|
||
></up-datetime-picker>
|
||
</view>
|
||
</view>
|
||
<view class="margin-top">
|
||
<view class="date-label">公司名称</view>
|
||
<up-input v-model="searchForm.deptName" placeholder="请输入公司名称" border="surround"></up-input>
|
||
</view>
|
||
<button class="search-btn" @click="handleSearch">查询</button>
|
||
</view>
|
||
|
||
<!-- 统计概览 -->
|
||
<view class="padding bg-white radius margin-top">
|
||
<view class="section-header">
|
||
<image class="section-icon" src="/static/yujin/yujin_tongji.png" mode="aspectFit"></image>
|
||
<view class="text-bold text-black">统计概览</view>
|
||
</view>
|
||
<view class="stat-grid margin-top">
|
||
<view class="stat-item stat-total">
|
||
<view class="stat-num">{{ statistics.total }}</view>
|
||
<view class="stat-label">总计</view>
|
||
</view>
|
||
<view class="stat-item stat-overdue">
|
||
<view class="stat-num">{{ statistics.overdue }}</view>
|
||
<view class="stat-label">逾期</view>
|
||
</view>
|
||
<view class="stat-item stat-completed">
|
||
<view class="stat-num">{{ statistics.completed }}</view>
|
||
<view class="stat-label">已完成</view>
|
||
</view>
|
||
<view class="stat-item stat-pending">
|
||
<view class="stat-num">{{ statistics.pending }}</view>
|
||
<view class="stat-label">待处理</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 数据列表标题 -->
|
||
<view class="bg-white radius padding margin-top margin-bottom flex align-center">
|
||
<view class="list-title-bar"></view>
|
||
<view class="text-bold text-black">日常安全检查预警数据列表</view>
|
||
</view>
|
||
|
||
<!-- 数据列表 -->
|
||
<view v-for="(item, index) in dataList" :key="item.id" class="list-card">
|
||
<!-- 状态标签(斜角) -->
|
||
<view class="status-tag" :class="getStatusClass(item.overdueDays)">
|
||
<text class="status-text">{{ getStatusText(item.overdueDays, item.statusName) }}</text>
|
||
</view>
|
||
|
||
<view class="card-header">
|
||
<view class="text-bold text-black">#{{ index + 1 }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">企业名称:</view>
|
||
<view class="row-value">{{ item.deptName || '-' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">计划名称:</view>
|
||
<view class="row-value">{{ item.planName || '-' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">计划周期:</view>
|
||
<view class="row-value">{{ item.cycleName || '-' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">预约检查日期:</view>
|
||
<view class="row-value">{{ item.taskDate || '-' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">实际完成时间:</view>
|
||
<view class="row-value">{{ item.finishTime || '未完成' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">负责人:</view>
|
||
<view class="row-value">{{ item.executorName || '-' }}</view>
|
||
</view>
|
||
<view class="card-row">
|
||
<view class="row-label">逾期天数:</view>
|
||
<view class="row-value">{{ item.overdueDays || '-' }}</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-if="dataList.length === 0" class="empty-tip">
|
||
<text>暂无数据</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { onShow } from '@dcloudio/uni-app'
|
||
import { getInspectionWarningList } from '@/request/api.js'
|
||
|
||
// 搜索表单
|
||
const searchForm = reactive({
|
||
startDate: '',
|
||
endDate: '',
|
||
deptName: ''
|
||
})
|
||
|
||
// 日期选择器
|
||
const showStartDatePicker = ref(false)
|
||
const showEndDatePicker = ref(false)
|
||
const startDateValue = ref(Number(new Date()))
|
||
const endDateValue = ref(Number(new Date()))
|
||
|
||
// 统计数据
|
||
const statistics = reactive({
|
||
total: 0,
|
||
overdue: 0,
|
||
completed: 0,
|
||
pending: 0
|
||
})
|
||
|
||
// 列表数据
|
||
const dataList = ref([])
|
||
const pageNum = ref(1)
|
||
const pageSize = ref(20)
|
||
|
||
// 日期格式化
|
||
const formatDate = (timestamp) => {
|
||
const date = new Date(timestamp)
|
||
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}`
|
||
}
|
||
|
||
// 日期选择确认
|
||
const onStartDateConfirm = (e) => {
|
||
searchForm.startDate = formatDate(e.value)
|
||
showStartDatePicker.value = false
|
||
}
|
||
|
||
const onEndDateConfirm = (e) => {
|
||
searchForm.endDate = formatDate(e.value)
|
||
showEndDatePicker.value = false
|
||
}
|
||
|
||
// 获取状态样式类
|
||
const getStatusClass = (overdueDays) => {
|
||
if (!overdueDays || overdueDays === '按期') {
|
||
return 'status-normal' // 按期/期限内
|
||
}
|
||
const days = parseInt(overdueDays)
|
||
if (days >= 7) {
|
||
return 'status-serious' // 严重逾期(红色)
|
||
} else if (days >= 1) {
|
||
return 'status-overdue' // 逾期(橙色)
|
||
}
|
||
return 'status-normal'
|
||
}
|
||
|
||
// 获取状态文本
|
||
const getStatusText = (overdueDays, statusName) => {
|
||
if (!overdueDays || overdueDays === '按期') {
|
||
return statusName === '已完成' ? '按期已完成' : '期限内待检'
|
||
}
|
||
const days = parseInt(overdueDays)
|
||
if (days >= 7) {
|
||
return '严重逾期'
|
||
} else if (days >= 1) {
|
||
return statusName === '已完成' ? '逾期已完成' : '逾期未检'
|
||
}
|
||
return '期限内待检'
|
||
}
|
||
|
||
// 获取数据
|
||
const fetchData = async () => {
|
||
try {
|
||
const params = {
|
||
pageNum: pageNum.value,
|
||
pageSize: pageSize.value
|
||
}
|
||
// 添加查询条件
|
||
if (searchForm.startDate) {
|
||
params.startDate = searchForm.startDate
|
||
}
|
||
if (searchForm.endDate) {
|
||
params.endDate = searchForm.endDate
|
||
}
|
||
if (searchForm.deptName && searchForm.deptName.trim()) {
|
||
params.deptName = searchForm.deptName.trim()
|
||
}
|
||
|
||
const res = await getInspectionWarningList(params)
|
||
if (res.code === 0) {
|
||
// 更新统计数据
|
||
if (res.data.statistics) {
|
||
statistics.total = res.data.statistics.total || 0
|
||
statistics.overdue = res.data.statistics.overdue || 0
|
||
statistics.completed = res.data.statistics.completed || 0
|
||
statistics.pending = res.data.statistics.pending || 0
|
||
}
|
||
// 更新列表数据
|
||
if (res.data.page && res.data.page.records) {
|
||
dataList.value = res.data.page.records
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取预警列表失败:', error)
|
||
}
|
||
}
|
||
|
||
// 搜索
|
||
const handleSearch = () => {
|
||
pageNum.value = 1
|
||
fetchData()
|
||
}
|
||
|
||
// 页面加载
|
||
onShow(() => {
|
||
fetchData()
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.page {
|
||
min-height: 100vh;
|
||
background: #EBF2FC;
|
||
padding-bottom: 40rpx;
|
||
}
|
||
|
||
// 区块标题
|
||
.section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.section-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
margin-right: 12rpx;
|
||
}
|
||
}
|
||
|
||
// 搜索卡片
|
||
.search-card {
|
||
.date-row {
|
||
display: flex;
|
||
gap: 20rpx;
|
||
|
||
.date-item {
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
.date-label {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 12rpx;
|
||
}
|
||
|
||
.date-picker {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
height: 72rpx;
|
||
padding: 0 20rpx;
|
||
background: #f8f8f8;
|
||
border-radius: 8rpx;
|
||
border: 1rpx solid #eee;
|
||
|
||
.date-value {
|
||
color: #333;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.date-placeholder {
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
|
||
.search-btn {
|
||
margin-top: 30rpx;
|
||
background: linear-gradient(135deg, #667eea 0%, #2667E9 100%);
|
||
color: #fff;
|
||
border-radius: 40rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
font-size: 30rpx;
|
||
}
|
||
}
|
||
|
||
// 统计卡片
|
||
.stat-grid {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 16rpx;
|
||
|
||
.stat-item {
|
||
flex: 1;
|
||
height: 124rpx;
|
||
border-radius: 12rpx;
|
||
color: #fff;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.stat-num {
|
||
font-size: 40rpx;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 24rpx;
|
||
margin-top: 8rpx;
|
||
}
|
||
}
|
||
|
||
.stat-total {
|
||
background: linear-gradient(135deg, #628EFB 0%, #4A7CF7 100%);
|
||
}
|
||
|
||
.stat-overdue {
|
||
background: linear-gradient(135deg, #32DCC7 0%, #20C5B0 100%);
|
||
}
|
||
|
||
.stat-completed {
|
||
background: linear-gradient(135deg, #32D1E9 0%, #20B8D0 100%);
|
||
}
|
||
|
||
.stat-pending {
|
||
background: linear-gradient(135deg, #A190F5 0%, #8B78E8 100%);
|
||
}
|
||
}
|
||
|
||
// 列表标题
|
||
.list-title-bar {
|
||
width: 8rpx;
|
||
height: 32rpx;
|
||
background: #2667E9;
|
||
border-radius: 4rpx;
|
||
margin-right: 12rpx;
|
||
}
|
||
|
||
// 数据卡片
|
||
.list-card {
|
||
position: relative;
|
||
background: #FFFFFF;
|
||
box-shadow: 0rpx 2rpx 10rpx rgba(0, 0, 0, 0.08);
|
||
border-left: 8rpx solid #2667E9;
|
||
border-radius: 16rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 20rpx;
|
||
overflow: hidden;
|
||
|
||
.card-header {
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.card-row {
|
||
display: flex;
|
||
margin-top: 16rpx;
|
||
font-size: 28rpx;
|
||
line-height: 1.5;
|
||
|
||
.row-label {
|
||
color: #999;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.row-value {
|
||
color: #333;
|
||
word-break: break-all;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 状态标签(斜角样式)
|
||
.status-tag {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 160rpx;
|
||
height: 50rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transform: rotate(0deg);
|
||
border-radius: 0 16rpx 0 16rpx;
|
||
|
||
.status-text {
|
||
font-size: 22rpx;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
// 严重逾期 - 红色
|
||
.status-serious {
|
||
background: linear-gradient(135deg, #FF6B6B 0%, #EE5A5A 100%);
|
||
}
|
||
|
||
// 逾期 - 橙色
|
||
.status-overdue {
|
||
background: linear-gradient(135deg, #FFA726 0%, #FF9800 100%);
|
||
}
|
||
|
||
// 按期/正常 - 绿色
|
||
.status-normal {
|
||
background: linear-gradient(135deg, #66BB6A 0%, #4CAF50 100%);
|
||
}
|
||
|
||
// 逾期已完成 - 蓝色
|
||
.status-completed {
|
||
background: linear-gradient(135deg, #42A5F5 0%, #2196F3 100%);
|
||
}
|
||
|
||
// 空状态
|
||
.empty-tip {
|
||
text-align: center;
|
||
padding: 100rpx 0;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
}
|
||
</style> |