vue3+antd的table小組件

antdtable組件支持增加搜索欄配置矮燎。增加按鈕等操作。

閑話少敘梅猿,上代碼

<!-- 更多與收起詳見用戶管理頁面 -->
<template>
  <div class="c-data-table">
    <a-spin :spinning="spinning">
      <a-card :title="title" :bordered="false">
        <div class="dt-search" v-if="$slots.search || $slots.searchmore">
          <!--  -->
          <a-form
            ref="searchform"
            size="mini"
            class="dt-search-form-inline"
            layout="inline"
            :model="searchParams"
            @submit.prevent="search({ _fromBar: true, _begin: 0 })"
          >
            <div v-if="showmore">
              <div class="formSearchLittle">
                <slot name="search" />
              </div>
            </div>
            <div v-else>
              <div class="">
                <slot name="searchmore" />
              </div>
            </div>
            <button type="submit" style="display: none;"></button>
          </a-form>
        </div>
        <div class="dt-toolbar" v-if="$slots.toolbar">
          <slot name="toolbar" />
        </div>
        <a-table
          :columns="columns"
          :data-source="dataSource"
          :pagination="false"
          :bordered="bordered"
          rowKey="id"
        >
        </a-table>
        <a-config-provider :locale="locale" v-if="pageable">
          <a-pagination
            show-size-changer
            v-model:current="current"
            v-model:pageSize="pageSize"
            :total="total"
            :showQuickJumper="true"
            @showSizeChange="onShowSizeChange"
            @change="onChange"
          >
          </a-pagination>
        </a-config-provider>
      </a-card>
    </a-spin>
  </div>
</template>
<script>
import { defineComponent, ref, watch, getCurrentInstance } from "vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
import { message } from "ant-design-vue";
import { useForm } from "@ant-design-vue/use";
export default defineComponent({
  name: "c-data-table",
  props: {
    //是否顯示邊框
    bordered: {
      type: Boolean,
      default: false,
    },
    // 請求的返回渲染參數(shù)
    resultKey: {
      type: String,
      default: "data",
    },
    // 行
    columns: Array,
    //請求地址
    serverId: String,
    //搜索請求
    searchParams: {
      type: Object,
      default: () => ({}),
    },
    title: String,
    // 是否顯示分頁
    pageable: {
      type: Boolean,
      default: true,
    },
  },
  setup() {
    let { proxy } = getCurrentInstance();
    const dataSource = ref([]);
    // const searchParams = reactive({ name: "" });
    const { resetFields } = useForm(proxy.$props.searchParams, {});
    const spinning = ref(false);
    const pageSize = ref(20);
    const current = ref(1);
    const total = ref(0);
    const onShowSizeChange = (current, pageSize) => {
      console.log(current, pageSize);
    };
    const onChange = (pageNumber) => {
      console.log("Page: ", pageNumber);
      search();
    };

    // 頁面搜索
    const search = (params = {}, fn = (rows) => rows) => {
      const { _begin } = params;
      console.log(proxy, fn);
      if (_begin >= 0) {
        current.value = _begin + 1;
      }
      const defaultParams = {
        pageNum: current.value,
        pageSize: pageSize.value,
        ...proxy.$props.searchParams,
      };
      spinning.value = true;
      return proxy.axios
        .get(proxy.$props.serverId, {
          params: { ...defaultParams },
        })
        .then((response) => {
          if (response.data.status == 1) {
            if (proxy.$props.pageable) {
              total.value = response.data.pageInfo.totalCount;
            }
            dataSource.value = response.data.data;
          } else {
            message.error("操作失敗");
          }
        })
        .catch((error) => {
          console.log(error);
          message.error("接口異常");
        })
        .finally(() => {
          spinning.value = false;
        });
    };

    //展開與收起
    const showmore = ref(true);
    const toogleShow = () => {
      showmore.value = !showmore.value;
    };
    watch(pageSize, () => {
      search();
    });
    return {
      onShowSizeChange,
      dataSource,
      onChange,
      locale: zhCN,
      total,
      pageSize,
      current,
      search,
      spinning,
      resetFields,
      showmore,
      toogleShow,
    };
  },
});
</script>
<style lang="scss">
.c-data-table {
  .ant-table-thead > tr > th {
    background-color: #1890ff;
    line-height: 14px;
    color: #fff;
    border-bottom: 5px solid #fff;
  }

  .ant-table-tbody > tr > td {
    line-height: 5px;
    background-color: #f0f8ff;
    border-bottom: 5px solid #fff;
  }

  .ant-table-tbody
    > tr:hover:not(.ant-table-expanded-row):not(.ant-table-row-selected)
    > td {
    background-color: #ddebff !important;
  }
  .ant-pagination {
    margin-top: 1em;
  }
  .dt-search {
    box-sizing: border-box;
    padding: 8px 0 5px;
    .dt-search-form-inline {
      .ant-form-item {
        margin-bottom: 5px;
        &:last-child {
          margin-right: 0;
        }
      }
    }
    .formSearchLookMore {
      display: inline-block;
      position: relative;
      top: 4px;
    }
    .formSearchLittle {
      display: inline-block;
      margin-right: 20px;
    }
  }
  .dt-search {
    .ant-btn {
      min-width: 79px;
      margin-right: 10px;
      font-size: 14px;
    }
  }
  .ant-card-body {
    padding: 0px 24px 24px;
  }
  .btnbox {
    a {
      margin-right: 20px;
    }
  }
}
.dt-toolbar {
  box-sizing: border-box;
  padding: 8px 0;
  .ant-btn {
    min-width: 79px;
    margin-right: 10px;
    font-size: 13px;
  }
}
</style>

下邊我們看一下這個組件的使用方法
使用的時候請放開所有注釋

<!---本頁面注釋建議不要隨便動6估M莨觥!Fよ怠V墼!6竦肌=摺!!0钚埂I局稀!--->
<template>
  <div>
    <a-spin :spinning="loading">
      <c-data-table
        :columns="columns"
        :title="'用戶管理'"
        :searchParams="searchParams"
        ref="RefChilde"
        serverId="/apis/users"
        resultKey="data"
      >
        <template v-slot:search>
          <a-form-item label="用戶名">
            <a-input v-model:value="searchParams.username" />
          </a-form-item>
          <a-form-item label="部門">
            <a-input v-model:value="searchParams.deptName" />
          </a-form-item>
          <span class="formSearchLookMore">
            <a-button type="primary" class="search" @click="gosearch()">
              <template #icon>
                <SearchOutlined />
                查詢
              </template>
            </a-button>
            <a-button type="default" class="reset" @click="reset()">
              <template #icon>
                <ReloadOutlined />
                重置
              </template>
            </a-button>
            <!-- <a href="javascript:;" @click="toogleShowMore">展開<DownOutlined /></a> -->
          </span>
        </template>
        <!-- <template v-slot:searchmore>
        <a-form-item label="用戶名:">
          <a-input v-model:value="searchParams.username" />
        </a-form-item>
        <a-form-item label="密碼:">
          <a-input v-model:value="searchParams.deptName" />
        </a-form-item>
        <a-form-item label="用戶名:">
          <a-input v-model:value="searchParams.name1" />
        </a-form-item>
        <a-form-item label="密碼:">
          <a-input v-model:value="searchParams.pass1" />
        </a-form-item>
        <a-form-item label="用戶名:">
          <a-input v-model:value="searchParams.name2" />
        </a-form-item>
        <a-form-item label="密碼:">
          <a-input v-model:value="searchParams.pass2" />
        </a-form-item>
        <a-button type="primary" class="search" @click="gosearch()">
          <template #icon>
            <SearchOutlined />
            查詢
          </template>
        </a-button>
        <a-button type="default" class="reset" @click="resetFields">
          <template #icon>
            <ReloadOutlined />
            重置
          </template>
        </a-button>
        <a href="javascript:;" @click="toogleShowMore">收起<UpOutlined /></a>
      </template> -->
      </c-data-table>
    </a-spin>
  </div>
</template>
<script>
import {
  defineComponent,
  reactive,
  ref,
  getCurrentInstance,
  onMounted,
} from "vue";
import zhCN from "ant-design-vue/lib/locale-provider/zh_CN";
import { SearchOutlined, ReloadOutlined } from "@ant-design/icons-vue";
import { Modal, message } from "ant-design-vue";
import CDataTable from "../../../../commons/CDataTable";
import { fmtDict } from "../../../../commons/common";
import { gender, status } from "../../../../commons/publicArray";
import _ from "lodash";
export default defineComponent({
  components: {
    [CDataTable.name]: CDataTable,
    SearchOutlined,
    ReloadOutlined,
  },
  setup() {
    const columns = [
      {
        title: "用戶名",
        dataIndex: "username",
        key: "username",
      },
      {
        title: "性別",
        dataIndex: "gender",
        customRender: ({ text }) => {
          return <div>{fmtDict(text, gender)}</div>;
        },
      },
      {
        title: "手機號",
        dataIndex: "phone",
        key: "phone",
        ellipsis: true,
      },
      {
        title: "郵箱",
        dataIndex: "email",
        key: "email",
        ellipsis: true,
      },
      {
        title: "部門",
        dataIndex: "deptName",
        key: "deptName",
        ellipsis: true,
      },
      {
        title: "創(chuàng)建時間",
        dataIndex: "createTime",
        key: "createTime",
        ellipsis: true,
      },
      {
        title: "更新時間",
        dataIndex: "updateTime",
        key: "updateTime",
        ellipsis: true,
      },
      {
        title: "用戶狀態(tài)",
        dataIndex: "status",
        customRender: ({ text }) => {
          return <div>{fmtDict(text, status)}</div>;
        },
      },
      {
        title: "操作",
        width: "220px",
        customRender: ({ text, index }) => {
          if (text.status == "FROZEN") {
            return (
              <div class="btnbox">
                <a href="javascript:;" onClick={() => lookMore(text, index)}>
                  角色分配
                </a>
                <a href="javascript:;" onClick={() => unblock(text, index)}>
                  解凍
                </a>
              </div>
            );
          } else {
            return (
              <div class="btnbox">
                <a href="javascript:;" onClick={() => lookMore(text, index)}>
                  角色分配
                </a>
                <a href="javascript:;" onClick={() => block(text, index)}>
                  凍結(jié)
                </a>
              </div>
            );
          }
        },
      },
    ];
    let { proxy } = getCurrentInstance();
    //搜索數(shù)據(jù)
    const searchParams = reactive({
      username: "",
      deptName: "",
    });
    //loading加載
    const loading = ref(false);
    //彈框顯示與隱藏
    const visible = ref(false);
    const RefChilde = ref(null);
    //角色彈框title
    const title = ref("");
    //用于存儲userid
    const userId = ref();
    //用戶分配角色
    const targetKeys = ref([]);
    const selectedKeys = ref([]);
    const mockData = ref([]);
    const handleChange = (nextTargetKeys, direction, moveKeys) => {
      console.log("nextTargetKeys", nextTargetKeys);
      console.log("direction: ", direction);
      console.log("moveKeys: ", moveKeys);
      if (direction == "right") {
        //綁定角色
        proxy.axios
          .post("/apis/users/" + userId.value + "/bindRole", {
            roleIds: moveKeys,
          })
          .then((res) => {
            if (res.data.status == 1) {
              message.success("分配成功");
              targetKeys.value = nextTargetKeys;
            } else {
              message.error("分配失敗");
            }
          });
      } else {
        //移出角色
        proxy.axios
          .post("/apis/users/" + userId.value + "/removeRole", {
            roleIds: moveKeys,
          })
          .then((res) => {
            if (res.data.status == 1) {
              message.success("移除成功");
              targetKeys.value = nextTargetKeys;
            } else {
              message.error("移除失敗");
            }
          });
      }
    };

    const handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
      selectedKeys.value = [...sourceSelectedKeys, ...targetSelectedKeys];
    };

    //調(diào)用子組件的查詢方法
    const gosearch = () => {
      RefChilde.value.search({ _fromBar: true, _begin: 0 });
    };
    //掉用子組件的重置方法
    const reset = () => {
      RefChilde.value.resetFields();
    };
    //給用戶綁定角色拉起彈框
    const lookMore = (text, index) => {
      console.log(text, index);
      loading.value = true;
      title.value = "為 " + text.username + " 賦予角色";
      userId.value = text.id;
      proxy.axios
        .get("/apis/users/" + text.id + "/roles")
        .then((res) => {
          mockData.value = res.data.data.assigned.concat(
            res.data.data.available
          );
          _.forEach(res.data.data.assigned, (item) => {
            targetKeys.value.push(item.id);
          });
          visible.value = true;
        })
        .catch(() => {
          message.error("獲取失敗");
        })
        .finally(() => {
          loading.value = false;
        });
    };
    //凍結(jié)
    const block = (item, index) => {
      console.log(item, index);
      Modal.warning({
        title: "請確認是否對用戶" + item.name + "進行凍結(jié)操作",
        okText: "確認", // 設(shè)置按鈕內(nèi)容顺囊,默認為 OK
        onOk: () => {
          // 點擊確認后的回調(diào)
          proxy.axios
            .patch("/apis/users/" + item.id + "/freeze")
            .then((res) => {
              if (res.data.status == 1) {
                message.success("凍結(jié)成功");
                gosearch();
              } else {
                message.error("凍結(jié)失敗");
              }
            })
            .catch((error) => {
              message.error(error);
            });
        },
      });
    };
    //解凍
    const unblock = (item, index) => {
      console.log(item, index);
      Modal.warning({
        title: "請確認是否對用戶" + item.name + "進行解凍操作",
        okText: "確認", // 設(shè)置按鈕內(nèi)容肌索,默認為 OK
        onOk: () => {
          // 點擊確認后的回調(diào)
          proxy.axios
            .patch("/apis/users/" + item.id + "/unfreeze")
            .then((res) => {
              if (res.data.status == 1) {
                message.success("解凍成功");
                gosearch();
              } else {
                message.error("解凍失敗");
              }
            })
            .catch((error) => {
              message.error(error);
            });
        },
      });
    };
    //展開與收起切換
    // const toogleShowMore = () => {
    //   RefChilde.value.toogleShow();
    // };
    onMounted(() => {
      gosearch();
    });
    return {
      columns,
      lookMore,
      searchParams,
      gosearch,
      reset,
      RefChilde,
      // toogleShowMore,
      block,
      unblock,
      loading,
      visible,
      title,

      mockData,
      targetKeys,
      selectedKeys,
      handleChange,
      handleSelectChange,
      locale: zhCN,
    };
  },
});
</script>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市特碳,隨后出現(xiàn)的幾起案子诚亚,更是在濱河造成了極大的恐慌,老刑警劉巖午乓,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件站宗,死亡現(xiàn)場離奇詭異,居然都是意外死亡益愈,警方通過查閱死者的電腦和手機梢灭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒸其,“玉大人敏释,你說我怎么就攤上這事∶” “怎么了钥顽?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長靠汁。 經(jīng)常有香客問我蜂大,道長,這世上最難降的妖魔是什么膀曾? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任县爬,我火速辦了婚禮,結(jié)果婚禮上添谊,老公的妹妹穿的比我還像新娘财喳。我一直安慰自己,他們只是感情好斩狱,可當(dāng)我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布耳高。 她就那樣靜靜地躺著,像睡著了一般所踊。 火紅的嫁衣襯著肌膚如雪泌枪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天秕岛,我揣著相機與錄音碌燕,去河邊找鬼误证。 笑死,一個胖子當(dāng)著我的面吹牛修壕,可吹牛的內(nèi)容都是我干的愈捅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼慈鸠,長吁一口氣:“原來是場噩夢啊……” “哼蓝谨!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起青团,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤譬巫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后督笆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芦昔,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年娃肿,在試婚紗的時候發(fā)現(xiàn)自己被綠了烟零。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡咸作,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宵睦,到底是詐尸還是另有隱情记罚,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布壳嚎,位于F島的核電站桐智,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏烟馅。R本人自食惡果不足惜说庭,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望郑趁。 院中可真熱鬧刊驴,春花似錦、人聲如沸寡润。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梭纹。三九已至躲惰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間变抽,已是汗流浹背础拨。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工氮块, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诡宗。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓滔蝉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親僚焦。 傳聞我的和親對象是個殘疾皇子锰提,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容