|
|
@@ -0,0 +1,254 @@
|
|
|
+<template>
|
|
|
+ <hc-new-dialog v-model="linkModal" is-table title="关联构建编码" widths="72rem" :loading="confirmLoad" @close="closeModal" @save="confirmLink">
|
|
|
+ <div class="link-dialog-box h-full p-2">
|
|
|
+ <hc-page-split>
|
|
|
+ <template #left>
|
|
|
+ <hc-card>
|
|
|
+ <el-radio-group v-model="leftRadio" class="flex flex-col" style="align-items: start;">
|
|
|
+ <div v-for="value in sourceData" :key="value.id">
|
|
|
+ <el-radio :value="value.id">
|
|
|
+ {{ value.name }}
|
|
|
+ </el-radio>
|
|
|
+ </div>
|
|
|
+ </el-radio-group>
|
|
|
+ </hc-card>
|
|
|
+ </template>
|
|
|
+ <hc-card>
|
|
|
+ <hc-search-input
|
|
|
+ v-model="queryValue"
|
|
|
+ placeholder="请输入节点关键词"
|
|
|
+ @search="searchTreeClick"
|
|
|
+ />
|
|
|
+
|
|
|
+
|
|
|
+ <el-scrollbar class="mt-4 h-[calc(100%-60px)]">
|
|
|
+ <template v-if="leftRadio">
|
|
|
+ <el-tree
|
|
|
+ ref="treeRef"
|
|
|
+ :data="treeData"
|
|
|
+ :props="treeProps"
|
|
|
+ :default-expand-all="false"
|
|
|
+
|
|
|
+ :filter-node-method="filterNode"
|
|
|
+ :load="loadNode"
|
|
|
+ lazy
|
|
|
+ node-key="id"
|
|
|
+ check-strictly
|
|
|
+ @node-click="handleNodeClick"
|
|
|
+ >
|
|
|
+ <!-- 自定义节点内容,使用单选框 -->
|
|
|
+ <template #default="{ node, data }">
|
|
|
+ <span class="custom-tree-node">
|
|
|
+ <!-- 使用单选框替代复选框 -->
|
|
|
+ <el-radio
|
|
|
+ v-model="selectedNodeId"
|
|
|
+ :value="data.id"
|
|
|
+ :disabled="data.nodeType === 6"
|
|
|
+ class="mr-2"
|
|
|
+ />
|
|
|
+ <span>{{ node.label }}</span>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-tree>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div class="py-10 text-center text-gray-500">请先选择左侧工区</div>
|
|
|
+ </template>
|
|
|
+ </el-scrollbar>
|
|
|
+ </hc-card>
|
|
|
+ </hc-page-split>
|
|
|
+ </div>
|
|
|
+ </hc-new-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { ref, watch } from 'vue'
|
|
|
+import wbsApi from '~api/data-fill/wbs'
|
|
|
+import { getArrValue, getObjValue } from 'js-fast-way'
|
|
|
+// 接收父组件传入的属性
|
|
|
+const props = defineProps({
|
|
|
+ pKeyId:{
|
|
|
+ type: String,
|
|
|
+ default: '',
|
|
|
+ },
|
|
|
+})
|
|
|
+const emit = defineEmits(['close', 'save'])
|
|
|
+const pKeyId = ref(props.pKeyId)
|
|
|
+watch(() => props.pKeyId, (val) => {
|
|
|
+ pKeyId.value = val
|
|
|
+})
|
|
|
+// 对话框显示状态
|
|
|
+const linkModal = defineModel('modelValue', {
|
|
|
+ default: false,
|
|
|
+})
|
|
|
+
|
|
|
+// 左侧单选框值
|
|
|
+const leftRadio = ref('')
|
|
|
+const sourceData = ref([
|
|
|
+ { id: '54e8a314de8a493d9f08a9d3cf7c', name: '一工区' },
|
|
|
+ { id: 'f4fb6834d501474194410c15e9f5', name: '二工区' },
|
|
|
+ { id: '7a5e3bb9c36d43c8a08bfb44b13e', name: '四工区' },
|
|
|
+ { id: '9e61c9bc6dd742d9922aa61b8bd1', name: '五工区' },
|
|
|
+ { id: '119739d00e974214acd85b3ad661', name: '六工区' },
|
|
|
+ { id: 'cc10f104ddb64320ab59ac7abec9', name: '二期工程' },
|
|
|
+])
|
|
|
+// 监听左侧工区变化,重新加载根节点数据
|
|
|
+watch(leftRadio, (newVal) => {
|
|
|
+ loadRootNodes(newVal)
|
|
|
+ selectedNodeId.value = ''
|
|
|
+ selectedNodeData.value = null
|
|
|
+})
|
|
|
+// 搜索关键词
|
|
|
+const queryValue = ref('')
|
|
|
+
|
|
|
+// 树形组件引用
|
|
|
+const treeRef = ref(null)
|
|
|
+
|
|
|
+// 选中的节点ID
|
|
|
+const selectedNodeId = ref(null)
|
|
|
+
|
|
|
+// 树形结构配置
|
|
|
+const treeProps = {
|
|
|
+ label: 'name',
|
|
|
+ children: 'children',
|
|
|
+ isLeaf: 'isLeaf', // 新增isLeaf字段判断是否为叶子节点
|
|
|
+}
|
|
|
+
|
|
|
+// 树形数据 - 初始只存放根节点
|
|
|
+const treeData = ref([])
|
|
|
+
|
|
|
+// 监听对话框显示状态
|
|
|
+watch(() => linkModal.value, (val) => {
|
|
|
+ if (val) {
|
|
|
+ // 对话框打开时的初始化操作
|
|
|
+ selectedNodeId.value = ''
|
|
|
+ queryValue.value = ''
|
|
|
+
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+// 加载根节点数据
|
|
|
+const loadRootNodes = async (workArea) => {
|
|
|
+ // 清空现有树形数据
|
|
|
+ treeData.value = []
|
|
|
+ // 重置选中节点ID
|
|
|
+ selectedNodeId.value = ''
|
|
|
+
|
|
|
+ if (!workArea) return // 如果没有选中工区则不加载
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 加载根节点(parentId设为0表示根节点)
|
|
|
+ const { data } = await wbsApi.getChildNodes({
|
|
|
+ contractId: workArea,
|
|
|
+ pKeyId: pKeyId.value || '',
|
|
|
+ parentId: 0, // 明确请求根节点数据
|
|
|
+ })
|
|
|
+
|
|
|
+ // 设置根节点数据
|
|
|
+ treeData.value = getArrValue(data)
|
|
|
+ // 重置树形组件状态
|
|
|
+ if (treeRef.value) {
|
|
|
+ console.log(treeRef.value, 'treeRef.value.')
|
|
|
+
|
|
|
+ treeRef.value.setCheckedKeys([])
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载根节点失败:', error)
|
|
|
+ }
|
|
|
+}
|
|
|
+// 懒加载节点方法
|
|
|
+
|
|
|
+const loadNode = async (node, resolve) => {
|
|
|
+ const { level, data: item } = node
|
|
|
+
|
|
|
+
|
|
|
+ // 根节点(level:0)已通过loadRootNodes加载,直接返回空数组阻止重复请求
|
|
|
+ if (level === 0) {
|
|
|
+ return resolve([])
|
|
|
+ }
|
|
|
+ let parentId = 0
|
|
|
+ if (level !== 0) {
|
|
|
+ const nodeData = getObjValue(item)
|
|
|
+ parentId = nodeData?.id
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取数据
|
|
|
+ const { data } = await wbsApi.getChildNodes({
|
|
|
+ contractId: leftRadio.value || '',
|
|
|
+
|
|
|
+ pKeyId: pKeyId.value || '',
|
|
|
+ parentId,
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ resolve(getArrValue(data))
|
|
|
+}
|
|
|
+// 修改加载根节点数据方法
|
|
|
+
|
|
|
+// 关闭对话框
|
|
|
+const closeModal = () => {
|
|
|
+ linkModal.value = false
|
|
|
+ selectedNodeData.value = null
|
|
|
+ selectedNodeId.value = null
|
|
|
+ leftRadio.value = null
|
|
|
+ emit('close')
|
|
|
+}
|
|
|
+
|
|
|
+// 搜索树形节点
|
|
|
+const searchTreeClick = () => {
|
|
|
+ treeRef.value.filter(queryValue.value)
|
|
|
+}
|
|
|
+
|
|
|
+// 节点过滤方法
|
|
|
+const filterNode = (value, data) => {
|
|
|
+ if (!value) return true
|
|
|
+ return data.name.toLowerCase().includes(value.toLowerCase())
|
|
|
+}
|
|
|
+
|
|
|
+// 处理节点点击事件
|
|
|
+const selectedNodeData = ref(null)
|
|
|
+const handleNodeClick = (data) => {
|
|
|
+ // 如果是叶子节点才允许选中
|
|
|
+ selectedNodeId.value = data.id
|
|
|
+ selectedNodeData.value = data
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// 确认关联
|
|
|
+const confirmLoad = ref(false)
|
|
|
+const confirmLink = async () => {
|
|
|
+ if (!selectedNodeId.value) {
|
|
|
+ // 提示用户未选择节点
|
|
|
+ window?.$message?.warning('请选择节点')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ confirmLoad.value = true
|
|
|
+ const { error, code, data, msg } = await wbsApi.batchBind([
|
|
|
+ selectedNodeData.value,
|
|
|
+ ])
|
|
|
+ confirmLoad.value = false
|
|
|
+
|
|
|
+ if (!error && code === 200) {
|
|
|
+ window.$message?.success(msg ?? '操作成功')
|
|
|
+ closeModal()
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+// 调整单选框与文字的对齐方式
|
|
|
+:deep(.el-radio) {
|
|
|
+ vertical-align: middle;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-tree-node {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+</style>
|