Files
threeonecheck_web/pages/editchecklist/editchecklist.vue
2026-02-08 09:30:43 +08:00

1633 lines
41 KiB
Vue
Raw Permalink 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="page">
<view class="form-card">
<!-- 检查表名称 -->
<view class="form-item">
<view class="form-label">
<text>检查表名称</text>
<text class="required">*</text>
</view>
<up-input v-model="formData.name" placeholder="请输入检查表名称" border="surround"></up-input>
</view>
<!-- 分派单位 -->
<view class="form-item">
<view class="form-label">
<text>分派单位</text>
<text class="required">*</text>
</view>
<view class="picker-input" @click="showDeptPicker = true">
<text :class="formData.deptName ? 'picker-value' : 'picker-placeholder'">
{{ formData.deptName || '请选择分派单位' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-picker
:show="showDeptPicker"
:columns="deptCascaderColumns"
:defaultIndex="deptCascaderIndexs"
@confirm="onDeptConfirm"
@change="onDeptCascaderChange"
@cancel="showDeptPicker = false"
@close="showDeptPicker = false"
></up-picker>
</view>
<!-- 补充说明 -->
<view class="form-item">
<view class="form-label">
<text>补充说明</text>
</view>
<up-textarea v-model="formData.remark" placeholder="请输入补充说明"></up-textarea>
</view>
<!-- 检查表类型 -->
<view class="form-item">
<view class="form-label">
<text>检查表类型</text>
</view>
<view class="picker-input" @click="showTypePicker = true">
<text :class="formData.typeName ? 'picker-value' : 'picker-placeholder'">
{{ formData.typeName || '请选择检查表类型' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-picker
:show="showTypePicker"
:columns="typeColumns"
@confirm="onTypeConfirm"
@cancel="showTypePicker = false"
@close="showTypePicker = false"
></up-picker>
</view>
<!-- 运行模式 -->
<view class="form-item">
<view class="form-label">
<text>运行模式</text>
</view>
<view class="picker-input" @click="showModePicker = true">
<text :class="formData.modeName ? 'picker-value' : 'picker-placeholder'">
{{ formData.modeName || '请选择运行模式' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-picker
:show="showModePicker"
:columns="modeColumns"
@confirm="onModeConfirm"
@cancel="showModePicker = false"
@close="showModePicker = false"
></up-picker>
</view>
<!-- 执行人员仅当运行模式为"指定人员"时显示 -->
<view class="form-item" v-if="formData.modeName === '指定人员'">
<view class="form-label">
<text>执行人员</text>
</view>
<view class="picker-input" @click="openExecutorPopup">
<text :class="formData.executorNames ? 'picker-value' : 'picker-placeholder'">
{{ formData.executorNames || '请选择执行人员' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
</view>
<!-- 周期 -->
<view class="form-item">
<view class="form-label">
<text>周期</text>
</view>
<view class="picker-input" @click="showCyclePicker = true">
<text :class="formData.cycleName ? 'picker-value' : 'picker-placeholder'">
{{ formData.cycleName || '请选择周期' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-picker
:show="showCyclePicker"
:columns="cycleColumns"
@confirm="onCycleConfirm"
@cancel="showCyclePicker = false"
@close="showCyclePicker = false"
></up-picker>
</view>
<!-- 工作日开关 -->
<view class="form-item">
<view class="form-label">
<text>工作日开关</text>
</view>
<view class="switch-row">
<switch :checked="workdaySwitch" @change="onSwitchChange" color="#07C160" />
</view>
</view>
<!-- 开始时间 -->
<view class="form-item">
<view class="form-label">
<text>开始时间</text>
</view>
<view class="picker-input" @click="showStartDatePicker = true">
<text :class="formData.startDate ? 'picker-value' : 'picker-placeholder'">
{{ formData.startDate || '请选择开始时间' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-datetime-picker
:show="showStartDatePicker"
mode="datetime"
v-model="startDateValue"
@confirm="onStartDateConfirm"
@cancel="showStartDatePicker = false"
@close="showStartDatePicker = false"
></up-datetime-picker>
</view>
<!-- 结束时间 -->
<view class="form-item">
<view class="form-label">
<text>结束时间</text>
</view>
<view class="picker-input" @click="showEndDatePicker = true">
<text :class="formData.endDate ? 'picker-value' : 'picker-placeholder'">
{{ formData.endDate || '请选择结束时间' }}
</text>
<text class="cuIcon-unfold picker-arrow"></text>
</view>
<up-datetime-picker
:show="showEndDatePicker"
mode="datetime"
v-model="endDateValue"
@confirm="onEndDateConfirm"
@cancel="showEndDatePicker = false"
@close="showEndDatePicker = false"
></up-datetime-picker>
</view>
<!-- 已添加的检查项 -->
<view class="form-item">
<view class="form-label label-blue">
<text>已添加的检查项{{ checkItemCount }}</text>
</view>
<!-- 空状态提示 -->
<view v-if="checkItemCount === 0" class="empty-check-tip">
<text class="text-gray">暂无检查项目请添加</text>
</view>
<!-- 手动添加的检查项卡片 -->
<view class="check-card manual-card" v-for="(item, index) in manualCheckItems" :key="'manual-' + index">
<view class="card-tag">{{ index + 1 }}</view>
<view class="check-info">
<view class="info-row">
<text class="info-label">检查项名称</text>
<text class="info-value">{{ item.name }}</text>
</view>
<view class="info-row">
<text class="info-label">检查内容</text>
<text class="info-value">{{ item.point }}</text>
</view>
<view class="info-row">
<text class="info-label">参考法规</text>
<text class="info-value">{{ item.regulationName || '-' }}</text>
</view>
</view>
<view class="check-action">
<button class="btn-delete" @click="deleteManualCheckItem(item, index)">删除</button>
</view>
</view>
<!-- 从检查库添加的检查项卡片 -->
<view class="check-card" v-for="(item, index) in checkItems" :key="'lib-' + index">
<view class="check-info">
<view class="info-row">
<text class="info-label">关联表名</text>
<text class="info-value">{{ item.tableName }}</text>
</view>
<view class="info-row">
<text class="info-label">检查项数量</text>
<text class="info-value">{{ item.count }}</text>
</view>
</view>
<view class="check-action">
<button class="btn-delete" @click="deleteCheckItem(index)">删除</button>
</view>
</view>
</view>
<!-- 添加检查项 -->
<view class="form-item">
<view class="form-label label-blue">
<text>添加检查项</text>
</view>
<view class="add-btns">
<button class="btn-add" @click="showAddPopup = true">手动添加</button>
<button class="btn-add" @click="openLibraryPopup">从检查库添加</button>
</view>
</view>
<!-- <view style="height: 20px;"></view> -->
</view>
<!-- 保存按钮 -->
<view class="footer-btn">
<button class="btn-save" @click="handleSave">保存</button>
</view>
<!-- 手动添加检查项弹出框 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title">手动添加检查项</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<view class="popup-form-item">
<view class="popup-form-label">检查名称<text class="required">*</text></view>
<up-input v-model="checkForm.name" placeholder="请输入检查名称" border="surround"></up-input>
</view>
<view class="popup-form-item">
<view class="popup-form-label">检查内容<text class="required">*</text></view>
<up-textarea v-model="checkForm.point" placeholder="请输入检查内容" :height="150"></up-textarea>
</view>
<view class="popup-form-item">
<view class="popup-form-label">参考法规</view>
<view class="popup-select regulation-select" @click="openLawPopup">
<text class="regulation-text" :class="checkForm.regulationName ? '' : 'text-gray'">{{ checkForm.regulationName || '选择法规' }}</text>
<text class="cuIcon-unfold select-icon"></text>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm" @click="handleAddCheck">确定</button>
</view>
</view>
</u-popup>
<!-- 选择法规弹出框 -->
<u-popup :show="showLawPopup" mode="center" round="20" @close="showLawPopup = false">
<view class="law-popup">
<view class="popup-header">
<view class="popup-title">选择参考法规</view>
<view class="popup-close" @click="showLawPopup = false">×</view>
</view>
<view class="search-box">
<text class="cuIcon-search search-icon"></text>
<input class="search-input" v-model="lawKeyword" placeholder="请输入关键词搜索" @confirm="searchRegulation" />
<text class="search-btn" @click="searchRegulation">搜索</text>
</view>
<scroll-view class="law-list" scroll-y @scrolltolower="loadMoreLaw">
<view v-if="lawLoading && lawList.length === 0" class="loading-tip">加载中...</view>
<view v-else-if="!lawLoading && lawList.length === 0" class="empty-tip">暂无数据</view>
<template v-else>
<view
class="law-item"
:class="{ 'law-item-active': selectedLawId === item.id }"
v-for="item in lawList"
:key="item.id"
@click="selectLaw(item)"
>
<view class="law-title">{{ item.depict }}</view>
<view class="law-basis text-gray">{{ item.legalBasis }}</view>
</view>
<view v-if="lawLoading" class="loading-tip">加载中...</view>
</template>
</scroll-view>
<view class="popup-footer">
<button class="btn-cancel" @click="showLawPopup = false">取消</button>
<button class="btn-confirm" @click="confirmLaw">确定</button>
</view>
</view>
</u-popup>
<!-- 从检查库添加弹出框 -->
<u-popup :show="showLibraryPopup" mode="center" round="20" @close="closeLibraryPopup">
<view class="library-popup">
<view class="popup-header">
<view class="popup-title">选择检查库</view>
<view class="popup-close" @click="closeLibraryPopup">×</view>
</view>
<view class="search-box">
<text class="cuIcon-search search-icon"></text>
<input class="search-input" v-model="libraryKeyword" placeholder="请输入关键词搜索" @confirm="searchLibrary" />
<text class="search-btn" @click="searchLibrary">搜索</text>
</view>
<scroll-view class="library-list" scroll-y @scrolltolower="loadMoreLibrary">
<view v-if="libraryLoading && libraryList.length === 0" class="loading-tip">加载中...</view>
<view v-else-if="!libraryLoading && libraryList.length === 0" class="empty-tip">暂无数据</view>
<template v-else>
<view
class="library-item"
v-for="item in libraryList"
:key="item.id"
@click="toggleLibrarySelect(item)"
>
<view class="library-checkbox" :class="{ 'library-checkbox-active': selectedLibraries.includes(item.id) }">
<text v-if="selectedLibraries.includes(item.id)" class="cuIcon-check"></text>
</view>
<view class="library-info">
<view class="library-name">关联表名{{ item.name }}</view>
<view class="library-count">{{ item.pointCount }}</view>
</view>
</view>
<view v-if="libraryLoading" class="loading-tip">加载中...</view>
</template>
</scroll-view>
<button class="btn-add-library" @click="addSelectedLibrary">添加选中项</button>
</view>
</u-popup>
<!-- 执行人员选择弹窗 -->
<u-popup :show="showExecutorPopup" mode="center" round="20" @close="showExecutorPopup = false">
<view class="executor-popup">
<view class="popup-header">
<view class="popup-title">选择执行人员</view>
<view class="popup-close" @click="showExecutorPopup = false">×</view>
</view>
<scroll-view class="executor-list" scroll-y>
<view v-if="executorList.length === 0" class="empty-tip">暂无人员数据</view>
<view
v-else
class="executor-item"
v-for="item in executorList"
:key="item.userId"
@click="toggleExecutorSelect(item)"
>
<view class="executor-checkbox" :class="{ 'executor-checkbox-active': selectedExecutorIds.includes(item.userId) }">
<text v-if="selectedExecutorIds.includes(item.userId)" class="cuIcon-check"></text>
</view>
<view class="executor-info">
<text class="executor-name">{{ item.nickName }}</text>
</view>
</view>
</scroll-view>
<view class="popup-footer">
<button class="btn-cancel" @click="showExecutorPopup = false">取消</button>
<button class="btn-confirm" @click="confirmExecutorSelect">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { getRegulationList, addCheckPoint, detailcheckPoint, deleteCheckPoint, getCheckItemList, getCheckItemListDetail, getDeptUsers, getParentDepts, addCheckTable } from '@/request/api.js';
import { onMounted } from 'vue';
// 表单数据
const formData = reactive({
name: '',
deptId: '',
deptName: '',
remark: '',
type: '', // 检查表类型1-日常检查2-专项检查3-设备检查
typeName: '',
modeId: '',
modeName: '',
selectDeptId: '',
selectDeptName: '',
executorIds: [], // 执行人员ID数组
executorNames: '', // 执行人员名称(显示用)
cycleId: '',
cycleName: '',
startDate: '',
endDate: ''
});
// 工作日开关(单独定义避免页面闪烁)
const workdaySwitch = ref(false);
const onSwitchChange = (e) => {
workdaySwitch.value = e.detail.value;
};
// 日期选择器值
const startDateValue = ref(Number(new Date()));
const endDateValue = ref(Number(new Date()));
// 选择器显示控制
const showDeptPicker = ref(false);
const showTypePicker = ref(false);
const showModePicker = ref(false);
const showDeptSelectPicker = ref(false);
const showCyclePicker = ref(false);
const showStartDatePicker = ref(false);
const showEndDatePicker = ref(false);
// 选择器数据
const deptColumns = ref([['湘西自治州和谐网络科技有限公司', '湘西自治州和谐云大数据科技有限公司', '湘西网络有限公司']]);
const typeColumns = ref([['日常检查', '专项检查', '设备检查']]);
const modeColumns = ref([['全员', '指定人员']]);
const cycleColumns = ref([['每天一次', '每周一次', '每月一次', '每季度一次']]);
// 执行人员选择器
const showExecutorPopup = ref(false);
const executorList = ref([]);
const selectedExecutorIds = ref([]);
// 分派单位级联选择器
const deptTree = ref([]);
const deptCascaderColumns = ref([]);
const deptCascaderIndexs = ref([0]);
const selectedDeptPath = ref([]); // 选中的路径
// 选择器确认回调
const onDeptConfirm = (e) => {
// 获取最后选中的部门
const lastSelected = selectedDeptPath.value[selectedDeptPath.value.length - 1];
if (lastSelected) {
formData.deptId = lastSelected.deptId;
formData.deptName = selectedDeptPath.value.map(d => d.deptName).join(' / ');
}
showDeptPicker.value = false;
};
// 检查表类型映射:日常检查->1, 专项检查->2, 设备检查->3
const typeMap = {
'日常检查': 1,
'专项检查': 2,
'设备检查': 3
};
const onTypeConfirm = (e) => {
if (e.value && e.value.length > 0) {
formData.typeName = e.value[0];
formData.type = typeMap[e.value[0]];
}
showTypePicker.value = false;
};
const onModeConfirm = (e) => {
if (e.value && e.value.length > 0) {
formData.modeName = e.value[0];
// 如果切换到全员,清空执行人员选择
if (e.value[0] === '全员') {
formData.executorIds = [];
formData.executorNames = '';
selectedExecutorIds.value = [];
}
}
showModePicker.value = false;
};
// 获取当前部门用户列表
const fetchDeptUsers = async () => {
try {
const res = await getDeptUsers();
if (res.code === 0 && res.data) {
executorList.value = res.data || [];
}
} catch (error) {
console.error('获取部门用户失败:', error);
}
};
// 切换执行人员选择
const toggleExecutorSelect = (item) => {
const index = selectedExecutorIds.value.indexOf(item.userId);
if (index > -1) {
selectedExecutorIds.value.splice(index, 1);
} else {
selectedExecutorIds.value.push(item.userId);
}
};
// 确认执行人员选择
const confirmExecutorSelect = () => {
formData.executorIds = [...selectedExecutorIds.value];
const selectedUsers = executorList.value.filter(u => selectedExecutorIds.value.includes(u.userId));
formData.executorNames = selectedUsers.map(u => u.nickName).join('、');
showExecutorPopup.value = false;
};
// 打开执行人员选择弹窗
const openExecutorPopup = () => {
selectedExecutorIds.value = [...formData.executorIds];
showExecutorPopup.value = true;
};
// 获取父级部门列表(树形结构)
const fetchParentDepts = async () => {
try {
const res = await getParentDepts();
if (res.code === 0 && res.data) {
deptTree.value = res.data;
// 初始化级联选择器第一列
initDeptCascader(res.data);
}
} catch (error) {
console.error('获取部门树失败:', error);
}
};
// 初始化部门级联选择器
const initDeptCascader = (data) => {
if (!data) return;
// 第一列数据
const firstColumn = buildDeptColumn(data);
deptCascaderColumns.value = [firstColumn];
deptCascaderIndexs.value = [0];
selectedDeptPath.value = [data];
// 如果有子级,添加下一列
if (data.children && data.children.length > 0) {
const secondColumn = data.children.map(item => ({ text: item.deptName, ...item }));
deptCascaderColumns.value.push(secondColumn);
deptCascaderIndexs.value.push(0);
selectedDeptPath.value.push(data.children[0]);
// 检查是否还有下一级
if (data.children[0].children && data.children[0].children.length > 0) {
const thirdColumn = data.children[0].children.map(item => ({ text: item.deptName, ...item }));
deptCascaderColumns.value.push(thirdColumn);
deptCascaderIndexs.value.push(0);
selectedDeptPath.value.push(data.children[0].children[0]);
}
}
};
// 构建部门列数据
const buildDeptColumn = (data) => {
return [{ text: data.deptName, ...data }];
};
// 部门级联选择器列改变
const onDeptCascaderChange = (e) => {
const { columnIndex, index, value } = e;
// 更新当前列的选中索引
deptCascaderIndexs.value[columnIndex] = index;
// 更新选中路径
selectedDeptPath.value[columnIndex] = value;
// 删除后续列
deptCascaderColumns.value = deptCascaderColumns.value.slice(0, columnIndex + 1);
deptCascaderIndexs.value = deptCascaderIndexs.value.slice(0, columnIndex + 1);
selectedDeptPath.value = selectedDeptPath.value.slice(0, columnIndex + 1);
// 如果有子级,添加新列
if (value.children && value.children.length > 0) {
const nextColumn = value.children.map(item => ({ text: item.deptName, ...item }));
deptCascaderColumns.value.push(nextColumn);
deptCascaderIndexs.value.push(0);
selectedDeptPath.value.push(value.children[0]);
// 继续检查是否有下下级
if (value.children[0].children && value.children[0].children.length > 0) {
const thirdColumn = value.children[0].children.map(item => ({ text: item.deptName, ...item }));
deptCascaderColumns.value.push(thirdColumn);
deptCascaderIndexs.value.push(0);
selectedDeptPath.value.push(value.children[0].children[0]);
}
}
};
const onDeptSelectConfirm = (e) => {
if (e.value && e.value.length > 0) {
formData.selectDeptName = e.value[0];
}
showDeptSelectPicker.value = false;
};
const onCycleConfirm = (e) => {
if (e.value && e.value.length > 0) {
formData.cycleName = e.value[0];
}
showCyclePicker.value = false;
};
// 日期时间格式化(精确到时分秒)
const formatDateTime = (timestamp) => {
const date = new Date(timestamp);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
const onStartDateConfirm = (e) => {
formData.startDate = formatDateTime(e.value);
showStartDatePicker.value = false;
};
const onEndDateConfirm = (e) => {
formData.endDate = formatDateTime(e.value);
showEndDatePicker.value = false;
};
// 手动添加的检查项列表
const manualCheckItems = ref([]);
// 从检查库添加的检查项
const checkItems = ref([]);
// 检查项数量(手动添加的数量 + 检查库的数量)
const checkItemCount = computed(() => {
const libraryCount = checkItems.value.reduce((sum, item) => sum + item.count, 0);
return manualCheckItems.value.length + libraryCount;
});
// 删除手动添加的检查项(调用接口删除)
const deleteManualCheckItem = (item, index) => {
uni.showModal({
title: '提示',
content: '确定要删除该检查项吗?',
confirmColor: '#F56C6C',
success: async (res) => {
if (res.confirm) {
// 手动添加的检查项有id需要调用接口删除
if (item.id) {
try {
uni.showLoading({ title: '删除中...' });
const result = await deleteCheckPoint({ id: item.id });
uni.hideLoading();
if (result.code === 0) {
manualCheckItems.value.splice(index, 1);
uni.showToast({ title: '删除成功', icon: 'success' });
} else {
uni.showToast({ title: result.msg || '删除失败', icon: 'none' });
}
} catch (error) {
uni.hideLoading();
console.error('删除检查项失败:', error);
uni.showToast({ title: '删除失败', icon: 'none' });
}
} else {
// 没有id的情况理论上不应该出现直接从本地移除
manualCheckItems.value.splice(index, 1);
uni.showToast({ title: '删除成功', icon: 'success' });
}
}
}
});
};
// 删除检查库中的检查项(只从本地暂存删除,不调用接口)
const deleteCheckItem = (index) => {
uni.showModal({
title: '提示',
content: '确定要删除该检查项吗?',
confirmColor: '#F56C6C',
success: (res) => {
if (res.confirm) {
checkItems.value.splice(index, 1);
uni.showToast({ title: '删除成功', icon: 'success' });
}
}
});
};
// 手动添加检查项弹窗
const showAddPopup = ref(false);
const checkForm = reactive({
name: '', // 检查名称
point: '', // 检查内容
regulationId: null, // 参考法规ID
regulationName: '' // 参考法规名称(显示用)
});
// 选择法规弹窗
const showLawPopup = ref(false);
const lawKeyword = ref('');
const selectedLawId = ref(null);
const selectedLawName = ref('');
const lawList = ref([]);
const lawLoading = ref(false);
const lawPageNum = ref(1);
const lawPageSize = ref(10);
const hasMoreLaw = ref(true);
// 打开法规选择弹窗
const openLawPopup = () => {
showLawPopup.value = true;
// 如果列表为空,加载数据
if (lawList.value.length === 0) {
fetchRegulationList();
}
};
// 获取法规列表
const fetchRegulationList = async (isLoadMore = false) => {
if (lawLoading.value) return;
lawLoading.value = true;
try {
// 构建参数,只传有值的字段
const params = {
pageNum: lawPageNum.value,
pageSize: lawPageSize.value,
status: 1 // 启用状态
};
// keyword 有值时才传
if (lawKeyword.value && lawKeyword.value.trim()) {
params.keyword = lawKeyword.value.trim();
}
const res = await getRegulationList(params);
if (res.code === 0) {
const records = res.data.records || res.data || [];
if (isLoadMore) {
lawList.value = [...lawList.value, ...records];
} else {
lawList.value = records;
}
// 判断是否还有更多
const total = res.data.total || 0;
hasMoreLaw.value = lawList.value.length < total;
}
} catch (error) {
console.error('获取法规列表失败:', error);
} finally {
lawLoading.value = false;
}
};
// 搜索法规
const searchRegulation = () => {
lawPageNum.value = 1;
lawList.value = [];
hasMoreLaw.value = true;
fetchRegulationList();
};
// 加载更多法规
const loadMoreLaw = () => {
if (!hasMoreLaw.value || lawLoading.value) return;
lawPageNum.value++;
fetchRegulationList(true);
};
// 选择法规
const selectLaw = (item) => {
selectedLawId.value = item.id;
// 用 depict描述作为显示名称
selectedLawName.value = item.depict || item.keyword || '';
};
// 确认选择法规
const confirmLaw = () => {
if (selectedLawId.value) {
checkForm.regulationId = selectedLawId.value;
checkForm.regulationName = selectedLawName.value;
}
showLawPopup.value = false;
};
// 提交手动添加的检查项
const handleAddCheck = async () => {
if (!checkForm.name) {
uni.showToast({ title: '请输入检查名称', icon: 'none' });
return;
}
if (!checkForm.point) {
uni.showToast({ title: '请输入检查内容', icon: 'none' });
return;
}
try {
uni.showLoading({ title: '添加中...' });
// 调用接口新增检查项
const params = {
name: checkForm.name,
point: checkForm.point,
regulationId: checkForm.regulationId || undefined
};
const res = await addCheckPoint(params);
if (res.code === 0) {
// 新增成功后,获取详情
const checkPointId = res.data?.id || res.data;
if (checkPointId) {
const detailRes = await detailcheckPoint(checkPointId);
if (detailRes.code === 0 && detailRes.data) {
// 添加到手动检查项列表
manualCheckItems.value.push({
id: detailRes.data.id,
name: detailRes.data.name,
point: detailRes.data.point,
regulationId: detailRes.data.regulationId,
regulationName: detailRes.data.regulationName || checkForm.regulationName
});
}
} else {
// 如果没有返回ID直接用表单数据添加
manualCheckItems.value.push({
name: checkForm.name,
point: checkForm.point,
regulationId: checkForm.regulationId,
regulationName: checkForm.regulationName
});
}
uni.hideLoading();
uni.showToast({ title: '添加成功', icon: 'success' });
showAddPopup.value = false;
// 重置表单
checkForm.name = '';
checkForm.point = '';
checkForm.regulationId = null;
checkForm.regulationName = '';
} else {
uni.hideLoading();
uni.showToast({ title: res.msg || '添加失败', icon: 'none' });
}
} catch (error) {
uni.hideLoading();
console.error('添加检查项失败:', error);
uni.showToast({ title: '添加失败', icon: 'none' });
}
};
// 从检查库添加弹窗
const showLibraryPopup = ref(false);
const libraryKeyword = ref('');
const selectedLibraries = ref([]);
const libraryList = ref([]);
const libraryLoading = ref(false);
const libraryPageNum = ref(1);
const libraryPageSize = ref(10);
const hasMoreLibrary = ref(true);
// 打开检查库弹窗时获取数据
const openLibraryPopup = () => {
showLibraryPopup.value = true;
libraryKeyword.value = '';
libraryPageNum.value = 1;
libraryList.value = [];
hasMoreLibrary.value = true;
selectedLibraries.value = [];
fetchLibraryList();
};
// 关闭检查库弹窗
const closeLibraryPopup = () => {
showLibraryPopup.value = false;
selectedLibraries.value = [];
};
// 获取检查库列表
const fetchLibraryList = async (isLoadMore = false) => {
if (libraryLoading.value) return;
libraryLoading.value = true;
try {
const params = {
pageNum: libraryPageNum.value,
pageSize: libraryPageSize.value
};
// name 有值时才传
if (libraryKeyword.value && libraryKeyword.value.trim()) {
params.name = libraryKeyword.value.trim();
}
const res = await getCheckItemList(params);
if (res.code === 0) {
const records = res.data.records || [];
if (isLoadMore) {
libraryList.value = [...libraryList.value, ...records];
} else {
libraryList.value = records;
}
// 判断是否还有更多
const total = res.data.total || 0;
hasMoreLibrary.value = libraryList.value.length < total;
}
} catch (error) {
console.error('获取检查库列表失败:', error);
} finally {
libraryLoading.value = false;
}
};
// 搜索检查库
const searchLibrary = () => {
libraryPageNum.value = 1;
libraryList.value = [];
hasMoreLibrary.value = true;
fetchLibraryList();
};
// 加载更多检查库
const loadMoreLibrary = () => {
if (!hasMoreLibrary.value || libraryLoading.value) return;
libraryPageNum.value++;
fetchLibraryList(true);
};
const toggleLibrarySelect = (item) => {
const index = selectedLibraries.value.indexOf(item.id);
if (index > -1) {
selectedLibraries.value.splice(index, 1);
} else {
selectedLibraries.value.push(item.id);
}
};
// 添加选中的检查库
const addSelectedLibrary = async () => {
if (selectedLibraries.value.length === 0) {
uni.showToast({ title: '请选择检查库', icon: 'none' });
return;
}
uni.showLoading({ title: '加载中...' });
try {
// 遍历选中的检查库,获取详情
for (const id of selectedLibraries.value) {
const res = await getCheckItemListDetail({ itemId: id });
if (res.code === 0 && res.data) {
const records = res.data.records || [];
const total = res.data.total || 0;
// 获取关联表名第一项的name
const tableName = records.length > 0 ? records[0].name : '';
// 添加到检查项列表
checkItems.value.push({
itemId: id,
tableName: tableName,
count: total,
details: records // 保存详情数据,以便后续使用
});
}
}
uni.hideLoading();
uni.showToast({ title: '添加成功', icon: 'success' });
showLibraryPopup.value = false;
selectedLibraries.value = [];
} catch (error) {
uni.hideLoading();
console.error('获取检查库详情失败:', error);
uni.showToast({ title: '添加失败', icon: 'none' });
}
};
// 保存
const handleSave = async () => {
// 表单验证
if (!formData.name) {
uni.showToast({ title: '请输入检查表名称', icon: 'none' });
return;
}
if (!formData.deptId) {
uni.showToast({ title: '请选择分派单位', icon: 'none' });
return;
}
if (!formData.type) {
uni.showToast({ title: '请选择检查表类型', icon: 'none' });
return;
}
if (!formData.modeName) {
uni.showToast({ title: '请选择运行模式', icon: 'none' });
return;
}
// 如果选择指定人员,需要选择执行人员
if (formData.modeName === '指定人员' && formData.executorIds.length === 0) {
uni.showToast({ title: '请选择执行人员', icon: 'none' });
return;
}
if (!formData.cycleName) {
uni.showToast({ title: '请选择周期', icon: 'none' });
return;
}
if (!formData.startDate || !formData.endDate) {
uni.showToast({ title: '请选择计划时间', icon: 'none' });
return;
}
// 构建 items 数组关联检查项id列表
const items = [];
// 添加手动添加的检查项id
manualCheckItems.value.forEach(item => {
if (item.id) {
items.push(item.id );
}
});
// 添加从检查库选择的检查项详情中的所有项的 pointId
checkItems.value.forEach(lib => {
if (lib.details && lib.details.length > 0) {
lib.details.forEach(detail => {
if (detail.pointId) {
items.push(detail.pointId );
}
});
}
});
if (items.length === 0) {
uni.showToast({ title: '请添加检查项', icon: 'none' });
return;
}
// 运行模式映射:指定人员=1全员=2
const runModeMap = {
'指定人员': 1,
'全员': 2
};
// 周期映射:每天=1每周=2每月=3每季度=4
const cycleMap = {
'每天一次': 1,
'每周一次': 2,
'每月一次': 3,
'每季度一次': 4
};
// 构建 itemIds 数组从检查库选择的检查库id列表
const itemIds = [];
checkItems.value.forEach(lib => {
if (lib.itemId) {
itemIds.push(lib.itemId);
}
});
// 构建提交参数
const params = {
name: formData.name,
deptId: formData.deptId,
description: formData.remark || '',
type: formData.type, // 检查表类型1-日常检查2-专项检查3-设备检查
runMode: runModeMap[formData.modeName] || 2,
checkPointIds: items,
itemIds: itemIds, // 从检查库选择的库id数组
cycle: cycleMap[formData.cycleName] || 1,
isWeekend: workdaySwitch.value ? 1 : 2,
planStartTime: formData.startDate,
planEndTime: formData.endDate
};
// 如果是指定人员模式添加执行人员id
if (formData.modeName === '指定人员' && formData.executorIds.length > 0) {
params.executorId = formData.executorIds[0]; // 如果只能选一个执行人员
// 如果支持多个执行人员可以改为params.executorIds = formData.executorIds;
}
try {
uni.showLoading({ title: '保存中...' });
const res = await addCheckTable(params);
uni.hideLoading();
if (res.code === 0) {
uni.showToast({ title: '保存成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: res.msg || '保存失败', icon: 'none' });
}
} catch (error) {
uni.hideLoading();
console.error('保存失败:', error);
uni.showToast({ title: '保存失败', icon: 'none' });
}
};
// 页面加载时获取数据
onMounted(() => {
fetchDeptUsers();
fetchParentDepts();
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
padding: 24rpx;
padding-bottom: 140rpx;
}
// 表单卡片
.form-card {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 80rpx;
}
// 表单项
.form-item {
margin-bottom: 32rpx;
&:last-child {
margin-bottom: 0;
}
}
// 表单标题
.form-label {
font-size: 28rpx;
color: #999;
margin-bottom: 16rpx;
display: flex;
align-items: center;
.required {
color: #F56C6C;
margin-left: 4rpx;
}
}
// 蓝色标题
.label-blue {
color: #2667E9;
}
// 选择器输入框
.picker-input {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
background: #fff;
border: 2rpx solid #E5E5E5;
border-radius: 8rpx;
padding: 0 24rpx;
.picker-value {
color: #333;
font-size: 28rpx;
}
.picker-placeholder {
color: #C0C4CC;
font-size: 28rpx;
}
.picker-arrow {
color: #C0C4CC;
font-size: 24rpx;
}
}
// 开关行
.switch-row {
display: flex;
align-items: center;
gap: 30rpx;
}
// 空状态提示
.empty-check-tip {
text-align: center;
padding: 60rpx 0;
font-size: 28rpx;
}
// 检查项卡片
.check-card {
background: #F8FAFF;
border-left: 6rpx solid #2667E9;
border-radius: 8rpx;
padding: 24rpx;
padding-bottom: 80rpx;
margin-bottom: 20rpx;
position: relative;
.check-info {
.info-row {
display: flex;
margin-bottom: 16rpx;
font-size: 26rpx;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #666;
flex-shrink: 0;
}
.info-label-bold {
font-weight: bold;
}
.info-value {
color: #333;
flex: 1;
}
}
}
.check-action {
position: absolute;
right: 20rpx;
bottom: 20rpx;
.btn-delete {
width: 120rpx;
height: 56rpx;
line-height: 56rpx;
background: #F56C6C;
color: #fff;
font-size: 26rpx;
border-radius: 8rpx;
padding: 0;
&::after {
border: none;
}
}
}
}
// 手动添加的检查项卡片带第x项标签
.manual-card {
padding-top: 50rpx;
.card-tag {
position: absolute;
left: 0;
top: 0;
background: #2667E9;
color: #fff;
font-size: 24rpx;
padding: 6rpx 20rpx;
border-radius: 0 0 12rpx 0;
}
}
// 添加按钮组
.add-btns {
display: flex;
justify-content: space-between;
gap: 24rpx;
.btn-add {
flex: 1;
height: 72rpx;
line-height: 72rpx;
background: #fff;
border: 2rpx solid #2667E9;
border-radius: 8rpx;
color: #2667E9;
font-size: 28rpx;
padding: 0;
&::after {
border: none;
}
}
}
// 底部保存按钮
.footer-btn {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding: 20rpx 40rpx;
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
background: #EBF2FC;
.btn-save {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: #2667E9;
color: #fff;
font-size: 32rpx;
border-radius: 44rpx;
&::after {
border: none;
}
}
}
// 弹出框样式
.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;
font-weight: bold;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
.popup-body {
padding: 30rpx;
max-height: 700rpx;
overflow-y: auto;
}
.popup-form-item {
margin-bottom: 24rpx;
}
.popup-form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
display: flex;
align-items: center;
.required {
color: #F56C6C;
margin-left: 4rpx;
}
}
.popup-select {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 8rpx;
padding: 0 24rpx;
font-size: 28rpx;
}
.regulation-select {
align-items: flex-start;
padding: 20rpx 24rpx;
.regulation-text {
flex: 1;
line-height: 1.5;
word-break: break-all;
}
.select-icon {
flex-shrink: 0;
margin-left: 16rpx;
margin-top: 4rpx;
}
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
button {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
font-size: 30rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #fff;
color: #666;
}
.btn-confirm {
background: #2667E9;
color: #fff;
}
}
// 选择法规弹窗
.law-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
max-height: 80vh;
}
.search-box {
display: flex;
align-items: center;
background: #F5F5F5;
border-radius: 40rpx;
padding: 16rpx 24rpx;
margin: 20rpx 30rpx;
.search-icon {
font-size: 28rpx;
color: #999;
margin-right: 12rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
background: transparent;
}
.search-btn {
color: #2667E9;
font-size: 26rpx;
margin-left: 16rpx;
}
}
.loading-tip, .empty-tip {
text-align: center;
padding: 40rpx;
color: #999;
font-size: 26rpx;
}
.law-list {
max-height: 400rpx;
padding: 0 30rpx;
}
.law-item {
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
font-size: 28rpx;
color: #333;
.law-title {
line-height: 1.5;
margin-bottom: 8rpx;
}
.law-basis {
font-size: 24rpx;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
.law-item-active {
border-color: #2667E9;
background: #F0F6FF;
}
.load-more {
text-align: center;
padding: 20rpx;
margin: 0 30rpx;
border: 2rpx solid #2667E9;
border-radius: 40rpx;
}
// 检查库弹窗样式
.library-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
max-height: 80vh;
}
.library-list {
max-height: 400rpx;
padding: 0 30rpx;
}
.library-item {
display: flex;
align-items: flex-start;
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
}
.library-checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #ccc;
border-radius: 8rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 4rpx;
font-size: 24rpx;
}
.library-checkbox-active {
background: #2667E9;
border-color: #2667E9;
color: #fff;
}
.library-info {
flex: 1;
}
.library-name {
font-size: 28rpx;
color: #333;
line-height: 1.5;
}
.library-count {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.btn-add-library {
width: calc(100% - 60rpx);
height: 80rpx;
line-height: 80rpx;
background: #2667E9;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
margin: 20rpx 30rpx;
&::after {
border: none;
}
}
// 执行人员弹窗样式
.executor-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
max-height: 80vh;
}
.executor-list {
max-height: 500rpx;
padding: 0 30rpx;
}
.executor-item {
display: flex;
align-items: center;
padding: 24rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.executor-checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #ccc;
border-radius: 8rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.executor-checkbox-active {
background: #2667E9;
border-color: #2667E9;
color: #fff;
}
.executor-info {
flex: 1;
}
.executor-name {
font-size: 28rpx;
color: #333;
}
</style>