优化后,再次提交
This commit is contained in:
@@ -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);
|
||||
};
|
||||
|
||||
// 图片预览 - 隐患图片
|
||||
|
||||
Reference in New Issue
Block a user