Explorar o código

参数库修改

duy hai 5 meses
pai
achega
076f6cbe5e

+ 87 - 0
src/api/modules/paramter/parmter.js

@@ -0,0 +1,87 @@
+import { HcApi } from '../../request'
+
+export default {
+    /**
+     * 分页查询参数库
+     * @param {Object} params - 查询参数
+     */
+    async queryParameterList(params) {
+        return HcApi({
+            url: '/api/blade-manager/parameter/list',
+            method: 'get',
+            params,
+        })
+    },
+
+    /**
+     * 新增或修改参数库
+     * @param {Object} data - 参数数据
+     */
+    async submitParameter(data) {
+        return HcApi({
+            url: '/api/blade-manager/parameter/submit',
+            method: 'post',
+            data,
+        })
+    },
+
+    /**
+     * 删除参数库
+     * @param {Object} params - 删除参数
+     */
+    async remove(params) {
+        return HcApi({
+            url: '/api/blade-manager/parameter/remove',
+            method: 'get',
+            params,
+        })
+    },
+
+    /**
+     * 根据参树Id获取项目和合同段信息
+     * @param {Object} params - 查询参数
+     */
+    async getProjectContractByParam(params) {
+        return HcApi({
+            url: '/api/blade-manager/parameterelement/getProjectContract',
+            method: 'get',
+            params,
+        })
+    },
+
+    /**
+     * 新增元素
+     * @param {Object} data - 元素数据
+     */
+    async submitElement(data) {
+        return HcApi({
+            url: '/api/blade-manager/parameterelement/submit',
+            method: 'post',
+            data,
+        })
+    },
+
+    /**
+     * 加载元素列表
+     * @param {Object} params - 查询参数
+     */
+    async getParameterElementList(params) {
+        return HcApi({
+            url: '/api/blade-manager/parameterelement/getParameterElementList',
+            method: 'post',
+            data: params,
+        })
+    },
+
+    /**
+     * 删除元素
+     * @param {Object} params - 删除参数
+     */
+    async removeElement(params) {
+        return HcApi({
+            url: '/api/blade-manager/parameterelement/remove',
+            method: 'get',
+            params,
+        })
+    },
+}

+ 10 - 0
src/views/desk/wbs.vue

@@ -9,6 +9,7 @@
             <el-button hc-btn type="primary" @click="addRowClick">新增</el-button>
             <el-button hc-btn type="danger" :disabled="tableCheckKeys.length <= 0" @click="batchDelClick">删除</el-button>
             <el-button hc-btn type="warning" @click="elementLibrary">元素库</el-button>
+            <el-button hc-btn type="warning" style="background-color: #2550A2; color: #fff;" @click="paramLibrary">参数库</el-button>
         </template>
         <hc-table
             :column="tableColumn" :datas="tableData" :loading="tableLoading" :index-style="{ width: 60 }"
@@ -57,6 +58,8 @@
         <HcElementLib v-model="isElementLibShow" />
         <!-- 编辑wbs库 -->
         <HcDrawerwbs v-model="isDrawerWbsShow" :data="tableInfo" @close="getTableData" />
+        <!-- 参数库 -->
+        <HcParamLib v-model="isParamLibShow" />
     </hc-card>
 </template>
 
@@ -68,6 +71,7 @@ import { getDictionaryData, reloadPage } from '~uti/tools'
 import HcElementLib from './wbs/element-lib.vue'
 import mainApi from '~api/desk/wbs'
 import HcDrawerwbs from './wbs/drawer-wbs.vue'
+import HcParamLib from './wbs/paramter/paramLid.vue'
 
 //激活
 onActivated(() => {
@@ -224,4 +228,10 @@ onDeactivated(() => {
     isElementLibShow.value = false
     isDrawerWbsShow.value = false
 })
+
+//参数库
+const isParamLibShow = ref(false)
+const paramLibrary = () => {
+    isParamLibShow.value = true
+}
 </script>

+ 194 - 0
src/views/desk/wbs/paramter/addParamDialog.vue

@@ -0,0 +1,194 @@
+<template>
+    <hc-dialog
+        v-model="dialogVisible"
+        :title="modalTitle"
+        widths="30%"
+        :loading="submitLoading"
+        @close="closeDialog"
+        @save="submitForm"
+    >
+        <el-form 
+            ref="formRef"
+            :model="parameter"
+            :rules="rules"
+            label-width="120px"
+            label-position="left"
+        >
+            <el-form-item label="参数名称" prop="paramName">
+                <el-input v-model="parameter.paramName" />
+            </el-form-item>
+            <el-form-item label="参数类型" prop="paramTypeVal">
+                <el-select
+                    v-model="parameter.paramTypeVal"
+                    multiple
+                    placeholder="请选择"
+                >
+                    <el-option 
+                        v-for="item in paramTypeList" 
+                        :key="item.value" 
+                        :label="item.label" 
+                        :value="item.value"
+                    />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="是否区分项目" prop="type">
+                <el-radio-group v-model="parameter.type">
+                    <el-radio :value="1">是</el-radio>
+                    <el-radio :value="2">否</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item label="备注">
+                <el-input 
+                    v-model="parameter.remarks" 
+                    type="textarea" 
+                />
+            </el-form-item>
+        </el-form>
+    </hc-dialog>
+</template>
+
+<script setup>
+import { onMounted, reactive, ref, watch } from 'vue'
+
+import { getDictionaryData } from '~uti/tools'
+import paramApi from '~api/paramter/parmter'
+import { formValidate } from 'js-fast-way'
+
+// 定义props
+const props = defineProps({
+    modelValue: {
+        type: Boolean,
+        default: false,
+    },
+    params: {
+        type: Object,
+        default: () => ({}),
+    },
+})
+
+// 定义emit
+const emit = defineEmits(['update:modelValue', 'add-parameter'])
+
+// 定义组件名称
+defineOptions({
+    name: 'AddParamDialog',
+})
+
+// 双向绑定弹窗显示状态
+const dialogVisible = ref(false)
+
+// 数据定义
+const formRef = ref(null)
+const modalTitle = ref('新增参数')
+const paramTypeList = ref([])
+
+const parameter = reactive({
+    paramName: '',
+    paramTypeVal: [],
+    type: false,
+    remarks: '',
+})
+
+// 表单校验规则
+const rules = {
+    paramName: [
+        { required: true, message: '请输入参数名称', trigger: 'blur' },
+    ],
+    paramTypeVal: [
+        { required: true, message: '请选择参数类型', trigger: 'change' },
+    ],
+    type: [
+        { required: true, message: '请选择是否区分项目', trigger: 'change' },
+    ],
+}
+
+// 监听参数变化
+watch(() => props.params, (newVal) => {
+    modalTitle.value = newVal.id ? '编辑参数' : '新增参数'
+}, { deep: true })
+
+// 获取参数类型列表
+const getParamTypeList = async () => {
+  paramTypeList.value = await getDictionaryData('parameter_type')
+}
+
+// 显示弹窗
+const show = async (data) => {
+    // 先重置数据
+    await closeDialog()
+    
+    // 然后再打开弹窗和设置新数据
+    dialogVisible.value = true
+    modalTitle.value = data?.id ? '编辑参数' : '新增参数'
+    
+    // 确保参数类型列表已加载
+    if (paramTypeList.value.length === 0) {
+        await getParamTypeList()
+    }
+    
+    if (data) {
+        // 重置表单数据
+        const paramTypes = data.paramType?.split(',') || []
+        Object.assign(parameter, {
+            id: data.id,
+            paramName: data.paramName,
+            paramTypeVal: paramTypes.map(type => {
+                const dictItem = paramTypeList.value.find(item => item.value === type)
+                return Number(dictItem?.value || type)
+            }),
+            type: data.type,
+            remarks: data.remarks,
+        })
+    }
+}
+
+// 关闭弹窗
+const closeDialog = () => {
+    dialogVisible.value = false
+    formRef.value?.resetFields()
+    // 重置所有数据到初始状态
+    Object.assign(parameter, {
+        id: undefined,
+        paramName: '',
+        paramTypeVal: [],
+        type: false,
+        remarks: '',
+    })
+}
+
+// 提交表单
+const submitLoading = ref(false)
+const submitForm = async () => {
+    if (!formRef.value) return
+    const valid = await formValidate(formRef.value)
+    if (!valid) return
+
+    submitLoading.value = true
+    try {
+        const { error, code } = await paramApi.submitParameter({
+            ...parameter,
+            paramType: parameter.paramTypeVal.join(','),
+            id: parameter.id, // 确保 ID 传递
+        })
+        
+        if (!error && code === 200) {
+            window?.$message?.success('操作成功')
+            emit('add-parameter')
+            closeDialog()
+        }
+    } finally {
+        submitLoading.value = false
+    }
+}
+
+// 组件挂载时获取参数类型列表
+onMounted(() => {
+    getParamTypeList()
+})
+
+// 暴露方法给父组件
+defineExpose({
+    show,
+    hide: closeDialog, // 暴露 hide 方法
+})
+</script>

+ 148 - 0
src/views/desk/wbs/paramter/checkDetailEle.vue

@@ -0,0 +1,148 @@
+<template>
+    <hc-dialog
+        v-model="dialogVisible"
+        title="选择元素表"
+        widths="800px"
+        @close="dialogVisible = false"
+        @save="confirmSelection"
+    >
+        <div class="boxnei">
+            <div class="mg-b-10 flex">
+                <el-input
+                    v-model="formulaInput"
+                    placeholder="请输入名称"
+                    size="small" 
+                    clearable 
+                />
+                <el-button type="primary" class="hc-btn mg-l-10" @click="searchFormulaName">搜索</el-button>
+            </div>
+
+            <hc-table
+                :column="tableColumn"
+                :datas="editEleListFilter"
+                :loading="loading"
+                :index-style="{ width: 60 }"
+                height="400"
+            >
+                <template #action="{ row }">
+                    <el-link 
+                        v-if="!row.select" 
+                        type="primary"
+                        @click="selectElement(row)"
+                    >
+                        选择
+                    </el-link>
+                    <el-link
+                        v-else
+                        type="danger"
+                        @click="canlSelect(row)"
+                    >
+                        取消选择
+                    </el-link>
+                </template>
+            </hc-table>
+        </div>
+    </hc-dialog>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import treeApi from '~api/wbs/tree'
+import { getArrValue } from 'js-fast-way'
+// 定义emit
+const emit = defineEmits(['confirm-selection'])
+
+// 定义组件名称
+defineOptions({
+    name: 'CheckDetailEle',
+})
+
+// 响应式状态
+const dialogVisible = ref(false)
+const loading = ref(false)
+const formulaInput = ref('')
+const editEleListFilter = ref([])
+const editEleListAll = ref([])
+const selectedDataValue = ref([])
+
+// 表格列配置
+const tableColumn = ref([
+    { key: 'eName', name: '字段信息', align: 'center' },
+    { key: 'action', name: '操作', width: 200, align: 'center' },
+])
+
+// 方法定义
+const show = async (id, selectedData) => {
+    dialogVisible.value = true
+    selectedDataValue.value = selectedData || []
+    
+    const { error, code, data } = await treeApi.getTableElments({ id })
+    if (!error && code === 200) {
+        editEleListFilter.value = getArrValue(data)
+        editEleListAll.value = [...editEleListFilter.value]
+        updateSelectStatus()
+    }
+}
+
+const updateSelectStatus = () => {
+    const selectedIds = new Set(selectedDataValue.value.map(item => item.id))
+    editEleListFilter.value.forEach(item => {
+        item.select = selectedIds.has(item.id)
+    })
+    selectedDataValue.value.forEach(item => {
+        item.select = selectedIds.has(item.id)
+    })
+}
+
+const searchFormulaName = () => {
+    editEleListFilter.value = editEleListAll.value.filter((ele) => {
+        return ele.eName.indexOf(formulaInput.value) > -1
+    })
+}
+
+const selectElement = (row) => {
+    row.select = true
+}
+
+const canlSelect = (row) => {
+    row.select = false
+    selectedDataValue.value.forEach((ele) => {
+        if (ele.id === row.id) {
+            ele.select = false
+        }
+    })
+}
+
+const confirmSelection = () => {
+    const selectedData = editEleListFilter.value.filter(item => item.select === true)
+    const arr = selectedDataValue.value.filter(item => item.select === true)
+    const combinedData = [...arr, ...selectedData]
+    
+    // 使用 Map 来过滤掉重复的 id
+    const uniqueData = Array.from(new Map(combinedData.map(item => [item.id, item])).values())
+    
+    // 触发事件将选中的数据传递给父组件
+    emit('confirm-selection', uniqueData)
+    dialogVisible.value = false
+}
+
+// 定义暴露给父组件的方法
+defineExpose({
+    show,
+})
+</script>
+
+<style scoped>
+.boxnei {
+    padding: 20px;
+}
+.flex {
+    display: flex;
+}
+.mg-b-10 {
+    margin-bottom: 10px;
+}
+.mg-l-10 {
+    margin-left: 10px;
+}
+</style>

+ 303 - 0
src/views/desk/wbs/paramter/checkEleDialog.vue

@@ -0,0 +1,303 @@
+<template>
+    <div>
+        <hc-dialog 
+            v-model="dialogVisible"
+            is-table 
+            title="选择元素表" 
+            widths="80%" 
+            @close="dialogVisible = false"
+            @save="confirmSelection"
+        >
+            <div style="height: 100%;">
+                <hc-page-split :options="{ sizes: [30, 70] }">
+                    <template #left>
+                        <hc-card scrollbar>
+                            <el-tree 
+                                :load="loadNode" 
+                                lazy 
+                                :props="defaultProps" 
+                                node-key="id" 
+                                :expand-on-click-node="false" 
+                                @node-click="handleNodeClick"
+                            />
+                        </hc-card>
+                    </template>
+                    
+                    <hc-card scrollbar>
+                        <template #search>
+                            <div class="search-box">
+                                <el-input 
+                                    v-model="searchTitle" 
+                                    placeholder="请输入你想搜索的表单名称" 
+                                    clearable 
+                                    class="w-100"
+                                />
+                                <el-button 
+                                    hc-btn 
+                                    type="primary" 
+                                    class="mg-l-10"
+                                    @click="onLoad"
+                                >
+                                    搜索
+                                </el-button>
+                            </div>
+                        </template>
+            
+                        <hc-table
+                            :column="tableColumn"
+                            :datas="tableData"
+                            :loading="tableLoading"
+                            :index-style="{ width: 60 }"
+                            :height="selectedData.length ? 'calc(100% - 220px)' : 'calc(100% - 120px)'"
+                        >
+                            <template #action="{ row }">
+                                <el-link type="primary" @click="selectElement(row)">选择元素</el-link>
+                            </template>
+                        </hc-table>
+
+                        <template #action>
+                            <div class="action-wrapper">
+                                <div v-if="selectedData.length" class="selected-box">
+                                    <div class="selected-box-title">已选择的元素</div>
+                                    <div class="selected-box-content">
+                                        <el-tag 
+                                            v-for="item in selectedData" 
+                                            :key="item.id" 
+                                            type="info" 
+                                            closable 
+                                            class="mg-r-5 mg-b-5" 
+                                            @close="handleClose(tag)"
+                                        >
+                                            {{ item.eName }}
+                                        </el-tag>
+                                    </div>
+                                </div>
+                                <div class="pagination-wrapper">
+                                    <hc-pages
+                                        :pages="page"
+                                        @change="handlePageChange"
+                                    />
+                                </div>
+                            </div>
+                        </template>
+                    </hc-card>
+                </hc-page-split>
+            </div>
+        </hc-dialog>
+        <CheckDetailEle ref="checkDetailEleDialog" @confirm-selection="handleConfirmSelection" />
+    </div>
+</template>
+
+<script setup>
+import { reactive, ref } from 'vue'
+
+import privateApi from '~api/wbs/private'
+import { getArrValue } from 'js-fast-way'
+import CheckDetailEle from './checkDetailEle.vue'
+// 定义emit
+const emit = defineEmits(['confirmCheck'])
+
+// 定义组件名称
+defineOptions({
+  name: 'CheckEleDialog',
+})
+
+// 响应式状态
+const dialogVisible = ref(false)
+const defaultProps = reactive({
+  children: 'children',
+  label: 'title',
+  isLeaf: (data) => !data.hasChildren || (data.isExistForm == 1),
+})
+
+const tableData = ref([])
+const selectedElement = ref(null)
+
+const treeId = ref('')
+const tableLoading = ref(false)
+const total = ref(0)
+const page = ref({
+  current: 1, size: 20, total: 60,
+})
+const searchTitle = ref('')
+
+const selectedData = ref([])
+
+// 引用子组件
+const checkDetailEleDialog = ref(null)
+
+// 添加表格列配置
+const tableColumn = ref([
+    { key: 'title', name: '元素表名称' },
+    { key: 'tabType', name: '元素表类型', width: 120, align: 'center' },
+    { key: 'elementTotal', name: '元素总量', width: 80, align: 'center' },
+    { key: 'tabOwner', name: '所属方', width: 140, align: 'center' },
+    { key: 'fillRate', name: '填报率', width: 80, align: 'center' },
+    { key: 'action', name: '操作', width: 80, align: 'center' },
+])
+
+// 方法定义
+const show = async (selectedElements) => {
+    dialogVisible.value = true
+    
+    const { error, code, data } = await privateApi.tabTypeLazyTreeAll({
+        parentId: 12345678910,
+        current: 1,
+        size: 1000,
+    })
+    
+    if (!error && code === 200) {
+        tableData.value = getArrValue(data?.records)
+        if (selectedElements?.length) {
+            selectedData.value = selectedElements
+        }
+    }
+}
+
+const loadNode = async (node, resolve) => {
+    const parentId = node.level === 0 ? 12345678910 : node.data.id
+    const { error, code, data } = await privateApi.tabTypeLazyTreeAll({ 
+        parentId, 
+        current: 1, 
+        size: 1000, 
+    })
+    
+    if (!error && code === 200) {
+        const records = getArrValue(data?.records)
+        resolve(records.map(item => ({
+            ...item,
+            leaf: !item.hasChildren,
+        })))
+    } else {
+        resolve([])
+    }
+}
+
+const handlePageChange = ({ current, size }) => {
+    page.value.current = current
+    page.value.size = size
+    onLoad()
+}
+
+const onLoad = async () => {
+  if (treeId.value) {
+    tableLoading.value = true
+    const { data, code, error } = await privateApi.tabTypeLazyTreeAll({
+      parentId: treeId.value, 
+      current: page.value.current, 
+      size: page.value.size, 
+      titleName: searchTitle.value,
+    })
+    if (!error && code === 200) {
+      tableData.value = getArrValue(data?.records)
+      page.value.total = data?.total
+    }
+    
+
+    tableLoading.value = false
+  }
+}
+
+const handleNodeClick = (data, node) => {
+  console.log('节点被点击:', data)
+  treeId.value = data.id
+  page.value.pageSize = 10
+  page.value.currentPage = 1
+  
+  if (data.hasChildren) {
+    onLoad()
+  }
+  
+  if (data.hasChildren === false && node.level == 2) {
+    tableLoading.value = true
+    tableData.value = [data]
+    total.value = 1
+    setTimeout(() => {
+      tableLoading.value = false
+    }, 1000)
+  } else {
+    tableData.value = []
+    total.value = 0
+  }
+}
+
+const selectElement = (row) => {
+  selectedElement.value = row
+  checkDetailEleDialog.value.show(row.id, selectedData.value)
+  console.log('选择的元素:', row)
+}
+
+const confirmSelection = () => {
+  if (selectedData.value) {
+    console.log('确认选择的元素:', selectedData.value)
+    emit('confirmCheck', selectedData.value)
+    dialogVisible.value = false
+  } else {
+    window.$message.warning('请选择一个元素')
+  }
+}
+
+const handleConfirmSelection = (data) => {
+  selectedData.value = data
+}
+
+const handleClose = (tag) => {
+  selectedData.value.splice(selectedData.value.indexOf(tag), 1)
+}
+
+// 定义暴露给父组件的方法
+defineExpose({
+  show,
+})
+</script>
+
+<style lang="scss" scoped>
+.search-box {
+    display: flex;
+    margin-bottom: 15px;
+}
+
+.action-wrapper {
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+}
+
+.selected-box {
+    position: relative;
+    height: 120px;
+    background: var(--el-bg-color);
+    border: 1px solid var(--el-border-color);
+    border-radius: 4px;
+    display: flex;
+    flex-direction: column;
+}
+
+.selected-box-title {
+    padding: 8px 10px;
+    font-weight: bold;
+    border-bottom: 1px solid var(--el-border-color);
+}
+
+.selected-box-content {
+    flex: 1;
+    padding: 10px;
+    overflow-y: auto;
+}
+
+.mg-l-10 {
+    margin-left: 10px;
+}
+
+.mg-r-5 {
+    margin-right: 5px;
+}
+
+.mg-b-5 {
+    margin-bottom: 5px;
+}
+
+.pagination-wrapper {
+    margin-top: 8px;
+}
+</style>

+ 540 - 0
src/views/desk/wbs/paramter/paramDetail.vue

@@ -0,0 +1,540 @@
+<template>
+    <div>
+        <!-- 弹窗 -->
+        <hc-dialog
+            v-model="dialogVisible"
+            title="参数信息"
+            widths="60%"
+            @close="closeParamDialog"
+        >
+            <div>
+                <div class="sub-title">{{ props.params.paramName }}</div>
+                <!-- 搜索栏 -->
+                <div class="search-container">
+                    <div>
+                        <el-form :inline="true" :model="searchForm" class="demo-form-inline">
+                            <el-form-item prop="projectName">
+                                <el-select 
+                                    v-model="searchForm.projectName" 
+                                    placeholder="项目名称" 
+                                    clearable 
+                                    style="width: 200px;"
+                                    @change="changeProject"
+                                >
+                                    <el-option
+                                        v-for="item in projectList"
+                                        :key="item.id"
+                                        :label="item.projectName"
+                                        :value="item.projectId"
+                                    />
+                                </el-select>
+                            </el-form-item>
+                            <el-form-item prop="contractSection">
+                                <el-select 
+                                    v-model="searchForm.contractId" 
+                                    placeholder="合同段" 
+                                    clearable
+                                    style="width: 200px;"
+                                >
+                                    <el-option
+                                        v-for="item in contractList"
+                                        :key="item.id"
+                                        :label="item.contractName"
+                                        :value="item.id"
+                                    />
+                                </el-select>
+                            </el-form-item>
+                            <el-form-item>
+                                <el-input 
+                                    v-model="searchForm.elementName" 
+                                    placeholder="元素名称" 
+                                    clearable
+                                />
+                            </el-form-item>
+                            <el-form-item>
+                                <el-button hc-btn type="primary" @click="searchElement">搜索</el-button>
+                            </el-form-item>
+                        </el-form>
+                    </div>
+
+                    <!-- 操作按钮 -->
+                    <div>
+                        <el-button hc-btn type="success" @click="handleAdd">新增元素</el-button>
+                        <el-button hc-btn type="primary" @click="handleEditParam">编辑参数</el-button>
+
+                        <el-button v-del-com:[handleDelteParam] hc-btn type="danger">删除参数</el-button>
+                    </div>
+                </div>
+
+                <!-- 表格 -->
+                <hc-table
+                    :column="tableColumn"
+                    :datas="tableData"
+                    :loading="tableLoading"
+                    :index-style="{ width: 60 }"
+                >
+                    <template #type="{ row }">
+                        {{ row.type === 1 ? '是' : '否' }}
+                    </template>
+                    <template #action="{ row }">
+                        <el-link type="primary" @click="handleEdit(row)">编辑</el-link>
+                        <el-link v-del-com:[handleDelteEle]="row" type="danger" class="mg-l-10">删除</el-link>
+                    </template>
+                </hc-table>
+            </div>
+        </hc-dialog>
+
+        <!-- 新增弹窗 -->
+        <hc-dialog 
+            v-model="addDialogVisible" 
+            :title="form.id ? '元素编辑' : '元素新增'" 
+            widths="30%" 
+            @close="closeDialog"
+        >
+            <el-form ref="formRef" :model="form" :rules="rules" label-position="left">
+                <el-form-item label="元素名称" label-width="120px">
+                    <el-input v-model="form.elementName" :disabled="form.selectedElement.length > 0" />
+                </el-form-item>
+                <el-form-item v-if="!isEdit" label="选择元素" label-width="120px">
+                    <el-button v-if="form.selectedElement.length === 0" style="width: 100%;" :disabled="form.elementName.length > 0" @click="checkEle">点击选择元素</el-button>
+                    <div v-else class="bottom-box" @click="checkEle">
+                        <el-scrollbar height="100px">
+                            <div class="tag-container">
+                                <el-tag 
+                                    v-for="item in form.selectedElement" 
+                                    :key="item.id" 
+                                    type="info" 
+                                    closable 
+                                    class="mb-5 mr-5" 
+                                    @close="handleClose(tag)"
+                                >
+                                    {{ item.eName }}
+                                </el-tag>
+                            </div>
+                        </el-scrollbar>
+                    </div>
+                </el-form-item>
+                <el-form-item label="是否全局参数" label-width="120px" prop="type">
+                    <el-radio-group v-model="form.type">
+                        <el-radio :value="1">是</el-radio>
+                        <el-radio :value="2">否</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+       
+                <template v-if="form.type === 2">
+                    <div v-for="(item, index) in proData" :key="index" class="form-container" :style="{ marginTop: index === 0 ? '40px' : '0' }"> 
+                        <!-- 删除图标 -->
+                        <el-button
+                            v-if="index !== 0" type="danger" size="mini"
+                            icon="el-icon-delete" 
+                            circle 
+                            class="delete-icon" 
+                            @click="removeProData(index)"
+                        />
+                        <el-form-item label="选择项目" prop="contractSection" label-width="120px">
+                            <el-select v-model="item.projectName" placeholder="请选择项目" clearable style="width: 100%;" @change="changeProject">
+                                <el-option
+                                    v-for="item1 in projectList1"
+                                    :key="item1.id"
+                                    :label="item1.projectName"
+                                    :value="item1.id"
+                                />
+                            </el-select>
+                        </el-form-item>
+                        <el-form-item label="选择合同段" prop="contractSection" label-width="120px">
+                            <el-select v-model="item.contractSection" placeholder="请选择合同段" clearable multiple class="multiple-select">
+                                <el-option
+                                    v-for="item2 in contractList"
+                                    :key="item2.id"
+                                    :label="item2.contractName"
+                                    :value="item2.id"
+                                />
+                            </el-select>
+                        </el-form-item>
+                    </div>
+                </template>
+            </el-form>
+            <template #footer>
+                <span class="dialog-footer">
+                    <el-button @click="addDialogVisible = false">取 消</el-button>
+                    <el-button type="primary" :loading="submitLoading" @click="confirmAdd">确 定</el-button>
+                </span>
+            </template>
+        </hc-dialog>
+
+        <!-- 选择元素弹窗 -->
+        <checkEleDialog ref="checkEleDialogRef" @confirm-check="confirmCheck" />
+        <!-- 编辑参数弹窗 -->
+        <addParamDialog ref="addParamDialogRef" :params="params" @add-parameter="addCardFinish" />
+    </div>
+</template>
+
+<script setup>
+import { nextTick, reactive, ref } from 'vue'
+
+import projectApi from '~api/project/project'
+import contractApi from '~api/project/contract'
+import { getArrValue } from 'js-fast-way'
+import paramApi from '~api/paramter/parmter'
+import checkEleDialog from './checkEleDialog.vue'
+import addParamDialog from './addParamDialog.vue'
+
+// 定义props
+const props = defineProps({
+    params: {
+        type: Object,
+        default: () => ({}),
+    },
+})
+
+// 定义emit
+const emit = defineEmits(['finshDetail'])
+
+// 数据定义
+const dialogVisible = ref(false)
+const projectList = ref([])
+const projectList1 = ref([])
+const contractList = ref([])
+const searchForm = reactive({
+    projectName: '',
+    contractId: '',
+    elementName: '',
+})
+const tableData = ref([])
+const tableLoading = ref(false)
+const addDialogVisible = ref(false)
+const formRef = ref(null)
+const isEdit = ref(false)
+const form = ref({
+    elementName: '',
+    selectedElement: [],
+    type: false,
+})
+const proData = ref([{}])
+const rules = {
+    type: [
+        { required: true, message: '请选择是否全局参数', trigger: 'change' },
+    ],
+}
+const editDialogVisible = ref(false)
+const paramId = ref('')
+const addParamDialogRef = ref(null)
+
+// 在 script setup 中添加
+const tableColumn = ref([
+    { key: 'elementName', name: '元素名称' },
+    { key: 'type', name: '是否全局参数', width: 120, align: 'center' },
+    { key: 'projectName', name: '项目名称', width: 180 },
+    { key: 'contractName', name: '合同段', width: 180 },
+    { key: 'action', name: '操作', width: 150, align: 'center' },
+])
+
+// 获取项目列表
+const getProjectListData = async (id) => {
+        if (!id) {
+            const res = await projectApi.page({ current: 1, size: 999 })
+            projectList.value = getArrValue(res.data.data.records ) || []
+        } else {
+            const res = await paramApi.getProjectContractByParam({ parameterId: id })
+            projectList.value = getArrValue(res.data) || []
+        }
+   
+}
+
+// 获取项目列表
+const getProjectListData1 = async () => {
+        const { data } = await projectApi.page({ current: 1, size: 999 })
+        projectList1.value = getArrValue( data?.records)
+  
+}
+
+// 项目变化
+const changeProject = async (val) => {
+    try {
+        const res = await contractApi.getList(val)
+        contractList.value = getArrValue( res.data)
+    } catch (error) {
+        console.error('获取合同段列表失败:', error)
+    }
+}
+
+// 搜索元素
+const searchElement = () => {
+    getTableData()
+}
+
+// 获取表格数据
+const getTableData = async () => {
+    tableLoading.value = true
+   
+        const { res, data, code } = await paramApi.getParameterElementList({
+            parameterId: props.params.id,
+            contractId: searchForm.contractId,
+            projectId: searchForm.projectName,
+            elementName: searchForm.elementName,
+        })
+      
+        if (code === 200) {
+            tableData.value = getArrValue( data) || []
+        } else {
+            tableData.value = []
+        }
+   
+}
+
+
+
+const handleDelteParam = async ({ item }, resolve) => {
+    const { isRes } = await paramApi.remove({ id: props.params.id })
+    resolve() //关闭弹窗
+    if (!isRes) return
+    window.$message.success('删除成功')
+    dialogVisible.value = false
+    emit('finshDetail')
+}
+
+// 关闭弹窗
+const closeParamDialog = () => {
+    dialogVisible.value = false
+    emit('finshDetail')
+    addDialogVisible.value = false
+    projectList.value = []
+    projectList1.value = []
+    contractList.value = []
+}
+
+// 显示弹窗
+const show = (id) => {
+    paramId.value = id
+  
+  
+    nextTick(() => {
+        dialogVisible.value = true
+        getTableData(id)
+        getProjectListData(id)
+    })
+}
+   
+
+
+// 新增元素
+const handleAdd = () => {
+    addDialogVisible.value = true
+    getProjectListData1()
+    isEdit.value = false
+    form.value = {
+        elementName: '',
+        selectedElement: [],
+        type: false,
+    }
+    proData.value = [{}]
+}
+
+// 关闭新增弹窗
+const closeDialog = () => {
+    addDialogVisible.value = false
+    isEdit.value = false
+    contractList.value = []
+}
+
+// 编辑参数
+const handleEditParam = () => {
+    addParamDialogRef.value?.show(props.params)
+}
+
+// 添加卡完成
+const addCardFinish = () => {
+    console.log('编辑完成')
+    closeParamDialog()
+}
+
+// 编辑元素
+const handleEdit = (row) => {
+    
+    getProjectListData1()
+    changeProject(row.projectId)
+    isEdit.value = true
+    form.value = row
+    let arr = [{
+        projectName: row.projectId,
+        contractSection: row.contractId ? row.contractId.split(',') : [],
+    }]
+    proData.value = arr
+    form.value.selectedElement = []
+    nextTick(() => {
+        addDialogVisible.value = true
+    })
+}
+
+const handleDelteEle = async ({ item }, resolve) => {
+    const { isRes } = await paramApi.removeElement({ id: item.id })
+    resolve() //关闭弹窗
+    if (!isRes) return
+    window.$message.success('删除成功')
+    getTableData().then()
+}
+/**
+ * 确认添加元素
+ * @returns {Promise<void>}
+ */
+const submitLoading = ref(false)
+const confirmAdd = async () => {
+   
+        const { selectedElement } = form.value
+        if (!form.value.elementName && (!selectedElement || selectedElement.length === 0)) {
+            window.$message.error('请选择元素或者完善元素名称')
+            return
+        }
+
+        const subArr = []
+        const projectList = []
+        
+        // 检查是否需要添加项目数据
+        if (form.value.type === 2) {
+            if (!proData.value?.[0]?.projectName) {
+                window.$message.warning('请先选择项目')
+                return
+            }
+            
+            proData.value.forEach(item => {
+                if (!item.contractSection) {
+                    window.$message.warning('请选择合同段')
+                    return
+                }
+                projectList.push({
+                    projectId: item.projectName,
+                    contractId: Array.isArray(item.contractSection) 
+                        ? item.contractSection.join(',') 
+                        : item.contractSection,
+                })
+            })
+        }
+
+        // 构建提交数据
+        if (selectedElement?.length > 0) {
+            selectedElement.forEach(item => {
+                subArr.push({
+                    id: form.value.id,
+                    parameterId: props.params.id,
+                    type: form.value.type,
+                    elementName: item.eName,
+                    projectList: form.value.type === 2 ? projectList : [],
+                })
+            })
+        } else if (form.value.elementName) {
+            subArr.push({
+                id: form.value.id,
+                parameterId: props.params.id,
+                type: form.value.type,
+                elementName: form.value.elementName,
+                projectList: form.value.type === 2 ? projectList : [],
+            })
+        }
+
+        if (subArr.length === 0) {
+            window.$message.error('提交数据不能为空')
+            return
+        }
+        submitLoading.value = true
+
+        const { code, msg } = await paramApi.submitElement(subArr)
+        submitLoading.value = false
+        if (code === 200) {
+            window.$message.success(msg)
+            addDialogVisible.value = false
+            await getTableData()
+        } else {
+            window.$message.error(msg || '操作失败')
+        }
+       
+}
+
+// 添加项目数据
+const addProData = () => {
+    proData.value.push({})
+}
+
+// 移除项目数据
+const removeProData = (index) => {
+    proData.value.splice(index, 1)
+}
+const checkEleDialogRef = ref(null)// 选择元素
+const checkEle = () => {
+    checkEleDialogRef.value.show(form.value.selectedElement)
+}
+
+// 确认检查
+const confirmCheck = (selectedData) => {
+    form.value.selectedElement = selectedData
+    console.log('选择的元素1111111111:', selectedData)
+}
+
+// 处理关闭
+const handleClose = (tag) => {
+    form.value.selectedElement.splice(form.value.selectedElement.indexOf(tag), 1)
+}
+
+// 暴露方法给父组件
+defineExpose({
+    show,
+})
+</script>
+
+<style lang="scss" scoped>
+.form-container1 {
+    position: relative;
+    max-height: 400px;
+    overflow-y: auto;
+}
+.form-container {
+    border: 1px solid #ccc; /* 淡灰色边框 */
+    padding: 20px 40px 0px 20px;
+    margin-bottom: 15px;
+    position: relative; 
+}
+.delete-icon {
+    position: absolute;
+    top: 5px;
+    right:5px;
+    z-index: 1000;
+}
+.add-button {
+    margin-left: 20px;
+    position: absolute;
+    top: 0px;
+    right: 5px;
+    z-index: 1000;
+}
+.multiple-select {
+    width: 100%;
+}
+.search-container {
+    display: flex;
+    justify-content: space-between; /* 使子元素两端对齐 */
+    align-items: center; /* 垂直居中对齐 */
+}
+.bottom-box {
+    width: 100%;
+    height: 120px;
+    border: 1px solid var(--el-border-color);
+    margin-top: 10px;
+    cursor: pointer;
+}
+.tag-container {
+    padding: 10px;
+}
+.mr-5 {
+    margin-right: 5px;
+}
+.mb-5 {
+    margin-bottom: 5px;
+}
+.sub-title{
+    margin-bottom: 15px;
+    font-weight: bold;
+    font-size: 16px
+}
+.mg-l-10 {
+    margin-left: 10px;
+}
+</style>

+ 227 - 0
src/views/desk/wbs/paramter/paramLid.vue

@@ -0,0 +1,227 @@
+<template>
+    <hc-drawer
+        v-model="isShow"
+        to-id="hc-main-box"
+        is-close
+        @close="drawerClose"
+    >
+        <hc-card v-loading="loading" scrollbar>
+            <template #extra>
+                <el-button hc-btn type="primary" @click="addCard">新增参数</el-button>
+            </template>
+
+            <div v-if="projectPageList.length > 0" class="param-list-container">
+                <el-row :gutter="20">
+                    <el-col 
+                        v-for="item in projectPageList" 
+                        :key="item.id" 
+                        :span="6"
+                    >
+                        <hc-card-item 
+                            class="param-card" 
+                            @click="handleSetParameterName(item)"
+                        >
+                            <div class="card-content">
+                                <div class="name-content">
+                                    <h3>{{ item.paramName }}</h3>
+                                    <p class="text-bold">{{ item.paramTypeName }}</p>
+                                    <p class="small-text">{{ item.remarks }}</p>
+                                </div>
+                            </div>
+                        </hc-card-item>
+                    </el-col>
+                </el-row>
+            </div>
+            <div v-else class="empty-data">
+                <hc-empty />
+            </div>
+            <template #action>
+                <hc-pages 
+                    v-if="projectPageList.length > 0"
+                    :pages="searchForm" 
+                  
+                    @change="handlePageChange" 
+                />
+            </template>
+        </hc-card>
+
+        <!-- 参数详情 -->
+        <paramDetail 
+            ref="paramDetailRef"
+            :params="parameterRow"
+            @finsh-detail="finshDetail"
+        />
+
+        <!-- 新增参数 -->
+        <addParamDialog 
+            ref="addParamDialogRef"
+            @add-parameter="addCardFinish" 
+        />
+    </hc-drawer>
+</template>
+
+<script setup>
+import { defineModel, reactive, ref, watch } from 'vue'
+import { getArrValue, getObjValue } from 'js-fast-way'
+import paramDetail from './paramDetail.vue'
+import addParamDialog from './addParamDialog.vue'
+import paramApi from '~api/paramter/parmter'
+
+// 定义组件名称
+defineOptions({
+    name: 'ParamLid',
+})
+
+// 双向绑定抽屉显示状态
+const isShow = defineModel('modelValue', {
+    type: Boolean,
+    default: false,
+})
+
+// 组件引用
+const paramDetailRef = ref(null)
+const addParamDialogRef = ref(null)
+
+// 数据定义
+const loading = ref(false)
+const projectPageList = ref([])
+const parameterRow = ref({})
+
+const searchForm = ref({ current: 1, size: 12, total: 0 })
+
+// 获取参数列表
+const getProjectPageList = async () => {
+    loading.value = true
+    const { error, code, data } = await paramApi.queryParameterList({
+        ...searchForm.value,
+    })
+    loading.value = false
+    if (!error && code === 200) {
+        projectPageList.value = getArrValue(data?.records)
+        searchForm.value.total = data?.total
+    } else {
+        projectPageList.value = []
+        searchForm.value.total = 0
+    }
+}
+
+// 分页变化
+const handlePageChange = ({ current, size }) => {
+   
+    
+    searchForm.value.current = current
+    searchForm.value.size = size
+    getProjectPageList()
+}
+
+// 新增参数
+const addCard = () => {
+    addParamDialogRef.value?.show()
+}
+
+// 新增完成
+const addCardFinish = () => {
+    getProjectPageList()
+}
+
+// 详情完成
+const finshDetail = () => {
+    getProjectPageList()
+}
+
+// 查看参数详情
+const handleSetParameterName = (item) => {
+    parameterRow.value = item
+    paramDetailRef.value?.show(item.id)
+}
+
+// 关闭抽屉
+const drawerClose = () => {
+    isShow.value = false
+}
+
+// 监听显示状态
+watch(isShow, (val) => {
+    if (val) {
+        getProjectPageList()
+    }
+})
+</script>
+
+<style lang="scss" scoped>
+.param-list-container {
+    padding: 20px;
+
+    .el-row {
+        row-gap: 20px;
+    }
+}
+
+.param-card {
+    cursor: pointer;
+    background-color: #F5F7FA;
+    height: 100%;
+    transition: all 0.3s;
+    
+    &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+    }
+    
+    .card-content {
+        padding: 16px;
+        display: flex;
+        flex-direction: column;
+        height: 100%;
+        min-height: 160px;
+    }
+
+    .name-avatar {
+        width: 60px;
+        height: 60px;
+        background: var(--el-color-primary);
+        color: white;
+        border-radius: 8px;
+        font-size: 24px;
+        margin-bottom: 16px;
+    }
+
+    .name-content {
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        
+        h3 {
+            margin: 0 0 16px;
+            font-size: 16px;
+            font-weight: bold;
+            line-height: 1.4;
+        }
+
+        .text-bold {
+            font-weight: bold;
+            margin: 0 0 20px;
+            line-height: 1.4;
+        }
+
+        .small-text {
+            font-size: 14px;
+            color: var(--el-text-color-secondary);
+            margin: auto 0 0 0;
+            line-height: 1.4;
+            display: -webkit-box;
+            -webkit-box-orient: vertical;
+            -webkit-line-clamp: 2;
+            overflow: hidden;
+            text-overflow: ellipsis;
+        }
+    }
+}
+
+.empty-data {
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+</style>