一单四制优化及加入工作流

This commit is contained in:
王利强
2026-07-27 09:27:22 +08:00
parent 455fd4fc07
commit 7c3285ed5a
725 changed files with 19668 additions and 2921 deletions

View File

@@ -19,7 +19,6 @@
</view>
<view class="flex margin-bottom">
<view class="text-gray">创建时间</view>
<view class="text-black">{{item.createdAt}}</view>
</view>
<view class="flex justify-between">
@@ -27,306 +26,32 @@
<view><button class="bg-blue round cu-btn lg" @click="editor(item)">查看详情</button></view>
</view>
</view>
<button class="cuIcon-add bg-blue round margin-top" @click="openAddPopup">新增</button>
<!-- 弹出框 -->
<u-popup :show="showAddPopup" mode="center" round="20" :safeAreaInsetBottom="false" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">新增销号申请</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<scroll-view class="popup-body" scroll-y :style="{ height: '60vh' }">
<view class="flex margin-bottom">
<view>隐患</view>
<view class="text-red">*</view>
</view>
<view class="picker-input" @click="showHazardPicker = true">
<text :class="selectedHazard ? '' : 'text-gray'">{{ selectedHazard || '请选择隐患' }}</text>
</view>
<up-picker
v-if="false" :show="showHazardPicker"
:columns="hazardColumns"
@confirm="onHazardConfirm"
@cancel="showHazardPicker = false"
@close="showHazardPicker = false"
></up-picker>
<view class="flex margin-bottom margin-top">
<view>整改时限</view>
</view>
<view class="picker-input readonly">
<text :class="formData.rectifyDeadline ? '' : 'text-gray'">{{ formData.rectifyDeadline || '请先选择隐患' }}</text>
</view>
<view class="margin-bottom margin-top">隐患治理责任单位</view>
<view class="picker-input readonly">
<text :class="selectedDeptName ? '' : 'text-gray'">{{ selectedDeptName || '请先选择隐患' }}</text>
</view>
<view class="margin-bottom margin-top">主要负责人</view>
<view class="picker-input readonly">
<text :class="formData.responsiblePerson ? '' : 'text-gray'">{{ formData.responsiblePerson || '请先选择隐患' }}</text>
</view>
<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>
<view class="margin-bottom margin-top">隐患治理责任单位自行验收的情况</view>
<up-textarea v-model="formData.selfVerifyContent" placeholder="请输入隐患治理责任单位自行验收的情况"></up-textarea>
<view class="flex margin-bottom margin-top">
<view class="text-gray">下一步流程</view>
<view class="text-red">*</view>
</view>
<view class="static-field">隐患销号审批</view>
<view class="flex margin-bottom margin-top">
<view class="text-gray">下一步处理人</view>
<view class="text-red">*</view>
</view>
<view class="static-field">部门企业管理员</view>
<view class="flex margin-bottom margin-top">
<view class="text-gray">短信提醒</view>
<view class="text-red">*</view>
</view>
<up-radio-group v-model="sendMsgFlagRadio" placement="row" activeColor="#2667e9">
<up-radio
label="是"
name="yes"
:customStyle="{ marginRight: '48rpx' }"
></up-radio>
<up-radio label="否" name="no"></up-radio>
</up-radio-group>
</scroll-view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
</view>
</view>
</u-popup>
<!-- 移出到外层的选择器组件防止其定位样式被 scroll-view 剪裁并导致暗色遮罩溢出异常 -->
<up-picker
:show="showHazardPicker"
:columns="hazardColumns"
@confirm="onHazardConfirm"
@cancel="showHazardPicker = false"
@close="showHazardPicker = false"
></up-picker>
<button class="cuIcon-add bg-blue round margin-top" @click="goAddApply">新增</button>
</view>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { getMyWriteOffList, applyDelete, getAcceptanceList, getHiddenDangerDetail, getRectifyDetail, generateWriteoffContent } from '@/request/api.js';
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { getMyWriteOffList } from '@/request/api.js';
// 弹窗控制
const showAddPopup = ref(false);
const showHazardPicker = ref(false);
// 隐患选择
const selectedHazard = ref('');
const selectedHazardId = ref('');
const hazardColumns = ref([['暂无数据']]);
const acceptanceHazardList = ref([]); // 存储可申请销号的隐患数据
const hazardList = ref([]); // 存储销号申请列表
// 隐患关联的只读展示字段
const selectedDeptName = ref('');
// AI生成状态
const aiGenerating = ref(false);
const hazardList = ref([]);
// 短信提醒
const sendMsgFlagRadio = ref('yes');
const sendMsgFlag = computed(() => sendMsgFlagRadio.value === 'yes');
// 表单数据
const formData = reactive({
rectifyDeadline: '', // 整改时限
responsibleDeptId: '', // 隐患治理责任单位ID
responsiblePerson: '', // 主要负责人
mainTreatmentContent: '', // 主要治理内容
treatmentResult: '', // 隐患治理完成内容
selfVerifyContent: '' // 责任单位自行验收情况
});
// 获取销号申请列表(页面显示用)
const fetchWriteOffList = async () => {
try {
const res = await getMyWriteOffList();
if (res.code === 0 && res.data) {
hazardList.value = res.data;
console.log('销号申请列表:', res.data);
}
} catch (error) {
console.error('获取销号申请列表失败:', error);
}
};
// 获取可申请销号的隐患列表(弹窗选择用)
const fetchAcceptanceList = async () => {
try {
const res = await getAcceptanceList();
if (res.code === 0 && res.data) {
const list = res.data.records || res.data || [];
acceptanceHazardList.value = list;
// 转换为 picker 需要的格式
if (list.length > 0) {
hazardColumns.value = [list.map(item => item.title || item.hazardTitle || `隐患${item.hazardId}`)];
} else {
hazardColumns.value = [['暂无可申请销号的隐患']];
}
console.log('可申请销号的隐患列表:', list);
}
} catch (error) {
console.error('获取可申请销号隐患列表失败:', error);
}
const goAddApply = () => {
uni.navigateTo({ url: '/pages/closeout/apply' });
};
// 打开新增弹窗
const openAddPopup = () => {
resetForm();
fetchAcceptanceList(); // 获取可申请销号的隐患列表
showAddPopup.value = true;
};
// 根据选中的隐患回显只读字段
const fillHazardRelatedFields = (hazard) => {
formData.rectifyDeadline = hazard.deadline || '';
selectedDeptName.value = hazard.deptName || '';
formData.responsiblePerson = hazard.rectifierName || '';
formData.responsibleDeptId = hazard.deptId || '';
};
// 隐患选择确认
const onHazardConfirm = (e) => {
console.log('选择的隐患:', e);
if (e.value && e.value.length > 0) {
selectedHazard.value = e.value[0];
const index = e.indexs[0];
const hazard = acceptanceHazardList.value[index];
if (hazard) {
selectedHazardId.value = hazard.hazardId;
fillHazardRelatedFields(hazard);
}
}
showHazardPicker.value = false;
};
// 重置表单
const resetForm = () => {
selectedHazard.value = '';
selectedHazardId.value = '';
selectedDeptName.value = '';
formData.rectifyDeadline = '';
formData.responsibleDeptId = '';
formData.responsiblePerson = '';
formData.mainTreatmentContent = '';
formData.treatmentResult = '';
formData.selfVerifyContent = '';
sendMsgFlagRadio.value = 'yes';
};
// 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) {
uni.showToast({ title: '请选择隐患', icon: 'none' });
return;
}
// 构建请求参数(与接口文档对应)
const params = {
hazardId: Number(selectedHazardId.value), // 隐患ID必需
rectifyDeadline: formData.rectifyDeadline || '', // 整改时限
responsibleDeptId: Number(formData.responsibleDeptId) || 0, // 隐患治理责任单位ID
responsiblePerson: formData.responsiblePerson || '', // 主要负责人
mainTreatmentContent: formData.mainTreatmentContent || '', // 主要治理内容
treatmentResult: formData.treatmentResult || '', // 隐患治理完成内容
selfVerifyContent: formData.selfVerifyContent || '', // 责任单位自行验收情况
sendMsgFlag: sendMsgFlag.value // 是否短信提醒
};
console.log('提交数据:', params);
try {
const res = await applyDelete(params);
if (res.code === 0) {
uni.showToast({ title: '申请成功', icon: 'success' });
showAddPopup.value = false;
resetForm();
// 刷新销号申请列表
fetchWriteOffList();
} else {
uni.showToast({ title: res.msg || '申请失败', icon: 'none' });
}
} catch (error) {
console.error('申请失败:', error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
const editor = (item) => {
if (!item?.id) {
uni.showToast({ title: '缺少申请ID', icon: 'none' });
@@ -336,8 +61,7 @@
url: `/pages/closeout/editor?applyId=${item.id}`
});
};
// 根据审核状态返回对应样式类
const getStatusClass = (item) => {
const statusName = item?.verifyResultName || '';
if (statusName === '待审核') return 'status-pending';
@@ -348,9 +72,8 @@
if (item?.verifyResult === 2) return 'status-rejected';
return 'status-default';
};
// 页面加载时获取销号申请列表
onMounted(() => {
onShow(() => {
fetchWriteOffList();
});
</script>
@@ -397,120 +120,4 @@
background: #F5F5F5;
color: #8C8C8C;
}
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.popup-title {
font-size: 32rpx;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
line-height: 1;
}
}
.popup-body {
padding: 30rpx;
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
button {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
margin: 0 !important;
padding: 0 !important;
font-size: 30rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #fff;
color: #666;
}
.btn-confirm {
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;
padding: 24rpx 20rpx;
margin-bottom: 20rpx;
border: 1rpx solid #eee;
text {
font-size: 28rpx;
}
&.readonly {
background: #f5f5f5;
color: #666;
}
}
.static-field {
background: #fff;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 20rpx 24rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
color: #333;
line-height: 1.5;
}
</style>
</style>