Files
threeonecheck_web/pages/index/index.vue
2026-05-03 09:08:56 +08:00

773 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<view class="content">
<!-- 顶部背景区域 -->
<view class="header-wrapper">
<!-- 渐变图片叠加在蓝色底色上 -->
<image class="header-bg-image" src="/static/home_icon/jianbianbeijing.png" mode="aspectFill"></image>
<!-- 自定义导航栏 -->
<u-navbar
title="三查一曝光"
:placeholder="false"
:fixed="false"
:safeAreaInsetTop="true"
bgColor="transparent"
titleColor="#fff"
:border="false"
leftIcon=""
>
</u-navbar>
<!-- 用户信息卡片 -->
<view class="user-card">
<view class="user-avatar">
<image class="avatar-image" :src="getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
</view>
<view class="user-info">
<view class="user-dept text-bold">{{ userInfo.deptName || '未知部门' }}</view>
<view class="user-phone">手机号{{ userInfo.phone || '未绑定' }}</view>
</view>
<!-- <view class="switch-btn">
<text>切换</text>
<u-icon name="list" color="#285CE9" size="14"></u-icon>
</view> -->
</view>
</view>
<view class="padding page-content">
<!-- 功能菜单 -->
<view class="menu-card">
<view class="menu-grid">
<view class="menu-item" v-for="(item, index) in infoList" :key="index" @click="handleMenuClick(item)">
<image class="menu-icon" :src="item.src"></image>
<text class="menu-text">{{ item.name }}</text>
</view>
</view>
</view>
<!-- 我的检查计划 -->
<view class="bg-white margin-top radius" style="padding: 40rpx; margin-left: -30rpx; margin-right: -30rpx;">
<view class="flex margin-bottom-xl">
<!-- <view class="border-tite"></view> -->
<view class="text-bold margin-left-xs" style="font-size: 32rpx;">我的检查计划</view>
</view>
<!-- 无数据提示 -->
<view v-if="checkPlanData.length === 0" class="text-center text-gray padding">
暂无检查计划
</view>
<!-- 列表渲染 -->
<view class="plan-card margin-bottom" v-for="(item, index) in checkPlanData" :key="item.id">
<!-- 蓝色标题栏 -->
<view class="plan-header">
<!-- <image src="/static/蒙版组 273.png" class="plan-header-icon"></image> -->
<text class="plan-header-title">{{ item.name }}</text>
</view>
<!-- 内容区域 -->
<view class="plan-body">
<view class="flex">
<view class="border-border margin-right-xs">{{ item.runModeName }}完成</view>
<view class="border-border">{{ item.cycle }}</view>
</view>
<view class="flex text-gray margin-top">
<view>计划时间</view>
<view style="color: #333333;">{{ formatDate(item.planStartTime) }}{{ formatDate(item.planEndTime) }}</view>
</view>
<view class="flex margin-top align-center">
<view style="color: #B5B5B5;">完成进度</view>
<view class="flex align-center margin-left-sm">
<view class="cu-progress round">
<view class="bg-green" :style="{ width: item.progress + '%' }"></view>
</view>
<text class="margin-left-sm">{{ item.progress }}%</text>
</view>
</view>
<view class="plan-stats margin-top">
<view class="plan-stat-item">
<view class="plan-stat-num text-orange">{{ item.totalCount }}</view>
<view class="plan-stat-label">隐患</view>
</view>
<view class="plan-stat-item">
<view class="plan-stat-num text-yellow">{{ item.totalCount - item.finishedCount }}</view>
<view class="plan-stat-label">待整改</view>
</view>
<view class="plan-stat-item">
<view class="plan-stat-num text-olive">0</view>
<view class="plan-stat-label">待验收</view>
</view>
<view class="plan-stat-item">
<view class="plan-stat-num text-blue">{{ item.finishedCount }}</view>
<view class="plan-stat-label">已完成</view>
</view>
</view>
<view class="margin-top margin-bottom flex justify-end">
<button class="cu-btn round lg light bg-blue margin-right" @click.stop="ViewDetails(item)">查看详情</button>
<button v-if="item.finishedCount < item.totalCount" class="cu-btn round lg bg-blue" @click.stop="goDetails(item)">开始检查</button>
<view v-else class="cu-btn round lg bg-green">已完成</view>
</view>
</view>
</view>
</view>
<!-- 我的隐患 -->
<view class="bg-white margin-top radius" style="padding: 40rpx; margin-left: -40rpx; margin-right: -40rpx;">
<view class="flex margin-bottom">
<!-- <view class="border-tite"></view> -->
<view class="text-bold margin-left-xs" style="font-size: 32rpx;">我的隐患排查</view>
</view>
<!-- Tab 筛选栏 -->
<scroll-view scroll-x class="danger-tab-scroll">
<view class="danger-tab-list">
<view
class="danger-tab-item"
:class="{ 'danger-tab-active': activeDangerTab === index }"
v-for="(tab, index) in dangerTabs"
:key="index"
@click="switchDangerTab(index)"
>{{ tab }}</view>
</view>
</scroll-view>
<!-- 无数据提示 -->
<view v-if="filteredDangerData.length === 0" class="text-center text-gray padding">
暂无隐患数据
</view>
<!-- 隐患卡片列表 -->
<view class="danger-card margin-top" v-for="(item, index) in filteredDangerData" :key="item.hazardId">
<!-- 标题行图标+标题 + 等级标签 -->
<view class="flex justify-between align-center">
<view class="flex align-center">
<text class="cuIcon-infofill text-blue" style="font-size: 36rpx; margin-right: 12rpx;"></text>
<text class="text-bold" style="font-size: 30rpx;">{{ item.title }}</text>
</view>
<view class="level-tag" :class="{
'level-minor': item.levelName === '轻微隐患',
'level-normal': item.levelName === '一般隐患',
'level-major': item.levelName === '重大隐患'
}">{{ item.levelName }}</view>
</view>
<!-- 地址 -->
<view class="text-gray margin-top-sm" style="font-size: 26rpx; padding-left: 48rpx;">{{ item.address }}</view>
<!-- 分隔线 -->
<view style="height: 1rpx; background: #EEEEEE; margin: 20rpx 0;"></view>
<!-- 信息行 -->
<view class="danger-info-row">
<text class="text-gray">隐患来源</text>
<text style="color: #333333;">{{ item.source }}</text>
</view>
<view class="danger-info-row">
<text class="text-gray">隐患状态</text>
<text style="color: #333333;">{{ item.statusName }}</text>
</view>
<view class="danger-info-row">
<text class="text-gray">发现时间</text>
<text style="color: #333333;">{{ item.createdAt }}</text>
</view>
<!-- 操作按钮 -->
<view class="margin-top flex justify-end" style="gap: 16rpx;">
<button class="cu-btn round lg light bg-blue" @click.stop="viewHazardDetail(item)">查看详情</button>
<button v-if="item.statusName === '待整改' && item.canEdit"
class="cu-btn round lg bg-blue" @click.stop="goRectification(item)">立即整改</button>
<button v-if="item.statusName === '待验收' && canAcceptance"
class="cu-btn round lg bg-blue" @click.stop="goAcceptance(item)">立即验收</button>
<button v-if="item.statusName === '待交办'"
class="cu-btn round lg bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
// import { onLoad } from '@dcloudio/uni-app';
import {getCheckPlanList,getHiddenDangerList} from '@/request/api.js'
import { getProfileDetail } from '@/request/three_one_api/info.js';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { toImageUrl } from '@/request/request.js';
const loading = ref(true);
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg';
// 用户信息
const userInfo = reactive({
userId: '',
username: '',
nickName: '',
deptId: '',
deptName: '',
role: '',
avatar: '',
phone: ''
});
// 获取用户角色判断是否有验收权限admin或manage才能验收
const canAcceptance = computed(() => {
return userInfo.role === 'admin' || userInfo.role === 'manage';
});
// 获取图片完整URL用于显示
const getImageUrl = (path) => {
if (!path) return '';
return toImageUrl(path);
};
// 获取用户信息(从接口获取)
const getUserInfo = async () => {
try {
const res = await getProfileDetail();
if (res.code === 0 && res.data) {
userInfo.userId = res.data.userId || '';
userInfo.username = res.data.userName || '';
userInfo.nickName = res.data.nickName || '';
userInfo.deptId = res.data.deptId || '';
userInfo.deptName = res.data.deptName || '';
userInfo.avatar = res.data.avatar || '';
userInfo.phone = res.data.phonenumber || res.data.phone || '';
// 获取角色信息
if (res.data.roles && res.data.roles.length > 0) {
userInfo.role = res.data.roles[0].roleKey || '';
}
}
} catch (e) {
console.error('获取用户信息失败:', e);
// 如果接口失败,尝试从本地存储获取
try {
const storedUserInfo = uni.getStorageSync('userInfo');
if (storedUserInfo) {
const info = JSON.parse(storedUserInfo);
userInfo.userId = info.userId || '';
userInfo.username = info.username || '';
userInfo.nickName = info.nickName || '';
userInfo.deptId = info.deptId || '';
userInfo.deptName = info.deptName || '';
userInfo.role = info.role || '';
userInfo.avatar = info.avatar || '';
userInfo.phone = info.phone || '';
}
} catch (storageError) {
console.error('从本地存储获取用户信息失败:', storageError);
}
}
};
const infoList = ref([
{
name: '成员管理',
src: '/static/home_icon/chengyuangaunli.png'
},
{
name: '信息填报',
src: '/static/home_icon/xinxitianbao.png'
},
{
name: '区域设置',
src: '/static/home_icon/quyushezhi.png'
},
{
name: '检查清单',
src: '/static/home_icon/jiachaqingdan.png'
},
{
name: '检查记录',
src: '/static/home_icon/jianchajilu.png'
},
{
name: '证件管理',
src: '/static/home_icon/zhengjianguanli.png'
},
{
name: '隐患排查',
src: '/static/home_icon/yinhuanpaicha.png'
},
{
name: '隐患销号',
src: '/static/home_icon/yinhuanxiaohao.png'
}
// ,
// {
// name: '设备登记',
// src: '/static/home_icon/shebeidengji.png'
// }
]);
const ViewDetails = (item) => {
uni.navigateTo({
url: `/pages/plandetail/plandetail?id=${item.id}`
})
}
const goDetails = (item) => {
uni.navigateTo({
url: `/pages/Inspectionresult/Inspectionresult?id=${item.id}`
})
}
// 菜单点击跳转
const handleMenuClick = (item) => {
const menuRoutes = {
'成员管理': '/pages/membermanagemen/membermanagemen',
'信息填报': '/pages/corporateInformation/corporateInformation',
'区域设置':'/pages/area/management',
'检查清单' :'/pages/checklist/checklist',
'检查记录': '/pages/Inspectionlog/Inspectionlog',
'证件管理': '/pages/Idphotomanagement/Idphotomanagement',
'隐患排查':'/pages/hiddendanger/Inspection',
'隐患销号':'/pages/closeout/application',
'设备登记':'/pages/equipmentregistration/equipmentregistration',
};
const url = menuRoutes[item.name];
if (url) {
uni.navigateTo({ url });
} else {
uni.showToast({ title: '功能开发中', icon: 'none' });
}
}
//我的检查计划
const checkPlanParams = ref({
pageNum: 1,
pageSize: 10,
name: ''
});
const checkPlanData = ref([]);
const getCheckPlanLists = async () => {
try {
const res = await getCheckPlanList(checkPlanParams.value);
console.log(res);
if (res.code === 0) {
checkPlanData.value = res.data.records;
}
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
// 格式化日期 (2025-12-18 00:00:00 -> 2025-12-18)
const formatDate = (dateStr) => {
if (!dateStr) return '';
return dateStr.split(' ')[0];
};
// 页面加载时调用接口
// onLoad(() => {
// getUserInfo();
// getCheckPlanLists();
// });
// 页面每次显示时都会加载数据
onShow(() => {
getUserInfo();
getCheckPlanLists();
getHiddenDangerLists();
});
//我的隐患排查
const hiddenDangerParams = ref({
pageNum: 1,
pageSize: 10,
name: ''
});
const hiddenDangerData = ref([]);
// 隐患排查 Tab 筛选
const dangerTabs = ref(['全部状态', '待验收', '待整改', '待交办', '验收通过']);
const activeDangerTab = ref(0);
// 切换 Tab
const switchDangerTab = (index) => {
activeDangerTab.value = index;
};
// 根据 Tab 过滤隐患数据
const filteredDangerData = computed(() => {
if (activeDangerTab.value === 0) {
return hiddenDangerData.value;
}
const status = dangerTabs.value[activeDangerTab.value];
return hiddenDangerData.value.filter(item => item.statusName === status);
});
const getHiddenDangerLists = async () => {
try {
const res = await getHiddenDangerList(hiddenDangerParams.value);
console.log(res);
if (res.code === 0) {
hiddenDangerData.value = res.data.records;
console.log(hiddenDangerData.value,1111);
}
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
// 页面加载时调用接口
onLoad(() => {
getHiddenDangerLists();
});
// ========== 隐患排查相关跳转函数 ==========
// 查看隐患详情
const viewHazardDetail = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/view?hazardId=${item.hazardId}&assignId=${item.assignId}`
})
}
// 立即整改(待整改状态)
const goRectification = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/rectification?hazardId=${item.hazardId}&assignId=${item.assignId}`
})
}
// 编辑整改信息(待验收状态)
const editRectification = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/rectification?rectifyId=${item.rectifyId}&isEdit=1`
})
}
// 立即验收
const goAcceptance = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/acceptance?hazardId=${item.hazardId}&assignId=${item.assignId}&rectifyId=${item.rectifyId}`
})
}
// 隐患交办
const assignHazard = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/assignment?hazardId=${item.hazardId}&assignId=${item.assignId}`
})
}
// 切换账户
const switchAccount = () => {
uni.showToast({
title: '切换账户功能开发中',
icon: 'none'
});
}
</script>
<style lang="scss" scoped>
// ========== 顶部背景区域样式 ==========
.header-wrapper {
position: relative;
padding-bottom: 40rpx;
overflow: hidden;
// 蓝色底色
background-color: #2472EA;
}
// 渐变图片叠加在蓝色底色上
.header-bg-image {
position: absolute;
top: 2rpx; // 往下移动
left: 0;
width: 100%;
height: 100%;
z-index: 0;
opacity: 1.6;
}
// 用户信息卡片
.user-card {
position: relative;
z-index: 10;
display: flex;
align-items: center;
padding: 42rpx 30rpx 54rpx 30rpx; // 上42 右30 下54 左30
.user-avatar {
flex-shrink: 0;
width: 144rpx;
height: 144rpx;
border-radius: 50%;
overflow: hidden;
background: #fff;
}
.user-info {
flex: 1;
margin-left: 24rpx;
overflow: hidden;
max-width: 576rpx;
.user-dept {
font-size: 34rpx;
color: #fff;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.user-phone {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.9);
margin-top: 10rpx;
}
}
.switch-btn {
display: flex;
align-items: center;
background: #fff;
padding: 16rpx 24rpx;
border-radius: 30rpx;
color: #285CE9;
font-size: 26rpx;
flex-shrink: 0;
margin-left: 20rpx;
text {
margin-right: 8rpx;
}
}
}
.page-content {
background: #F4F7FB;
border-radius: 40rpx 40rpx 0rpx 0rpx;
margin-top: -40rpx;
padding: 30rpx;
padding-bottom: 50rpx;
position: relative;
z-index: 10;
min-height: calc(100vh - 400rpx);
}
// ========== 功能菜单区域 ==========
.menu-card {
background: #fff;
border-radius: 40rpx 40rpx 0 0rpx;
padding: 44rpx 30rpx 30rpx 30rpx;
margin-left: -40rpx;
margin-right: -40rpx;
margin-top: -30rpx;
}
.menu-grid {
display: flex;
flex-wrap: wrap;
}
.menu-item {
width: 20%;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 38rpx;
.menu-icon {
width: 72rpx;
height: 80rpx;
}
.menu-text {
font-size: 24rpx;
color: #333;
margin-top: 14rpx;
text-align: center;
white-space: nowrap;
}
}
// 头像图片样式
.avatar-image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.list-list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
// ========== 检查计划卡片 ==========
.plan-card {
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.06);
}
.plan-header {
background: linear-gradient(135deg, #4A90E2 0%, #2667E9 100%);
padding: 24rpx 30rpx;
display: flex;
align-items: center;
.plan-header-icon {
width: 36rpx;
height: 36rpx;
margin-right: 12rpx;
}
.plan-header-title {
color: #fff;
font-size: 30rpx;
font-weight: bold;
}
}
.plan-body {
padding: 24rpx 30rpx 10rpx 30rpx;
background: #fff;
}
.plan-stats {
display: flex;
background: #F5F7FA;
border-radius: 12rpx;
border: 1rpx solid #E8ECF0;
overflow: hidden;
.plan-stat-item {
flex: 1;
text-align: center;
padding: 20rpx 0;
border-right: 1rpx solid #E8ECF0;
&:last-child {
border-right: none;
}
}
.plan-stat-num {
font-size: 36rpx;
font-weight: bold;
}
.plan-stat-label {
font-size: 24rpx;
color: #666;
margin-top: 8rpx;
}
}
.border-tite {
width: 10rpx;
height: 32rpx;
background: #2667E9;
border-radius: 10rpx 10rpx 10rpx 10rpx;
}
.cu-progress {
width: 300rpx;
height: 20rpx;
background: #ebeef5;
border-radius: 100rpx;
overflow: hidden;
view {
height: 100%;
border-radius: 100rpx;
transition: width 0.3s ease;
}
}
.bg-green {
background: #2667E9;
}
.border-border {
padding: 10rpx;
background: #EEF3FF;
border-radius: 4rpx 4rpx 4rpx 4rpx;
border: 2rpx solid #AAC5FC;
text-align: center;
justify-content: center;
align-items: center;
display: flex;
font-size: 28rpx;
color: #2667E9;
}
// 隐患等级标签样式
.level-tag {
padding: 4rpx 16rpx;
border-radius: 8rpx;
}
// 轻微隐患
.level-minor {
background: #F6FFED;
border: 2rpx solid #B7EB8F;
color: #52C41A;
}
// 一般隐患
.level-normal {
background: #FFF7E6;
border: 2rpx solid #FFD591;
color: #FA8C16;
}
// 重大隐患
.level-major {
background: #FFF1F0;
border: 2rpx solid #FFA39E;
color: #F5222D;
}
// ========== 隐患排查 Tab 筛选栏 ==========
.danger-tab-scroll {
white-space: nowrap;
margin-bottom: 20rpx;
}
.danger-tab-list {
display: inline-flex;
gap: 42rpx;
margin-left: 10rpx;
}
.danger-tab-item {
font-size: 28rpx;
color: #666;
padding-bottom: 12rpx;
position: relative;
flex-shrink: 0;
}
.danger-tab-active {
font-weight: bold;
color: #2667E9 !important;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 6rpx;
background: #2667E9;
border-radius: 3rpx;
}
}
// ========== 隐患卡片 ==========
.danger-card {
padding: 30rpx;
margin-bottom: 20rpx;
background: #FFFFFF;
box-shadow: 0rpx 6rpx 12rpx 2rpx #F1F5FE;
border-radius: 16rpx 16rpx 16rpx 16rpx;
border: 2rpx solid #EAECEF;
}
.danger-info-row {
font-size: 28rpx;
margin-top: 16rpx;
display: flex;
.text-gray {
white-space: nowrap;
flex-shrink: 0;
}
}
</style>