vue3 encapsulates the table pop-up component - table radio selection, axios dynamic interface, toRefs() usage, loading customization, table content exceeding the height scroll

vue3 encapsulates the table pop-up component - table radio selection, axios dynamic interface, toRefs() usage, loading customization, table content exceeding the height scroll

1

Insert image description here

2

Insert image description here

1. Click the page

index.vue

<template>
  <div class="main-content">
    <el-form ref="formRef" label-width="130" :model="formInline.formData">
      <el-row>
        <el-col :span="6">
          <el-form-item
            label="项目名称:"
            prop="prjName"
            :rules="{
              required: true,
              message: '请选择项目',
              trigger: 'change',
            }"
          >
            <el-input
              v-model="formInline.formData.prjName"
              :disabled="route.query.type === 'view'"
              maxlength="100"
              placeholder="请输入"
              @click="handlePrjName"
              @input="
                (e) => (formInline.formData.prjName = replaceCommonText(e))
              "
            />
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="牵头单位:" prop="leadUnitName">
            <el-input
              v-model="formInline.formData.leadUnitName"
              disabled="false"
              maxlength="100"
              placeholder="请输入"
              @input="
                (e) => (formInline.formData.leadUnitName = replaceCommonText(e))
              "
            />
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="项目负责人:" prop="prjHeadName">
            <el-input
              v-model="formInline.formData.prjHeadName"
              disabled="false"
              maxlength="100"
              placeholder="请输入"
              @input="
                (e) => (formInline.formData.prjHeadName = replaceCommonText(e))
              "
            />
          </el-form-item>
        </el-col>
        <el-col :span="6">
          <el-form-item label="系统内单位角色:" prop="innerRole">
            <dictSelect
              v-model="formInline.formData.innerRole"
              :dictid="'sgCompRole'"
              disabled="false"
            />
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>
    <SelectProject
      v-if="dialogProject"
      v-model:dataType="dataType"
      v-model:dialogVisible="dialogProject"
      v-model:prjData="formInline.formData"
      :prj-category="2"
      :request-url="mediumExamSelectPrj"
      :selected="formInline.formData.prjCode"
      @emit-select="handleChooseData"
    />
  </div>
</template>
<script setup>
  import SelectProject from "@/components/SelectProject";
  import { mediumExamSelectPrj } from "@/api/project/couny";
  const formInline = reactive({
    formData: {},
  });
  const dialogProject = ref(false);
  const dataType = ref("project");
  const handlePrjName = () => {
    dialogProject.value = true;
  };
  const handleChooseData = (val) => {
    formInline.formData.prjId = val[0].id;
  };
</script>
<style lang="scss" scoped></style>

2. Home page pop-up component

src\app\science\components\SelectProject.vue

<!--
  dialogVisible    // 弹窗显隐
  dataType         // 弹窗数据类型 project项目数据
  prjData          // 选择后项目数据
  prjCategory      // 项目分类 1 公司级,2 国家级,3 各单位自管, 100可研申报
  emit-select      // 项目选择后回调方法
  requestUrl       // 新的项目请求接口
-->
<template>
  <el-dialog
    v-model="dialogVisible"
    class="diaStyle"
    :modal="false"
    style="height: 80vh; overflow-y: auto"
    :title="dataType === 'project' ? '选择项目' : ''"
  >
    <el-form
      ref="formRef"
      class="inline-form"
      :inline="true"
      label-position="right"
      label-width="100px"
      :model="formInline"
    >
      <el-form-item label="项目名称:" prop="prjName">
        <el-input
          v-model="formInline.prjName"
          maxlength="100"
          placeholder="请输入"
          :rules="[
            {
              validator: validateCommonText,
              trigger: ['blur', 'change'],
            },
          ]"
          @input="(e) => (formInline.prjName = replaceCommonText(e))"
        />
      </el-form-item>

      <el-form-item
        label="牵头单位:"
        prop="leadUnit"
        :rules="[
          {
            validator: validateCommonText,
            trigger: ['blur', 'change'],
          },
        ]"
      >
        <unitSelect v-model="formInline.leadUnit" />
      </el-form-item>

      <el-form-item class="search_btn" style="float: right">
        <el-button v-throttle="3000" type="primary" @click="onSubmit">
          查询
        </el-button>
        <el-button v-throttle="3000" plain type="primary" @click="resetForm">
          重置
        </el-button>
      </el-form-item>
    </el-form>
    <el-table
      ref="multipleTable"
      border
      class="dialog-table"
      :data="tableData"
      highlight-current-row
      stripe
      @row-click="onSelect"
      @select-all="onSelectAll"
      @selection-change="selectItem"
    >
      <el-table-column width="55">
        <template #default="{ row }">
          <el-radio v-model="templateSelete" :label="row.id">{
   
   { '' }}</el-radio>
        </template>
      </el-table-column>

      <el-table-column label="项目名称" prop="prjName" />
      <el-table-column label="牵头单位" prop="leadUnitName" />
      <el-table-column label="项目负责人" prop="prjHeadName" />
      <el-table-column label="经费分配">
        <template #default="scope">
          <el-input
            v-if="scope.row.editType"
            v-model="scope.row.fee"
            maxlength="100"
            @click="selectFunds(scope.$index, scope.row)"
            @input="(e) => (scope.row.fee = replaceCommonText(e))"
          />
          <div v-else class="contain">
            <p v-for="item in scope.row.yunitList" :key="item">
              {
   
   { item.bearUnitName }}:{
   
   { item.payIn }}
            </p>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="项目标签">
        <template #default="{ row }">
          <div v-if="!row.isEdit">
            <span v-for="(item, index) in row.labelVOList" :key="item">
              {
   
   { item.labelName }}
              <!-- 最后一个标签尾部没有逗号 -->
              <span v-if="index !== row.labelVOList.length - 1">,</span>
            </span>
          </div>
          <el-select
            v-else
            v-model="row.labelVOListV2"
            multiple
            placeholder="请选择"
            @change="selectChange"
          >
            <el-option
              v-for="item in option"
              :key="item.id"
              :label="item.labelName"
              :value="item.id"
            />
          </el-select>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      background
      :current-page="page.currentPage"
      layout="total,size,prev,pager,next,jumper"
      :page-size="page.pageSize"
      :total="page.total"
      @current-change="hanleCurrentChange"
    />
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="submitDialog">确定</el-button>
        <el-button plain type="primary" @click="cancelDialog">取消</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup>
  import { projectData, feasStuPage } from "@/api/project/couny";
  import unitSelect from '@src/components/unitSelect'
  import { validateCommonText, replaceCommonText } from '@src/utils/validate'

  const multipleTable = ref(null)
  const formRef = ref(null)
  const multipleSelection = ref()

  const props = defineProps({
    dialogVisible: {
      default: null,
      type: Boolean,
    },
    selected: {
      default: '',
      type: String,
    },
    dataType: {
      default: null,
      type: String,
    },
    prjData: {
      default: null,
      type: Object,
    },
    prjCategory: {
      default: null,
      type: Number,
    },
    requestUrl: {
      default: null,
      type: Function,
    },
  })

  const { dataType, prjCategory, requestUrl } = toRefs(props)
  const emit = defineEmits([
    'update:dialogVisible',
    'update:prjData',
    'emit-select',
  ])
  const dialogVisible = computed({
    get: () => props.dialogVisible,
    set: (val) => emit('update:dialogVisible', val),
  })

  const page = reactive({
    pageSize: 10,
    currentPage: 1,
    total: 0,
  })
  //const templateSelete = ref('')
  const templateSelete = ref(props.selected)

  const tableData = ref([])

  //查询
  const formInline = ref({
    prjName: '',
    techFieldName: '',
    leadUnit: '',
  })
  if (dialogVisible) {
    formInline.value = {
      prjName: '',
      techFieldName: '',
      leadUnit: '',
    }
  }
  //重置
  const resetForm = () => {
    // if (!formEl) return
    formRef.value.resetFields()
    onLoad()
  }

  const onSubmit = async () => {
    page.currentPage = 1
    onLoad()
  }

  const hanleCurrentChange = (val) => {
    page.currentPage = val
    onLoad()
  }

  const onLoad = async () => {
    const formData = {
      size: page.pageSize,
      current: page.currentPage,
      prjCategory: prjCategory.value,
      ...formInline.value,
      state: '4',
    }
    const loadingInstance = ElLoading.service({
      lock: true,
      text: 'Loading',
      background: 'rgba(0, 0, 0, 0.7)',
    })

    if (requestUrl.value) {
      await requestUrl
        .value(formData)
        .then((res) => {
          tableData.value = res.data.data
          page.pageSize = res.data.pageSize
          page.total = Number(res.data.total)
          page.currentPage = res.data.pageNumber
          loadingInstance.close()
        })
        .catch(() => {
          loadingInstance.close()
        })
    } else if (prjCategory.value == 100) {
      formData.processState = '4'
      formData.leadUnitId = formData.leadUnit
      await feasStuPage(formData)
        .then((res) => {
          res.data.records.forEach((el) => {
            el.leadUnitName = el.leadUnitId
            el.prjHeadName = el.headName
          })
          tableData.value = res.data.records
          page.pageSize = res.data.pageSize
          page.total = res.data.total
          page.currentPage = res.data.pageNumber
          loadingInstance.close()
        })
        .catch(() => {
          loadingInstance.close()
        })
    } else {
      await projectData(formData)
        .then((res) => {
          tableData.value = res.data.records
          page.pageSize = res.data.pageSize
          page.total = res.data.total
          page.currentPage = res.data.pageNumber
          loadingInstance.close()
          tableData.value.forEach((el) => {
             if(el.prjCode == props.selected){
               templateSelete.value = el.id
               multipleTable.value = []
               multipleTable.value.push(el)
             }
          })
        })
        .catch(() => {
          loadingInstance.close()
        })
    }
  }

  onLoad()
  const onSelectAll = () => {
    multipleTable.value.clearSelection()
  }
  //下拉
  const selectChange = (val) => {
    console.log('val', val)
  }
  const selectItem = (rows) => {
    if (rows.length > 1) {
      const newRows = rows.filter((it, index) => {
        if (index === rows.length - 1) {
          multipleTable.value.toggleRowSelection(it, true)
          return true
        } else {
          multipleTable.value.toggleRowSelection(it, false)
          return false
        }
      })
      multipleSelection.value = newRows
    } else {
      multipleSelection.value = rows
    }
  }

  const onSelect = (row) => {
    templateSelete.value = row.id
    multipleTable.value.clearSelection()
    multipleTable.value.toggleRowSelection(row, true)
    multipleSelection.value = []
    multipleSelection.value.push(row)
  }

  const cancelDialog = () => {
    emit('update:dialogVisible', false)
  }
  const submitDialog = async () => {
    if (multipleSelection.value) {
      multipleSelection.value[0].prjId = multipleSelection.value[0].id
      emit('update:prjData', multipleSelection.value[0])
      emit('update:dialogVisible', false)
      emit('emit-select', multipleSelection.value)
    } else {
      ElMessage.error('请选择项目')
    }
  }
</script>
<style lang="scss" scoped>
  .dialog-project {
    height: 80vh;
    overflow-y: auto;
  }
  .dialog-footer {
    text-align: center;
  }
  .contain {
    height: 70px !important;
    overflow-y: auto !important; //表格内容超出高度滚动
    p {
      line-height: 14px;
    }
  }
</style>
Home page interface
import request from '@src/utils/request'
import {
    
     sciencePostUrl } from '@/config'

//项目中期项目选择列表
export const mediumExamSelectPrj = (data) => {
    
    
  return request({
    
    
    url: `${
      
      sciencePostUrl}/mediumExam/selectPrj`,
    method: 'post',
    data,
  })
}

//变更管理-项目-选择项目审核通过的
export const projectData = (data) => {
    
    
  return request({
    
    
    url: `${
      
      sciencePostUrl}/prjChange/queryItem`,
    method: 'post',
    data,
  })
}

//可研申报-项目-选择项目审核通过的
export const feasStuPage = (data) => {
    
    
  return request({
    
    
    url: `${
      
      sciencePostUrl}/feasStu/feasStuPage`,
    method: 'post',
    data,
  })
}
form validation

src\utils\validate.ts

/**
 * @description form表单特定字符校验
 * @param value
 * @returns {boolean}
 */
export function validateCommonText(rule: any, value: any, callback: any) {
    
    
    const err: any = validatorSpecialCharacter(value)
    if (err) {
    
    
      callback(new Error(err.message))
      return
    }
  callback()
}

//  禁止输入框特殊字符校验 
export function replaceCommonText(e: any) {
    
    
  const err: any = validatorSpecialCharacter(e)
  if (err) {
    
    
    ElMessage({
    
    
      message:  err.message,
      type: 'warning',
    })
    const y = e.replace(e, '')
    return y
  } else {
    
    
    return e     
  }
}

3. Drop-down component

src\components\unitSelect.vue

<!-- 
  modelValue       //select的值 code值
  disabled         //是否编辑
  contrUnitName    //回显是select的name 值
  change-unit      //回调方法: 参数为选择后单位相关的数据
  labelCode        //二级单位数据传对应labelCode   
  orgcode         //组织树下拉数据筛选条件
-->
<template>
  <div style="width: 100%">
    <el-select
      v-if="labelCode"
      v-model="unitValue"
      :disabled="disabled"
      filterable
      placeholder="请选择单位"
      @change="selectUnitEvent"
    >
      <el-option
        v-for="item in companyLabelData"
        :key="item.id"
        :label="item.orgObjMdmName"
        :value="item.id"
      />
    </el-select>

    <el-select
      v-else-if="orgcode"
      v-model="unitValue"
      :disabled="disabled"
      filterable
      placeholder="请选择单位"
      @change="selectUnitEvent"
    >
      <el-option
        v-for="item in companyData"
        :key="item.id"
        :label="item.orgObjMdmName"
        :value="item.id"
      />
    </el-select>

    <el-select
      v-else
      v-model="unitValue"
      clearable
      :disabled="disabled"
      filterable
      :loading="loading"
      placeholder="请搜索单位"
      remote
      :remote-method="remoteMethod"
      reserve-keyword
      @change="selectUnitEvent"
    >
      <template #prefix>
        <el-icon class="el-input__icon"><search /></el-icon>
      </template>
      <el-option
        v-for="item in companyData"
        :key="item.id"
        :label="item.orgObjMdmName"
        :value="item.id"
      />
    </el-select>
  </div>
</template>
<script setup>
  import { getUnits, getLabelUnits } from '@src/api/common/base'
  import { Search } from '@element-plus/icons-vue'
  const props = defineProps({
    modelValue: {
      default: null,
      type: Number,
    },
    contrUnitName: {
      default: null,
      type: String,
    },
    labelCode: {
      default: null,
      type: Array,
    },
    disabled: {
      default: false,
      type: Boolean,
    },
    orgcode: {
      default: '',
      type: String,
    },
  })

  const ruleForm = ref({
    orgObjMdmNameLike: '',
    current: '1',
    size: 100,
  })
  const { labelCode, disabled, orgcode } = toRefs(props)
  const emit = defineEmits(['update:modelValue', 'change-unit'])
  const companyData = ref()
  const companyLabelData = ref()

  onMounted(() => {
    watch(
      () => props.modelValue,
      (newVal) => {
        if (newVal) {
          nextTick(() => {
            if (props?.labelCode && !companyLabelData.value?.length) {
              getLabelUnitsList()
            } else if (props?.orgcode && !companyData.value?.length) {
              getUnitsList()
            } else if (!props.orgcode) {
              companyData.value = [
                {
                  orgObjMdmName: props.contrUnitName,
                  id: props.modelValue,
                },
              ]
            }
          })
        }
      },
      { immediate: true }
    )
  })

  //接口文档调取
  const getUnitsList = async () => {
    ruleForm.value.porgObjCodeInner = orgcode.value
    const pattern = /[_]$/
    if (!pattern.test(ruleForm.value.orgObjMdmNameLike)) {
      await getUnits(ruleForm.value).then((res) => {
        companyData.value = res.data.list
      })
    }
  }
  const getLabelUnitsList = async () => {
    await getLabelUnits({ labelCode: labelCode.value }).then((res) => {
      companyLabelData.value = res.data
    })
  }

  if (labelCode.value && labelCode.value.length) {
    getLabelUnitsList()
  } else if (orgcode.value && orgcode.value.length) {
    getUnitsList()
  }

  const unitValue = toRef(props, 'modelValue')
  const selectUnitEvent = (val) => {
    emit('update:modelValue', val)
    let obj
    if (labelCode.value && labelCode.value.length) {
      obj = val
        ? companyLabelData.value.find(function (item) {
            return item.id === val
          })
        : { id: '', orgObjMdmName: '' }
    } else {
      obj = val
        ? companyData.value.find(function (item) {
            return item.id === val
          })
        : { id: '', orgObjMdmName: '' }
    }
    emit('change-unit', obj)
  }

  //过滤筛选关键字数据
  const loading = ref(false)
  const remoteMethod = (query) => {
    if (query) {
      ruleForm.value.orgObjMdmNameLike = query
      loading.value = true
      setTimeout(() => {
        loading.value = false
        getUnitsList()
      }, 200)
    } else {
      companyData.value = []
    }
  }
</script>
unit interface

src\api\common\base.js

import request from '@src/utils/request'

//枚举值查询 process.env.VUE_APP_URL--> apiUrl
const configInfo = sessionStorage.getItem('configInfo') || '{}'
const apiUrl = JSON.parse(configInfo)?.baseApiUrl || 'http://27.86.34.99/kjapi'

//模糊搜索单位下来数据
export const getUnits = (data) => {
    
    
  return request({
    
    
    url: `${
      
      apiUrl}/srbm-bas-mdm-front/member/feignDataRel/org/page`,
    method: 'post',
    data,
  })
}

//二级单位数据
export const getLabelUnits = (data) => {
    
    
  return request({
    
    
    url: `${
      
      apiUrl}/srbm-bas-mdm-front/member/feignDataRel/org/search`,
    method: 'post',
    data,
  })
}

Guess you like

Origin blog.csdn.net/weixin_44867717/article/details/132603418