修改并优化了一些功能及bug

This commit is contained in:
王利强
2026-05-14 13:45:46 +08:00
parent 805747d1d9
commit 2322fcf39a
51 changed files with 802 additions and 346 deletions

View File

@@ -96,12 +96,12 @@
</view>
<scroll-view class="popup-body" scroll-y :style="{ height: '60vh' }">
<view class="flex margin-bottom">
<view class="text-gray">隐患图片/视频</view>
<view class="text-gray">隐患图片</view>
<view class="text-red">*</view>
</view>
<up-upload :fileList="hazardFileList" @afterRead="afterRead" @delete="deletePic" name="1" multiple
:maxCount="10"></up-upload>
<view class="text-gray text-sm">必填请上传现场照片或者视频作为隐患证据</view>
<view class="text-gray text-sm">必填请上传现场照片作为隐患证据</view>
<view class="ai-btn-wrapper margin-top">
<button class="ai-analyze-btn" :loading="aiAnalyzing" :disabled="aiAnalyzing" @click="handleAiAnalyze">
<text v-if="!aiAnalyzing" class="cuIcon-magic ai-btn-icon"></text>
@@ -383,7 +383,7 @@
const confirmHazard = () => {
// 表单验证
if (hazardFileList.value.length === 0) {
uni.showToast({ title: '请上传隐患图片/视频', icon: 'none' });
uni.showToast({ title: '请上传隐患图片', icon: 'none' });
return;
}
if (!hazardFormData.title) {

View File

@@ -1,13 +1,5 @@
<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">
@@ -84,49 +76,57 @@
</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 class="bg-white radius padding-top padding-left padding-right margin-top margin-bottom">
<view class="flex align-center" style="margin-bottom: 20rpx;">
<view class="list-title-bar"></view>
<view class="text-bold text-black">日常安全检查预警数据列表</view>
</view>
<scroll-view scroll-x :show-scrollbar="false">
<view class="status-tabs-inner">
<view v-for="(tab, index) in statusTabs" :key="index" class="status-tab-item"
:class="{ 'status-tab-active': activeStatusTab === index }" @click="switchStatusTab(index)">
<text class="status-tab-text">{{ tab.label }}{{ tab.count != null ? tab.count : '' }}</text>
<view v-if="activeStatusTab === index" class="status-tab-bar"></view>
</view>
</view>
</scroll-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 class="card-title-row">
<view class="card-company-name">{{ item.deptName || '-' }}</view>
<view class="card-status-tag" :class="getStatusClass(item.overdueDays)">
<text>{{ getStatusText(item.overdueDays, item.statusName) }}</text>
</view>
</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 class="card-body">
<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>
@@ -168,6 +168,23 @@ const dataList = ref([])
const pageNum = ref(1)
const pageSize = ref(20)
// 状态筛选 Tab
const statusTabs = ref([
{ label: '全部状态', value: 0, count: null },
{ label: '逾期未检', value: 1, count: null },
{ label: '严重逾期', value: 2, count: null },
{ label: '期限内待检', value: 3, count: null },
{ label: '逾期已完成', value: 4, count: null },
{ label: '按期已完成', value: 5, count: null }
])
const activeStatusTab = ref(0)
const switchStatusTab = (index) => {
activeStatusTab.value = index
pageNum.value = 1
fetchData()
}
// 日期格式化(仅日期,用于页面显示)
const formatDate = (timestamp) => {
const date = new Date(timestamp)
@@ -236,6 +253,11 @@ const fetchData = async () => {
if (searchForm.deptName && searchForm.deptName.trim()) {
params.deptName = searchForm.deptName.trim()
}
// 状态筛选
const statusValue = statusTabs.value[activeStatusTab.value].value
if (statusValue !== 0) {
params.inspectionStatus = statusValue
}
const res = await getInspectionWarningList(params)
if (res.code === 0) {
@@ -391,31 +413,59 @@ onShow(() => {
// 数据卡片
.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;
padding: 0;
margin-bottom: 20rpx;
overflow: hidden;
.card-header {
margin-bottom: 20rpx;
.card-title-row {
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #4A7CF7 0%, #2667E9 100%);
padding: 24rpx 30rpx;
}
.card-company-name {
font-size: 32rpx;
font-weight: bold;
color: #fff;
flex: 1;
margin-right: 16rpx;
}
.card-status-tag {
padding: 8rpx 24rpx;
border-radius: 8rpx;
white-space: nowrap;
flex-shrink: 0;
font-size: 24rpx;
color: #fff;
font-weight: 500;
}
.card-body {
padding: 30rpx;
}
.card-row {
display: flex;
margin-top: 16rpx;
font-size: 28rpx;
line-height: 1.5;
&:first-of-type {
margin-top: 0;
}
.row-label {
color: #999;
white-space: nowrap;
flex-shrink: 0;
}
.row-value {
color: #333;
word-break: break-all;
@@ -423,26 +473,6 @@ onShow(() => {
}
}
// 状态标签(斜角样式)
.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%);
@@ -470,4 +500,49 @@ onShow(() => {
color: #999;
font-size: 28rpx;
}
// 状态筛选 Tab 样式
.status-tabs {
white-space: nowrap;
background: #fff;
border-radius: 16rpx;
margin-bottom: 20rpx;
padding: 0 10rpx;
}
.status-tabs-inner {
display: inline-flex;
align-items: center;
height: 88rpx;
white-space: nowrap;
}
.status-tab-item {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 24rpx;
height: 88rpx;
position: relative;
}
.status-tab-text {
font-size: 26rpx;
color: #666;
}
.status-tab-active .status-tab-text {
color: #2667E9;
font-weight: bold;
}
.status-tab-bar {
position: absolute;
bottom: 8rpx;
width: 40rpx;
height: 6rpx;
background: #2667E9;
border-radius: 3rpx;
}
</style>

View File

@@ -26,7 +26,7 @@
</view>
<!-- 新增按钮 -->
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">新增公司区域</button>
<button class="add-btn bg-blue round" @click="openAddPopup">新增公司区域</button>
<!-- 新增/编辑弹窗组件 -->
<AreaFormPopup
@@ -117,11 +117,19 @@ const handlePopupClose = () => {
// 提交表单
const handleSubmit = async (formData) => {
submitting.value = true;
//新增区域时候,是要先添加企业信息,然后才能新增企业的
try {
// 从本地存储中获取企业id
// const userInfoStr = uni.getStorageSync('userInfo');
// const userInfo = userInfoStr ? JSON.parse(userInfoStr) : {};
// console.log('userInfo:', userInfo);
const submitData = {
name: formData.name,
color: formData.color
// enterpriseId: userInfo.deptId
};
let res;

View File

@@ -12,7 +12,7 @@
<!-- 新增按钮 -->
<button class="add-btn" @click="goToAdd">
<text class="cuIcon-add"></text>
<!-- <text class="cuIcon-add"></text> -->
<text>新增检查表</text>
</button>
</view>

View File

@@ -1,9 +1,9 @@
<template>
<view class="padding page">
<view class="padding bg-white radius margin-bottom" v-for="(item,index) in hazardList" :key="index">
<view class="padding bg-white radius margin-bottom card-item" v-for="(item,index) in hazardList" :key="index">
<view class="flex justify-between margin-bottom">
<view class="text-bold text-black">{{item.hazardTitle}}</view>
<view>{{item.statusName}}</view>
<view class="text-bold text-black" style="flex: 1; margin-right: 16rpx;">{{item.hazardTitle}}</view>
<view class="status-tag" :class="getStatusClass(item.verifyResultName)">{{item.verifyResultName || '未知'}}</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患日期</view>
@@ -74,7 +74,7 @@
:columns="deptColumns"
@confirm="onDeptConfirm"
@cancel="showDeptPicker = false"
@close="showDeptPicker = false"
@close="showDeptPicker = false"
></up-picker>
<view class="margin-bottom margin-top">主要负责人</view>
<up-input v-model="formData.responsiblePerson" placeholder="请输入主要负责人"></up-input>
@@ -366,6 +366,16 @@
})
};
// 根据审核状态返回对应样式类
const getStatusClass = (status) => {
switch (status) {
case '待审核': return 'status-pending';
case '已通过': return 'status-passed';
case '已驳回': return 'status-rejected';
default: return 'status-pending';
}
};
// 页面加载时获取销号申请列表
onMounted(() => {
fetchWriteOffList();
@@ -378,6 +388,33 @@
background: #EBF2FC;
}
.status-tag {
padding: 4rpx 16rpx;
border-radius: 6rpx;
font-size: 22rpx;
white-space: nowrap;
flex-shrink: 0;
font-weight: 500;
height: 40rpx;
line-height: 40rpx;
align-self: flex-start;
}
.status-pending {
background: #FFF7E6;
color: #FA8C16;
}
.status-passed {
background: #F6FFED;
color: #52C41A;
}
.status-rejected {
background: #FFF1F0;
color: #F5222D;
}
.popup-content {
width: 600rpx;
background: #fff;

View File

@@ -623,12 +623,24 @@ const formatDateTime = (timestamp) => {
};
const onStartDateConfirm = (e) => {
formData.startDate = formatDateTime(e.value);
const selectedDate = formatDateTime(e.value);
// 如果已经选了结束时间,校验开始时间不能晚于结束时间
if (formData.endDate && new Date(selectedDate) > new Date(formData.endDate)) {
uni.showToast({ title: '开始时间不能晚于结束时间', icon: 'none' });
return;
}
formData.startDate = selectedDate;
showStartDatePicker.value = false;
};
const onEndDateConfirm = (e) => {
formData.endDate = formatDateTime(e.value);
const selectedDate = formatDateTime(e.value);
// 如果已经选了开始时间,校验结束时间不能早于开始时间
if (formData.startDate && new Date(selectedDate) < new Date(formData.startDate)) {
uni.showToast({ title: '结束时间不能早于开始时间', icon: 'none' });
return;
}
formData.endDate = selectedDate;
showEndDatePicker.value = false;
};
@@ -1015,6 +1027,10 @@ const handleSave = async () => {
uni.showToast({ title: '请选择计划时间', icon: 'none' });
return;
}
if (new Date(formData.endDate) < new Date(formData.startDate)) {
uni.showToast({ title: '结束时间不能早于开始时间', icon: 'none' });
return;
}
// 构建 items 数组关联检查项id列表
const items = [];
@@ -1024,12 +1040,12 @@ const handleSave = async () => {
items.push(item.id );
}
});
// 添加从检查库选择的检查项详情中的所有项的 pointId
// 添加从检查库选择的检查项详情中的所有项的 itemId
checkItems.value.forEach(lib => {
if (lib.details && lib.details.length > 0) {
lib.details.forEach(detail => {
if (detail.pointId) {
items.push(detail.pointId );
if (detail.itemId) {
items.push(detail.itemId);
}
});
}

View File

@@ -1,10 +1,23 @@
<template>
<view class=" page padding">
<view class="padding radius bg-white list-list margin-bottom" v-for="item in hiddenDangerList"
<!-- 顶部状态筛选 Tab -->
<scroll-view class="status-tabs" scroll-x :show-scrollbar="false">
<view class="status-tabs-inner">
<view v-for="(tab, index) in statusTabs" :key="index" class="status-tab-item"
:class="{ 'status-tab-active': activeTab === index }" @click="activeTab = index">
<text class="status-tab-text">{{ tab.label }}</text>
<view v-if="activeTab === index" class="status-tab-bar"></view>
</view>
</view>
</scroll-view>
<view v-if="filteredList.length === 0" class="empty-tip text-gray text-center padding">暂无数据</view>
<view class="padding radius bg-white list-list margin-bottom" v-for="item in filteredList"
:key="item.hazardId">
<view class="flex justify-between margin-bottom">
<view class="text-bold text-black">{{item.title}}</view>
<view class="text-blue">{{item.statusName}}</view>
<view class="text-blue" style="white-space: nowrap; flex-shrink: 0; margin-left: 16rpx;">{{item.statusName}}</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患等级</view>
@@ -56,12 +69,12 @@
</view>
<scroll-view class="popup-body" scroll-y>
<view class="flex margin-bottom">
<view class="text-gray">隐患图片/视频</view>
<view class="text-gray">隐患图片</view>
<view class="text-red">*</view>
</view>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple
:maxCount="10"></up-upload>
<view class="text-gray text-sm">必填请上传现场照片或者视频作为隐患证据</view>
<view class="text-gray text-sm">必填请上传现场照片作为隐患证据</view>
<view class="ai-btn-wrapper margin-top">
<button class="ai-analyze-btn" :loading="aiAnalyzing" :disabled="aiAnalyzing" @click="handleAiAnalyze">
<text v-if="!aiAnalyzing" class="cuIcon-magic ai-btn-icon"></text>
@@ -685,12 +698,31 @@
});
});
// 状态筛选 Tab
const statusTabs = ref([
{ label: '全部状态', value: '' },
{ label: '待验收', value: '待验收' },
{ label: '待整改', value: '待整改' },
{ label: '待交办', value: '待交办' },
{ label: '验收通过', value: '验收通过' }
]);
const activeTab = ref(0);
// 根据选中 tab 过滤列表
const filteredList = computed(() => {
const currentTab = statusTabs.value[activeTab.value];
if (!currentTab || !currentTab.value) {
return hiddenDangerList.value;
}
return hiddenDangerList.value.filter(item => item.statusName === currentTab.value);
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
padding-top: 100rpx; // 给顶部固定Tab留出空间
padding-bottom: 120rpx; // 给底部按钮留出空间
}
@@ -730,6 +762,8 @@
.level-tag {
padding: 4rpx 16rpx;
border-radius: 8rpx;
white-space: nowrap;
flex-shrink: 0;
}
// 轻微隐患
@@ -991,6 +1025,54 @@
}
}
}
// 状态筛选 Tab 样式
.status-tabs {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
white-space: nowrap;
background: #fff;
padding: 0 10rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
}
.status-tabs-inner {
display: inline-flex;
align-items: center;
height: 88rpx;
}
.status-tab-item {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 28rpx;
height: 88rpx;
position: relative;
}
.status-tab-text {
font-size: 28rpx;
color: #666;
}
.status-tab-active .status-tab-text {
color: #2667E9;
font-weight: bold;
}
.status-tab-bar {
position: absolute;
bottom: 8rpx;
width: 40rpx;
height: 6rpx;
background: #2667E9;
border-radius: 3rpx;
}
</style>
<style lang="scss">

View File

@@ -246,7 +246,8 @@
}
}
};
const infoList = ref([
// 全部菜单项
const allMenuList = [
{
name: '成员管理',
src: '/static/home_icon/chengyuangaunli.png'
@@ -263,10 +264,10 @@
name: '检查清单',
src: '/static/home_icon/jiachaqingdan.png'
},
{
name: '检查记录',
src: '/static/home_icon/jianchajilu.png'
},
// {
// name: '检查记录',
// src: '/static/home_icon/jianchajilu.png'
// },
{
name: '证件管理',
src: '/static/home_icon/zhengjianguanli.png'
@@ -279,12 +280,19 @@
name: '隐患销号',
src: '/static/home_icon/yinhuanxiaohao.png'
}
// ,
// {
// name: '设备登记',
// src: '/static/home_icon/shebeidengji.png'
// }
]);
];
// common角色只能看到的菜单名称
const commonMenuNames = ['隐患排查', '隐患销号'];
// 根据角色动态展示菜单
const infoList = computed(() => {
if (userInfo.role === 'common') {
return allMenuList.filter(item => commonMenuNames.includes(item.name));
}
// admin、manage 及其他角色展示全部菜单
return allMenuList;
});
const ViewDetails = (item) => {
uni.navigateTo({
url: `/pages/plandetail/plandetail?id=${item.id}`
@@ -690,6 +698,8 @@
.level-tag {
padding: 4rpx 16rpx;
border-radius: 8rpx;
white-space: nowrap;
flex-shrink: 0;
}
// 轻微隐患

View File

@@ -3,9 +3,20 @@
<!-- 顶部弥散渐变背景 -->
<view class="header-bg">
<!-- 弥散光斑效果 -->
<view class="blur-circle circle-1"></view>
<!-- <view class="blur-circle circle-1"></view>
<view class="blur-circle circle-2"></view>
<view class="blur-circle circle-3"></view>
<view class="blur-circle circle-3"></view> -->
<u-navbar
title="我的"
:placeholder="false"
:fixed="false"
:safeAreaInsetTop="true"
bgColor="transparent"
titleColor="#fff"
:border="false"
leftIcon=""
>
</u-navbar>
<!-- 标题 -->
<!-- <view class="header-title">我的</view> -->
@@ -19,7 +30,7 @@
<view class="user-name">{{ userInfo.nickName || '未设置昵称' }}</view>
<view class="user-phone">{{ userInfo.phonenumber || '未绑定手机' }}</view>
</view>
<button class="edit-btn" @click="editinfo()">编辑资料</button>
<image class="edit-icon" src="/static/my/edit.png" mode="aspectFit" @click="editinfo()"></image>
</view>
</view>
@@ -184,15 +195,15 @@
<style lang="scss" scoped>
.page-wrapper {
min-height: 100vh;
background: #EBF2FC;
background: #fff;
}
// 顶部弥散渐变背景
.header-bg {
position: relative;
height: 400rpx;
background: linear-gradient(180deg, #3B7FED 0%, #007AFF 50%, #8BB8F8 100%);
padding-top: 60rpx;
height: 480rpx;
background: #2667E9;
padding-top: 0;
overflow: hidden;
// 弥散光斑效果
@@ -277,27 +288,23 @@
}
}
.edit-btn {
// padding: 16rpx 32rpx;
background: rgba(255, 255, 255, 0.25);
border: 2rpx solid rgba(255, 255, 255, 0.5);
border-radius: 32rpx;
font-size: 26rpx;
color: #fff;
backdrop-filter: blur(10rpx);
&::after {
border: none;
}
.edit-icon {
width: 48rpx;
height: 48rpx;
flex-shrink: 0;
}
}
// 内容区域
.content-area {
position: relative;
margin-top: -60rpx;
padding: 0 30rpx 50rpx;
margin-top: -40rpx;
padding: 40rpx 30rpx 50rpx;
z-index: 10;
background: #fff;
border-top-left-radius: 40rpx;
border-top-right-radius: 40rpx;
min-height: calc(100vh - 360rpx);
}
// 菜单卡片
@@ -305,7 +312,7 @@
background: #fff;
border-radius: 24rpx;
padding: 10rpx 0;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.1);
}
.menu-item {