vue3+antd-vue@4 a-form 嵌套a-table 实现行内 勾选才进行检验

一、效果图如下

二、实现方法

以下方法可以判断当前行是否选中(核心实现代码)

javascript 复制代码
// 判断是否是选中的数据
const isSeledted = computed(() => record => {
  return state.selectedRowKeys.some(id => id === record.id);
});

在需要需要检验的字段的判断一下就好, 如果当前行勾选了, 就加上rules的校验, 否则就为rules = null

javascript 复制代码
:rules="isSeledted(record) ? [{ required: true, message: '请输入用途', trigger: 'blur' }] : null"
html 复制代码
<template #bodyCell="{ column, text, record, index }">
  <template v-if="column.dataIndex == 'purpose'">
    <div style="height: 44px" v-if="currentStep === 0">
      <a-form-item
        class="custom-form-item"
        label=" "
        :colon="false"
        :name="[index, 'purpose']"
        :rules="isSeledted(record) ? [{ required: true, message: '请输入用途', trigger: 'blur' }] : null">
        <a-input style="width: 100%" v-model:value="record[column.dataIndex]"></a-input>
      </a-form-item>
    </div>
    <span v-else>{{ text }}</span>
  </template>
  <template v-else-if="column.dataIndex == 'MBstate'">
    <span>已分配</span>
  </template>
</template>

三、完整代码

html 复制代码
<template>
  <div class="allot-warp">
    <a-form ref="tableFormRef" :model="state.tableSource" :label-col="{ style: { width: '10px' } }" :wrapper-col="{ span: 0 }">
        <a-table
          :row-key="_ => _.id"
          class="ant-table-striped"
          bordered
          :dataSource="tableSource"
          :columns="resultTableColumns"
          :pagination="Pagination"
          :scroll="{ x: tableWidth }"
          :row-selection="
            currentStep == 0
              ? {
                  selectedRowKeys: selectedRowKeys,
                  onChange: handleSelectChange
                }
              : null
          "
          :row-class-name="(_record, index) => (index % 2 === 1 ? 'table-striped' : null)">
          <template #headerCell="{ column }">
            <template v-if="column.dataIndex === 'result'">
              <div class="result-warp">
                <span>配置结果</span>
                <a-button type="link" @click="handleConfigResult">
                  <template #icon>
                    <SearchOutlined />
                  </template>
                </a-button>
              </div>
            </template>
          </template>
          <template #title="{ column }">
            <div v-if="currentStep == 1" style="display: flex; justify-content: space-between; align-items: center">
              <span>!红色背景代表配置校验未通过,黄色背景代表配置校验需要二次确认,绿色背景代表配置校验通过</span>
              <a-button type="primary" size="small" @click="handleExport">
                导出
                <template #icon>
                  <ArrowDownOutlined />
                </template>
              </a-button>
            </div>
          </template>
          <template #bodyCell="{ column, text, record, index }">
            <template v-if="column.dataIndex == 'purpose'">
              <div style="height: 44px" v-if="currentStep === 0">
                <a-form-item
                  class="custom-form-item"
                  label=" "
                  :colon="false"
                  :name="[index, 'purpose']"
                  :rules="isSeledted(record) ? [{ required: true, message: '请输入用途', trigger: 'blur' }] : null">
                  <a-input style="width: 100%" v-model:value="record[column.dataIndex]"></a-input>
                </a-form-item>
              </div>
              <span v-else>{{ text }}</span>
            </template>
            <template v-else-if="column.dataIndex == 'MBstate'">
              <span>已分配</span>
            </template>
          </template>
        </a-table>
      </a-form>
  </div>
</template>

<script setup>
import { ArrowDownOutlined, SearchOutlined } from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';
import { computed, h, reactive, ref, watch } from 'vue';
import VLANConfigDetail from '../components/VLANConfigDetail.vue';
const steps = [{ title: '分配选择' }, { title: '配置校验' }, { title: '分配入库' }];
let currentStep = ref(0);
const state = reactive({
  orderInfo: {
    orderId: ''
  },
  selectedRowKeys: []
});

let resultTableColumns = ref();

import useTable from './hooks/useTable.js';
const { tableSource, tableColumns, step2TableColumns, tableWidth, Pagination, getListFn, handleConfigResult, handleExport } = useTable();

const handleSelectChange = (selectedRowKeys, selectedRows) => {
  state.selectedRowKeys = selectedRowKeys;
  console.log('-------- selectedRowKeys --------', state.selectedRowKeys);
};

// 判断是否是选中的数据
const isSeledted = computed(() => record => {
  return state.selectedRowKeys.some(id => id === record.id);
});

// 查询接口
getListFn();

const configDetailRef = ref(null);
// 查看VLAN配置详情
const handleDetail = () => {
  configDetailRef.value.init('allot');
};

// 确认分配
const handleAllotSubmit = () => {
  console.log('handleAllotSubmit');
  Modal.confirm({
    title: '分配选择提交',
    content: '确认提交分配选择吗,确认提交即进行下一步配置校验',
    okText: '确 认',
    cancelText: '取 消',
    centered: true,
    onOk() {
      currentStep.value = 1;
    },
    onCancel() {}
  });
};

let step4Tip = row => {
  return h('div', null, [
    h('div', {}, [h('div', {}, '情景1:'), h('div', {}, `${row.tip}`)]),
    h('div', {}, [h('div', {}, '情景1:'), h('div', {}, `${row.tip}`)]),
    h('div', {}, [h('div', {}, '情景1:'), h('div', {}, `${row.tip}`)])
  ]);
};
// 确认配置检验
const handleAllot2Submit = () => {
  Modal.confirm({
    title: '预埋确认',
    content: step4Tip({ tip: '经再次校验,xx平面目标VLAN值:xxx,xxx现网未配置,无法预埋!请进行实施配置' }),
    okText: '确 认',
    cancelText: '取 消',
    centered: true,
    onOk() {
      currentStep.value = 2;
    },
    onCancel() {
      console.log('Cancel');
    }
  });
};

// 返回上一步
const handleBack = () => {};

watch(
  currentStep,
  val => {
    if (val === 1) {
      resultTableColumns.value = step2TableColumns.value;
    } else {
      resultTableColumns.value = tableColumns.value;
    }
  },
  { immediate: true }
);
</script>

<style lang="less" scoped>
.allot-warp {
  width: 100%;
  height: 100%;
  padding: 20px;
  background-color: #f5f5f5;
  .setps-warp {
    width: 100%;
    padding: 50px 40px;
    background-color: #fff;
  }
  .content-warp {
    margin-top: 15px;
    padding: 40px 20px;
    background-color: #fff;
    .content-tip {
      padding: 0 0 20px 0;
      .tip-title {
        font-size: 16px;
      }
      .tip-warp {
        margin-top: 10px;
        padding-left: 20px;
        .tip-item {
          margin-bottom: 10px;
          font-size: 14px;
        }
      }
    }
  }
}
.order-info-warp {
  padding: 20px 20px 0 20px;
  background-color: #fff;
  display: flex;
  .order-title {
    font-size: 18px;
    font-weight: 600;
    display: flex;
    align-items: center;
    margin-bottom: 20px;
  }
  .order-title::before {
    content: '';
    display: inline-block;
    width: 5px;
    height: 18px;
    background-color: #1890ff;
    margin-right: 10px;
  }
  .order-item-warp {
    margin: 10px 0;
    label {
      display: inline-block;
      width: 100px;
      padding-left: 20px;
    }
  }
}
</style>
相关推荐
mldong1 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排2 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60612 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角4 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!4 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰4 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi5 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen6 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马7 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu7 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss