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

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

@@ -16,21 +16,12 @@
<text>分派单位</text>
<text class="required">*</text>
</view>
<view class="picker-input" @click="showDeptPicker = true">
<view class="picker-input" @click="openDeptPopup">
<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>
<!-- 补充说明 -->
@@ -377,6 +368,42 @@
</view>
</u-popup>
<!-- 分派单位选择弹窗 -->
<u-popup :show="showDeptPicker" mode="center" round="20" :safeAreaInsetBottom="false" @close="cancelDeptSelect">
<view class="dept-popup">
<view class="popup-header">
<view class="popup-title">选择分派单位</view>
<view class="popup-close" @click="cancelDeptSelect">×</view>
</view>
<view v-if="showDeptPicker" class="dept-tree-body">
<xq-tree
v-if="deptTree.length"
ref="deptTreeRef"
:data="deptTree"
node-key="deptId"
label-key="deptName"
children-key="children"
show-checkbox
check-strictly
default-expand-all
:height="500"
:width="560"
:default-checked-keys="deptDefaultCheckedKeys"
empty-text="暂无部门数据"
@check="onDeptCheck"
@node-click="onDeptNodeClick"
/>
<view v-else class="empty-tip">暂无部门数据</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="cancelDeptSelect">取消</button>
<button class="btn-confirm" @click="confirmDeptSelect">确定</button>
</view>
</view>
</u-popup>
<!-- 执行人员选择弹窗 -->
<u-popup :show="showExecutorPopup" mode="center" round="20" @close="showExecutorPopup = false">
<view class="executor-popup">
@@ -413,9 +440,8 @@
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { ref, reactive, computed, onMounted, nextTick } from 'vue';
import { getRegulationList, addCheckPoint, detailcheckPoint, deleteCheckPoint, getCheckItemList, getCheckItemListDetail, getDeptUsers, getDeptChildren, addCheckTable } from '@/request/api.js';
import { onMounted } from 'vue';
// 表单数据
const formData = reactive({
@@ -560,13 +586,11 @@ const endDateValue = ref(getTodayTimestamp());
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([['每天一次', '每周一次', '每月一次', '每季度一次']]);
@@ -576,23 +600,84 @@ const showExecutorPopup = ref(false);
const executorList = ref([]);
const selectedExecutorId = ref(null);
// 分派单位级联选择器
// 分派单位树形选择器
const deptTree = ref([]);
const deptCascaderColumns = ref([]);
const deptCascaderIndexs = ref([0]);
const selectedDeptPath = ref([]); // 选中的路径
const deptTreeRef = ref(null);
const selectedDeptId = ref(null);
const deptDefaultCheckedKeys = ref([]);
// 选择器确认回调
const onDeptConfirm = () => {
const lastSelected = selectedDeptPath.value[selectedDeptPath.value.length - 1]
if (lastSelected) {
formData.deptId = lastSelected.deptId
formData.deptName = selectedDeptPath.value.map(d => d.deptName).join(' / ')
clearExecutorSelection()
fetchDeptUsers(lastSelected.deptId)
const getDeptNodeId = (node) => node?.deptId ?? node?.raw?.deptId ?? null;
const syncDeptTreeChecked = (deptId) => {
nextTick(() => {
if (deptId) {
deptTreeRef.value?.setCheckedKeys?.([deptId]);
} else {
deptTreeRef.value?.clearChecked?.();
}
});
};
const findDeptPath = (tree, targetId, path = []) => {
for (const node of tree) {
const currentPath = [...path, node];
if (String(node.deptId) === String(targetId)) {
return currentPath;
}
if (node.children?.length) {
const found = findDeptPath(node.children, targetId, currentPath);
if (found) return found;
}
}
showDeptPicker.value = false
}
return null;
};
const openDeptPopup = () => {
selectedDeptId.value = formData.deptId || null;
deptDefaultCheckedKeys.value = formData.deptId ? [formData.deptId] : [];
showDeptPicker.value = true;
syncDeptTreeChecked(formData.deptId);
};
const onDeptNodeClick = (node) => {
const deptId = getDeptNodeId(node);
selectedDeptId.value = deptId;
syncDeptTreeChecked(deptId);
};
const onDeptCheck = (node, { checkedKeys = [] } = {}) => {
const deptId = getDeptNodeId(node);
const isChecked = checkedKeys.some((key) => String(key) === String(deptId));
if (isChecked) {
selectedDeptId.value = deptId;
syncDeptTreeChecked(deptId);
return;
}
selectedDeptId.value = null;
syncDeptTreeChecked(null);
};
const cancelDeptSelect = () => {
showDeptPicker.value = false;
};
const confirmDeptSelect = () => {
if (!selectedDeptId.value) {
uni.showToast({ title: '请选择分派单位', icon: 'none' });
return;
}
const path = findDeptPath(deptTree.value, selectedDeptId.value);
if (!path?.length) {
uni.showToast({ title: '请选择分派单位', icon: 'none' });
return;
}
const selected = path[path.length - 1];
formData.deptId = selected.deptId;
formData.deptName = path.map((d) => d.deptName).join(' / ');
clearExecutorSelection();
fetchDeptUsers(selected.deptId);
showDeptPicker.value = false;
};
// 检查表类型映射:日常检查->1, 专项检查->2, 设备检查->3
const typeMap = {
@@ -674,72 +759,12 @@ const fetchDeptChildren = async () => {
if (res.code === 0 && res.data) {
const list = Array.isArray(res.data) ? res.data : []
deptTree.value = handleTree(list, 'deptId')
initDeptCascader(deptTree.value)
}
} catch (error) {
console.error('获取部门树失败:', error)
}
}
// 初始化部门级联选择器
const initDeptCascader = (treeData) => {
const roots = Array.isArray(treeData) ? treeData : (treeData ? [treeData] : [])
if (roots.length === 0) return
const firstColumn = roots.map(item => ({ text: item.deptName, ...item }))
deptCascaderColumns.value = [firstColumn]
deptCascaderIndexs.value = [0]
selectedDeptPath.value = [roots[0]]
let current = roots[0]
while (current.children && current.children.length > 0) {
const nextColumn = current.children.map(item => ({ text: item.deptName, ...item }))
deptCascaderColumns.value.push(nextColumn)
deptCascaderIndexs.value.push(0)
selectedDeptPath.value.push(current.children[0])
current = current.children[0]
}
}
// 部门级联选择器列改变
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];
@@ -1857,6 +1882,31 @@ onMounted(() => {
}
}
// 分派单位弹窗样式
.dept-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
.popup-footer {
button {
margin: 0;
}
}
}
.dept-tree-body {
height: 500rpx;
overflow: hidden;
:deep(.checkbox-custom.checked),
:deep(.checkbox-custom.indeterminate) {
background-color: #2667E9;
border-color: #2667E9;
}
}
// 执行人员弹窗样式
.executor-popup {
width: 600rpx;