优化后,再次提交
This commit is contained in:
@@ -38,7 +38,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 新增按钮 -->
|
||||
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">+ 新增</button>
|
||||
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">新增</button>
|
||||
|
||||
<!-- 新增/编辑证照弹窗 -->
|
||||
<u-popup :show="showAddPopup" mode="center" round="20" @close="closePopup">
|
||||
@@ -181,7 +181,7 @@ import {
|
||||
updateLicense,
|
||||
deleteLicense
|
||||
} from '@/request/three_one_api/license.js';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
import { getToken, toImageUrl } from '@/request/request.js';
|
||||
|
||||
// 证照列表
|
||||
const licenseList = ref([]);
|
||||
@@ -228,8 +228,7 @@ onMounted(() => {
|
||||
// 获取图片完整URL
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
return toImageUrl(path);
|
||||
};
|
||||
|
||||
// 预览图片
|
||||
|
||||
@@ -102,6 +102,12 @@
|
||||
<up-upload :fileList="hazardFileList" @afterRead="afterRead" @delete="deletePic" name="1" multiple
|
||||
:maxCount="10"></up-upload>
|
||||
<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>
|
||||
{{ aiAnalyzing ? 'AI识别中...' : 'AI 识别隐患' }}
|
||||
</button>
|
||||
</view>
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患标题</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -112,8 +118,14 @@
|
||||
<view class="text-gray">隐患等级</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-choose v-model="hazardFormData.level" :options="levelOptions" :wrap="false" item-width="183rpx"
|
||||
item-height="72rpx"></up-choose>
|
||||
<up-choose
|
||||
ref="levelChooseRef"
|
||||
v-model="hazardFormData.level"
|
||||
:options="levelOptions"
|
||||
:wrap="false"
|
||||
item-width="183rpx"
|
||||
item-height="72rpx"
|
||||
></up-choose>
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患来源</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -191,9 +203,9 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { ref, reactive, computed, nextTick } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { enterCheckPlan, submitCheckResult, addHiddenDanger, getHiddenDangerLabelList } from '@/request/api.js';
|
||||
import { enterCheckPlan, submitCheckResult, addHiddenDanger, getHiddenDangerLabelList, analyzeHazardImage } from '@/request/api.js';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
import { getAreaList } from '@/request/three_one_api/area.js';
|
||||
|
||||
@@ -290,6 +302,12 @@
|
||||
// 隐患附件列表
|
||||
const hazardFileList = ref([]);
|
||||
|
||||
// up-choose 组件的 ref
|
||||
const levelChooseRef = ref(null);
|
||||
|
||||
// AI 识别相关
|
||||
const aiAnalyzing = ref(false);
|
||||
|
||||
// 是否已填写隐患数据
|
||||
const hasHazardData = computed(() => {
|
||||
return hazardFormData.title && hazardFileList.value.length > 0;
|
||||
@@ -427,11 +445,13 @@
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url);
|
||||
let item = hazardFileList.value[fileListLen];
|
||||
const serverPath = typeof result === 'string' ? result : (result?.url || result?.path || '');
|
||||
hazardFileList.value.splice(fileListLen, 1, {
|
||||
...item,
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
url: baseUrl.replace('/prod-api', '') + serverPath,
|
||||
serverPath: serverPath,
|
||||
});
|
||||
fileListLen++;
|
||||
}
|
||||
@@ -463,6 +483,57 @@
|
||||
});
|
||||
};
|
||||
|
||||
// AI 识别隐患
|
||||
const handleAiAnalyze = async () => {
|
||||
const imageFiles = hazardFileList.value.filter(f => {
|
||||
return f.status === 'success' && f.url.toLowerCase().match(/\.(jpg|jpeg|png|gif|bmp|webp)$/);
|
||||
});
|
||||
if (imageFiles.length === 0) {
|
||||
uni.showToast({ title: '请先上传隐患图片', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const fullImageUrl = imageFiles[0].url;
|
||||
|
||||
aiAnalyzing.value = true;
|
||||
try {
|
||||
console.log('开始调用AI分析接口,图片地址:', fullImageUrl);
|
||||
const analyzeRes = await analyzeHazardImage({
|
||||
imageUrl: fullImageUrl,
|
||||
});
|
||||
|
||||
if (analyzeRes.code === 0 && analyzeRes.data) {
|
||||
const aiData = analyzeRes.data;
|
||||
console.log('AI分析结果:', aiData);
|
||||
|
||||
if (aiData.title) hazardFormData.title = aiData.title;
|
||||
if (aiData.description) hazardFormData.description = aiData.description;
|
||||
|
||||
if (aiData.level) {
|
||||
const levelMap = { '轻微': 0, '轻微隐患': 0, '一般': 1, '一般隐患': 1, '重大': 2, '重大隐患': 2 };
|
||||
const levelIndex = levelMap[aiData.level];
|
||||
if (levelIndex !== undefined) {
|
||||
hazardFormData.level = levelIndex;
|
||||
nextTick(() => {
|
||||
if (levelChooseRef.value && levelChooseRef.value.$data) {
|
||||
levelChooseRef.value.$data.currentIndex = levelIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({ title: 'AI分析完成,已自动填充', icon: 'success', duration: 2000 });
|
||||
} else {
|
||||
uni.showToast({ title: analyzeRes.msg || 'AI分析失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI分析接口调用失败:', error);
|
||||
uni.showToast({ title: 'AI分析失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
aiAnalyzing.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 提交逻辑 ====================
|
||||
|
||||
// 提交检查结果
|
||||
@@ -836,6 +907,38 @@
|
||||
.popup-body {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
// AI 识别按钮样式
|
||||
.ai-btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ai-analyze-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #2668EA 100%);
|
||||
border-radius: 36rpx;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ai-btn-icon {
|
||||
margin-right: 8rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
|
||||
@@ -168,7 +168,7 @@ const dataList = ref([])
|
||||
const pageNum = ref(1)
|
||||
const pageSize = ref(20)
|
||||
|
||||
// 日期格式化
|
||||
// 日期格式化(仅日期,用于页面显示)
|
||||
const formatDate = (timestamp) => {
|
||||
const date = new Date(timestamp)
|
||||
const year = date.getFullYear()
|
||||
@@ -177,14 +177,17 @@ const formatDate = (timestamp) => {
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
// 日期选择确认
|
||||
// 日期选择确认(开始日期补 00:00:00)
|
||||
const onStartDateConfirm = (e) => {
|
||||
searchForm.startDate = formatDate(e.value)
|
||||
const dateStr = formatDate(e.value)
|
||||
searchForm.startDate = `${dateStr} 00:00:00`
|
||||
showStartDatePicker.value = false
|
||||
}
|
||||
|
||||
// 日期选择确认(结束日期补 23:59:59)
|
||||
const onEndDateConfirm = (e) => {
|
||||
searchForm.endDate = formatDate(e.value)
|
||||
const dateStr = formatDate(e.value)
|
||||
searchForm.endDate = `${dateStr} 23:59:59`
|
||||
showEndDatePicker.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -76,9 +76,15 @@
|
||||
@cancel="showDeptPicker = false"
|
||||
@close="showDeptPicker = false"
|
||||
></up-picker>
|
||||
<view class="margin-bottom margin-top">主要负责人</view>
|
||||
<up-input v-model="formData.responsiblePerson" placeholder="请输入主要负责人"></up-input>
|
||||
<view class="margin-bottom margin-top">主要治理内容</view>
|
||||
<view class="margin-bottom margin-top">主要负责人</view>
|
||||
<up-input v-model="formData.responsiblePerson" placeholder="请输入主要负责人"></up-input>
|
||||
<view class="ai-btn-wrapper margin-top margin-bottom">
|
||||
<button class="ai-analyze-btn" :loading="aiGenerating" :disabled="aiGenerating" @click="handleAiGenerate">
|
||||
<text v-if="!aiGenerating" class="cuIcon-magic ai-btn-icon"></text>
|
||||
{{ aiGenerating ? 'AI生成中...' : 'AI 生成销号方案' }}
|
||||
</button>
|
||||
</view>
|
||||
<view class="margin-bottom margin-top">主要治理内容</view>
|
||||
<up-textarea v-model="formData.mainTreatmentContent" placeholder="请输入主要治理内容"></up-textarea>
|
||||
<view class="margin-bottom margin-top">隐患治理完成内容</view>
|
||||
<up-textarea v-model="formData.treatmentResult" placeholder="请输入隐患治理完成情况"></up-textarea>
|
||||
@@ -96,7 +102,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { getMyWriteOffList, applyDelete, getAcceptanceList, getDepartmentPersonUsers } from '@/request/api.js';
|
||||
import { getMyWriteOffList, applyDelete, getAcceptanceList, getDepartmentPersonUsers, getHiddenDangerDetail, getRectifyDetail, generateWriteoffContent } from '@/request/api.js';
|
||||
|
||||
// 弹窗控制
|
||||
const showAddPopup = ref(false);
|
||||
@@ -120,6 +126,9 @@
|
||||
// 日期选择
|
||||
const dateValue = ref(Date.now());
|
||||
|
||||
// AI生成状态
|
||||
const aiGenerating = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
rectifyDeadline: '', // 整改时限
|
||||
@@ -259,6 +268,61 @@
|
||||
formData.selfVerifyContent = '';
|
||||
};
|
||||
|
||||
// AI生成销号方案
|
||||
const handleAiGenerate = async () => {
|
||||
if (!selectedHazardId.value) {
|
||||
uni.showToast({ title: '请先选择隐患', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
aiGenerating.value = true;
|
||||
try {
|
||||
// 1. 获取隐患详情
|
||||
const hazardRes = await getHiddenDangerDetail({ hazardId: selectedHazardId.value });
|
||||
if (hazardRes.code !== 0 || !hazardRes.data) {
|
||||
uni.showToast({ title: '获取隐患详情失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 从 assigns 中获取 rectifyId
|
||||
const assigns = hazardRes.data.assigns;
|
||||
if (!assigns || assigns.length === 0 || !assigns[0].rectify) {
|
||||
uni.showToast({ title: '该隐患暂无整改记录', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
const rectifyId = assigns[0].rectify.rectifyId;
|
||||
|
||||
// 3. 获取整改详情
|
||||
const rectifyRes = await getRectifyDetail({ rectifyId });
|
||||
if (rectifyRes.code !== 0 || !rectifyRes.data) {
|
||||
uni.showToast({ title: '获取整改详情失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const rectifyPlan = rectifyRes.data.rectifyPlan;
|
||||
if (!rectifyPlan) {
|
||||
uni.showToast({ title: '整改方案内容为空', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. 调用AI生成销号方案
|
||||
const aiRes = await generateWriteoffContent({ rectifyContent: rectifyPlan });
|
||||
if (aiRes.code === 0 && aiRes.data) {
|
||||
formData.mainTreatmentContent = aiRes.data.mainContent || '';
|
||||
formData.treatmentResult = aiRes.data.completionContent || '';
|
||||
formData.selfVerifyContent = aiRes.data.selfInspection || '';
|
||||
uni.showToast({ title: 'AI生成成功', icon: 'success' });
|
||||
} else {
|
||||
uni.showToast({ title: aiRes.msg || 'AI生成失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI生成销号方案失败:', error);
|
||||
uni.showToast({ title: 'AI生成失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
aiGenerating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 确定新增
|
||||
const handleAdd = async () => {
|
||||
if (!selectedHazardId.value) {
|
||||
@@ -369,6 +433,37 @@
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.ai-btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ai-analyze-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #2668EA 100%);
|
||||
border-radius: 36rpx;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ai-btn-icon {
|
||||
margin-right: 8rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-input {
|
||||
background: #fff;
|
||||
border-radius: 8rpx;
|
||||
|
||||
@@ -61,8 +61,14 @@
|
||||
</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="flex margin-bottom margin-top">
|
||||
<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>
|
||||
{{ aiAnalyzing ? 'AI识别中...' : 'AI 识别隐患' }}
|
||||
</button>
|
||||
</view>
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患标题</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
@@ -72,8 +78,14 @@
|
||||
<view class="text-gray">隐患等级</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-choose v-model="formData.level" :options="levelOptions" :wrap="false" item-width="183rpx"
|
||||
item-height="72rpx"></up-choose>
|
||||
<up-choose
|
||||
ref="levelChooseRef"
|
||||
v-model="formData.level"
|
||||
:options="levelOptions"
|
||||
:wrap="false"
|
||||
item-width="183rpx"
|
||||
item-height="72rpx"
|
||||
></up-choose>
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患来源</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -155,7 +167,9 @@
|
||||
ref,
|
||||
computed,
|
||||
reactive,
|
||||
watch
|
||||
watch,
|
||||
nextTick,
|
||||
getCurrentInstance
|
||||
} from 'vue'
|
||||
import {
|
||||
onLoad,
|
||||
@@ -166,7 +180,8 @@
|
||||
enterCheckPlan,
|
||||
getCheckTaskDetail,
|
||||
getMyHiddenDangerList,
|
||||
getHiddenDangerLabelList
|
||||
getHiddenDangerLabelList,
|
||||
analyzeHazardImage
|
||||
} from '@/request/api.js'
|
||||
import { getAreaList } from '@/request/three_one_api/area.js'
|
||||
import {
|
||||
@@ -177,6 +192,9 @@
|
||||
// 弹窗控制
|
||||
const showAddPopup = ref(false);
|
||||
|
||||
// up-choose 组件的 ref
|
||||
const levelChooseRef = ref(null);
|
||||
|
||||
// 获取用户角色,判断是否有验收权限(admin或manage才能验收)
|
||||
const userRole = ref('');
|
||||
const canAcceptance = computed(() => {
|
||||
@@ -236,6 +254,9 @@
|
||||
tagIndex: 0, // 隐患标签索引
|
||||
source: '', // 隐患来源
|
||||
});
|
||||
|
||||
// 用于强制刷新 up-choose 组件的 key
|
||||
const levelChooseKey = ref(0);
|
||||
|
||||
// 经纬度
|
||||
const lng = ref(0);
|
||||
@@ -357,20 +378,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建附件列表 - 从上传返回的url中提取文件名
|
||||
const attachments = fileList1.value.map(file => {
|
||||
// 确保 url 是字符串
|
||||
let url = '';
|
||||
if (typeof file.url === 'string') {
|
||||
url = file.url;
|
||||
} else if (file.url && typeof file.url === 'object') {
|
||||
url = file.url.url || file.url.path || '';
|
||||
}
|
||||
// 从url中提取文件名
|
||||
const fileName = (typeof url === 'string' && url) ? url.split('/').pop() : (file.name || '');
|
||||
const path = file.serverPath || '';
|
||||
const fileName = path ? path.split('/').pop() : (file.name || '');
|
||||
return {
|
||||
fileName: fileName || '',
|
||||
filePath: url || '',
|
||||
filePath: path,
|
||||
fileType: file.type || 'image/png',
|
||||
fileSize: file.size || 0
|
||||
};
|
||||
@@ -511,11 +524,14 @@
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url);
|
||||
let item = fileList1.value[fileListLen];
|
||||
const serverPath = typeof result === 'string' ? result : (result?.url || result?.path || '');
|
||||
fileList1.value.splice(fileListLen, 1, {
|
||||
...item,
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result,
|
||||
// url: baseUrl + serverPath,
|
||||
url: baseUrl.replace('/prod-api', '') + serverPath,
|
||||
serverPath: serverPath,
|
||||
});
|
||||
fileListLen++;
|
||||
}
|
||||
@@ -542,9 +558,62 @@
|
||||
console.error('上传失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// AI 识别隐患
|
||||
const aiAnalyzing = ref(false);
|
||||
const handleAiAnalyze = async () => {
|
||||
const imageFiles = fileList1.value.filter(f => {
|
||||
return f.status === 'success' && f.url.toLowerCase().match(/\.(jpg|jpeg|png|gif|bmp|webp)$/);
|
||||
});
|
||||
if (imageFiles.length === 0) {
|
||||
uni.showToast({ title: '请先上传隐患图片', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const fullImageUrl = imageFiles[0].url;
|
||||
|
||||
aiAnalyzing.value = true;
|
||||
try {
|
||||
console.log('开始调用AI分析接口,图片地址:', fullImageUrl);
|
||||
const analyzeRes = await analyzeHazardImage({
|
||||
// imageUrl: 'https://yx.zhihuixiangxi.com:58880/1.png' ,
|
||||
imageUrl: fullImageUrl ,
|
||||
});
|
||||
|
||||
if (analyzeRes.code === 0 && analyzeRes.data) {
|
||||
const aiData = analyzeRes.data;
|
||||
console.log('AI分析结果:', aiData);
|
||||
|
||||
if (aiData.title) formData.title = aiData.title;
|
||||
if (aiData.description) formData.description = aiData.description;
|
||||
|
||||
if (aiData.level) {
|
||||
const levelMap = { '轻微': 0, '轻微隐患': 0, '一般': 1, '一般隐患': 1, '重大': 2, '重大隐患': 2 };
|
||||
const levelIndex = levelMap[aiData.level];
|
||||
if (levelIndex !== undefined) {
|
||||
formData.level = levelIndex;
|
||||
nextTick(() => {
|
||||
if (levelChooseRef.value && levelChooseRef.value.$data) {
|
||||
levelChooseRef.value.$data.currentIndex = levelIndex;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uni.showToast({ title: 'AI分析完成,已自动填充', icon: 'success', duration: 2000 });
|
||||
} else {
|
||||
uni.showToast({ title: analyzeRes.msg || 'AI分析失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI分析接口调用失败:', error);
|
||||
uni.showToast({ title: 'AI分析失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
aiAnalyzing.value = false;
|
||||
}
|
||||
};
|
||||
const tagOptions = ref([]);
|
||||
const fetchTagOptions = async () => {
|
||||
try {
|
||||
@@ -684,6 +753,37 @@
|
||||
color: #F5222D;
|
||||
}
|
||||
|
||||
.ai-btn-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ai-analyze-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #2668EA 100%);
|
||||
border-radius: 36rpx;
|
||||
border: none;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ai-btn-icon {
|
||||
margin-right: 8rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
width: 600rpx;
|
||||
background: #fff;
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
import { ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { acceptanceRectification, getHiddenDangerDetail } from '@/request/api.js';
|
||||
import { baseUrl,getToken } from '@/request/request.js';
|
||||
import { baseUrl, getToken, toImageUrl } from '@/request/request.js';
|
||||
|
||||
// 页面参数
|
||||
const rectifyId = ref('');
|
||||
@@ -75,9 +75,9 @@
|
||||
const getFullPath = (filePath) => {
|
||||
if (!filePath) return '';
|
||||
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
||||
return filePath;
|
||||
return toImageUrl(filePath);
|
||||
}
|
||||
return baseUrl + filePath;
|
||||
return toImageUrl(filePath);
|
||||
};
|
||||
|
||||
// 图片预览
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
<template>
|
||||
<view class="page padding">
|
||||
<view class="padding bg-white radius">
|
||||
<view class="form-label margin-bottom">
|
||||
<view class="text-gray">整改方案</view>
|
||||
<view class="text-red">*</view>
|
||||
<view class="form-header margin-bottom">
|
||||
<view class="form-label">
|
||||
<view class="text-gray">整改方案</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<button class="ai-rectify-btn" :loading="aiGenerating" :disabled="aiGenerating" @click="handleAiGenerate">
|
||||
<text v-if="!aiGenerating" class="cuIcon-magic ai-btn-icon"></text>
|
||||
{{ aiGenerating ? 'AI生成中...' : 'AI生成整改方案' }}
|
||||
</button>
|
||||
</view>
|
||||
<up-textarea v-model="formData.rectifyPlan" placeholder="请输入内容"></up-textarea>
|
||||
<up-textarea v-model="formData.rectifyPlan" placeholder="请输入内容" :maxlength="-1" autoHeight></up-textarea>
|
||||
<view class="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">整改完成情况</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -78,7 +84,7 @@
|
||||
<script setup>
|
||||
import {ref,reactive,computed} from 'vue'
|
||||
import {onLoad} from '@dcloudio/uni-app'
|
||||
import {submitRectification,getDepartmentPersonUsers,getRectifyDetail,getDeptUsersWithSubordinates} from '@/request/api.js'
|
||||
import {submitRectification,getDepartmentPersonUsers,getRectifyDetail,getDeptUsersWithSubordinates,getHiddenDangerDetail,generateRectifyPlan} from '@/request/api.js'
|
||||
import {baseUrl,getToken} from '@/request/request.js'
|
||||
|
||||
// 从页面参数获取的ID
|
||||
@@ -352,6 +358,45 @@
|
||||
}
|
||||
};
|
||||
|
||||
// AI生成整改方案
|
||||
const aiGenerating = ref(false);
|
||||
const handleAiGenerate = async () => {
|
||||
if (!hazardId.value) {
|
||||
uni.showToast({ title: '缺少隐患信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
aiGenerating.value = true;
|
||||
try {
|
||||
const detailRes = await getHiddenDangerDetail({
|
||||
hazardId: hazardId.value,
|
||||
assignId: assignId.value
|
||||
});
|
||||
|
||||
if (detailRes.code !== 0 || !detailRes.data) {
|
||||
uni.showToast({ title: '获取隐患详情失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { title, description } = detailRes.data;
|
||||
const aiRes = await generateRectifyPlan({ title, description });
|
||||
|
||||
if (aiRes.code === 0 && aiRes.data) {
|
||||
if (aiRes.data.rawResponse) {
|
||||
formData.rectifyPlan = aiRes.data.rawResponse;
|
||||
}
|
||||
uni.showToast({ title: 'AI生成完成', icon: 'success', duration: 2000 });
|
||||
} else {
|
||||
uni.showToast({ title: aiRes.msg || 'AI生成失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('AI生成整改方案失败:', error);
|
||||
uni.showToast({ title: 'AI生成失败,请重试', icon: 'none' });
|
||||
} finally {
|
||||
aiGenerating.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.hazardId) {
|
||||
hazardId.value = options.hazardId;
|
||||
@@ -379,7 +424,42 @@
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
// 表单标签样式 - 让*号和文字对齐
|
||||
.ai-rectify-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60rpx;
|
||||
padding: 0 24rpx;
|
||||
margin: 0;
|
||||
font-size: 24rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #4facfe 0%, #2668EA 100%);
|
||||
border-radius: 30rpx;
|
||||
border: none;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ai-btn-icon {
|
||||
margin-right: 6rpx;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getHiddenDangerDetail } from '@/request/api.js'
|
||||
import { baseUrl } from '@/request/request.js'
|
||||
import { toImageUrl } from '@/request/request.js'
|
||||
|
||||
// 详情数据
|
||||
const detailData = reactive({
|
||||
@@ -89,13 +89,7 @@
|
||||
|
||||
// 获取完整图片路径
|
||||
const getFullPath = (filePath) => {
|
||||
if (!filePath) return '';
|
||||
// 如果已经是完整路径则直接返回
|
||||
if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
|
||||
return filePath;
|
||||
}
|
||||
// 拼接 baseUrl
|
||||
return baseUrl + filePath;
|
||||
return toImageUrl(filePath);
|
||||
};
|
||||
|
||||
// 图片预览 - 隐患图片
|
||||
|
||||
@@ -1,144 +1,170 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<view class="flex padding-top-xl padding-bottom-xl text-white " style="background-color:#007aff ;">
|
||||
<view class="cu-avatar xl round margin-left">
|
||||
<image class="avatar-image" :src="getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="padding-left" style="display: flex;flex-direction: column;gap: 10rpx;justify-content: center;align-items: center;">
|
||||
<view class="text-bold">{{ userInfo.deptName || '未知部门' }}</view>
|
||||
<view class="flex padding-top-xs">
|
||||
<view>用户:</view>
|
||||
<view>{{ userInfo.nickName || userInfo.username || '未登录' }}</view>
|
||||
<!-- 顶部背景区域 -->
|
||||
<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="flex justify-between">
|
||||
<view></view>
|
||||
<view class="cu-btn text-blue margin-top text-bold">切换</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" style="background: #EBF2FC;">
|
||||
<view class="bg-white padding radius">
|
||||
<view class="flex margin-bottom-xl">
|
||||
<view class="border-tite"></view>
|
||||
<view class="margin-left-xs text-bold " >功能菜单</view>
|
||||
</view>
|
||||
<view class=" grid col-3 grid-square">
|
||||
<view class="list " v-for="(item, index) in infoList" :key="index" @click="handleMenuClick(item)">
|
||||
<image style="width: 102rpx;height: 102rpx;" :src="item.src"></image>
|
||||
<view>{{ item.name}}</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="padding bg-white margin-top radius">
|
||||
<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">我的检查计划</view>
|
||||
<!-- <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="list-list padding margin-bottom" v-for="(item, index) in checkPlanData" :key="item.id">
|
||||
<view class="flex">
|
||||
<image src="/static/蒙版组 273.png" style="width: 40rpx;height: 40rpx;"></image>
|
||||
<view class="text-bold margin-left">{{ item.name }}</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="flex margin-top">
|
||||
<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>{{ formatDate(item.planStartTime) }}至{{ formatDate(item.planEndTime) }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top align-center">
|
||||
<view>完成进度:</view>
|
||||
<view class="flex align-center margin-left-sm">
|
||||
<view class="cu-progress round">
|
||||
<view class="bg-green" :style="{ width: item.progress + '%' }"></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>
|
||||
<text class="margin-left-sm">{{ item.progress }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="grid col-4 bg-gray margin padding text-center radius">
|
||||
<view>
|
||||
<view class="text-orange">{{ item.totalCount }}</view>
|
||||
<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>
|
||||
<view class="text-yellow">{{ item.totalCount - item.finishedCount }}</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 class="text-olive">0</view>
|
||||
<view>待验收</view>
|
||||
</view>
|
||||
<view>
|
||||
<view class="text-blue">{{ item.finishedCount }}</view>
|
||||
<view>已完成</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 class="padding bg-white margin-top radius" >
|
||||
<view class="flex margin-bottom-xl ">
|
||||
<view class="border-tite"></view>
|
||||
<view class="text-bold margin-left-xs">我的隐患排查</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>
|
||||
<view class="list-list padding margin-bottom" v-for="(item,index) in hiddenDangerData" :key="item.hazardId">
|
||||
<view class="flex text-bold justify-between">
|
||||
<view class="flex">
|
||||
<view>隐患</view>
|
||||
<view class="text-bold margin-left">#{{ index + 1 }}</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="text-blue">{{item.statusName}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">标题:</view>
|
||||
<view>{{item.title}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">隐患来源:</view>
|
||||
<view>{{item.source}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray" style="white-space: nowrap;">隐患位置:</view>
|
||||
<view>{{item.address}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">隐患等级:</view>
|
||||
<view class="level-tag" :class="{
|
||||
'level-minor': item.levelName === '轻微隐患',
|
||||
'level-normal': item.levelName === '一般隐患',
|
||||
'level-major': item.levelName === '重大隐患'
|
||||
}">{{item.levelName}}</view>
|
||||
}">{{ item.levelName }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">发现时间:</view>
|
||||
<view>{{item.createdAt}}</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="margin-top margin-bottom flex justify-end" style="gap: 10rpx;">
|
||||
<!-- 所有状态都显示查看详情 -->
|
||||
<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>
|
||||
<!-- 待整改状态:canEdit为true时显示隐患交办和立即整改 -->
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="cu-btn round lg light bg-blue" @click.stop="assignHazard(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 === '待验收' && item.canEdit"
|
||||
class="cu-btn round lg light bg-blue" @click.stop="editRectification(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>
|
||||
@@ -154,7 +180,7 @@
|
||||
import {getCheckPlanList,getHiddenDangerList} from '@/request/api.js'
|
||||
import { getProfileDetail } from '@/request/three_one_api/info.js';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { baseUrl } from '@/request/request.js';
|
||||
import { toImageUrl } from '@/request/request.js';
|
||||
const loading = ref(true);
|
||||
|
||||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg';
|
||||
@@ -167,7 +193,8 @@
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
role: '',
|
||||
avatar: ''
|
||||
avatar: '',
|
||||
phone: ''
|
||||
});
|
||||
|
||||
// 获取用户角色,判断是否有验收权限(admin或manage才能验收)
|
||||
@@ -178,8 +205,7 @@
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
return toImageUrl(path);
|
||||
};
|
||||
|
||||
// 获取用户信息(从接口获取)
|
||||
@@ -193,6 +219,7 @@
|
||||
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 || '';
|
||||
@@ -212,49 +239,51 @@
|
||||
userInfo.deptName = info.deptName || '';
|
||||
userInfo.role = info.role || '';
|
||||
userInfo.avatar = info.avatar || '';
|
||||
userInfo.phone = info.phone || '';
|
||||
}
|
||||
} catch (storageError) {
|
||||
console.error('从本地存储获取用户信息失败:', storageError);
|
||||
}
|
||||
}
|
||||
};
|
||||
const infoList = ref([{
|
||||
const infoList = ref([
|
||||
{
|
||||
name: '成员管理',
|
||||
src: '../../static/组 19378.png'
|
||||
src: '/static/home_icon/chengyuangaunli.png'
|
||||
},
|
||||
{
|
||||
name: '企业信息填报',
|
||||
src: '../../static/组 19387.png'
|
||||
name: '信息填报',
|
||||
src: '/static/home_icon/xinxitianbao.png'
|
||||
},
|
||||
{
|
||||
name: '区域设置',
|
||||
src: '../../static/组 20253.png'
|
||||
src: '/static/home_icon/quyushezhi.png'
|
||||
},
|
||||
{
|
||||
name: '检查表',
|
||||
src: '../../static/组 20254.png'
|
||||
name: '检查清单',
|
||||
src: '/static/home_icon/jiachaqingdan.png'
|
||||
},
|
||||
{
|
||||
name: '检查记录',
|
||||
src: '../../static/组 20255.png'
|
||||
src: '/static/home_icon/jianchajilu.png'
|
||||
},
|
||||
{
|
||||
name: '证照管理',
|
||||
src: '../../static/组 20256.png'
|
||||
name: '证件管理',
|
||||
src: '/static/home_icon/zhengjianguanli.png'
|
||||
},
|
||||
{
|
||||
name: '隐患排查',
|
||||
src: '../../static/组 20257.png'
|
||||
src: '/static/home_icon/yinhuanpaicha.png'
|
||||
},
|
||||
{
|
||||
name: '隐患销号申请',
|
||||
src: '../../static/组 20258.png'
|
||||
},
|
||||
{
|
||||
name: '设备登记',
|
||||
src: '../../static/组 20259.png'
|
||||
name: '隐患销号',
|
||||
src: '/static/home_icon/yinhuanxiaohao.png'
|
||||
}
|
||||
|
||||
// ,
|
||||
// {
|
||||
// name: '设备登记',
|
||||
// src: '/static/home_icon/shebeidengji.png'
|
||||
// }
|
||||
]);
|
||||
const ViewDetails = (item) => {
|
||||
uni.navigateTo({
|
||||
@@ -270,15 +299,14 @@
|
||||
const handleMenuClick = (item) => {
|
||||
const menuRoutes = {
|
||||
'成员管理': '/pages/membermanagemen/membermanagemen',
|
||||
'企业信息填报': '/pages/corporateInformation/corporateInformation',
|
||||
'信息填报': '/pages/corporateInformation/corporateInformation',
|
||||
'区域设置':'/pages/area/management',
|
||||
'检查表' :'/pages/checklist/checklist',
|
||||
'检查清单' :'/pages/checklist/checklist',
|
||||
'检查记录': '/pages/Inspectionlog/Inspectionlog',
|
||||
'证照管理': '/pages/Idphotomanagement/Idphotomanagement',
|
||||
'证件管理': '/pages/Idphotomanagement/Idphotomanagement',
|
||||
'隐患排查':'/pages/hiddendanger/Inspection',
|
||||
'隐患销号申请':'/pages/closeout/application',
|
||||
'隐患销号':'/pages/closeout/application',
|
||||
'设备登记':'/pages/equipmentregistration/equipmentregistration',
|
||||
// 可以在这里添加其他菜单的跳转路径
|
||||
};
|
||||
|
||||
const url = menuRoutes[item.name];
|
||||
@@ -336,6 +364,24 @@
|
||||
});
|
||||
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);
|
||||
@@ -392,13 +438,97 @@
|
||||
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: #EBF2FC;
|
||||
background: #F4F7FB;
|
||||
border-radius: 40rpx 40rpx 0rpx 0rpx;
|
||||
margin-top: -30rpx;
|
||||
margin-top: -40rpx;
|
||||
padding: 30rpx;
|
||||
padding-bottom: 50rpx;
|
||||
position: relative;
|
||||
@@ -406,6 +536,42 @@
|
||||
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%;
|
||||
@@ -413,20 +579,6 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
gap: 30rpx;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.list {
|
||||
background: #F2F6FF;
|
||||
box-shadow: 0rpx 4rpx 8rpx 2rpx #CADDFC;
|
||||
border-radius: 10rpx;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
|
||||
}
|
||||
|
||||
.list-list {
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
|
||||
@@ -435,6 +587,67 @@
|
||||
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;
|
||||
@@ -499,4 +712,62 @@
|
||||
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>
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
import { baseUrl, getToken, toImageUrl } from '@/request/request.js';
|
||||
import { getProfileDetail, updateProfile } from '@/request/three_one_api/info.js';
|
||||
|
||||
const saving = ref(false);
|
||||
@@ -85,8 +85,7 @@ const userInfo = reactive({
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
return toImageUrl(path);
|
||||
};
|
||||
|
||||
// 页面加载时获取个人信息
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { baseUrl } from '@/request/request.js';
|
||||
import { toImageUrl } from '@/request/request.js';
|
||||
import { getProfileDetail } from '@/request/three_one_api/info.js';
|
||||
|
||||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg';
|
||||
@@ -108,8 +108,7 @@
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
return toImageUrl(path);
|
||||
};
|
||||
|
||||
// 获取用户信息
|
||||
|
||||
Reference in New Issue
Block a user