Vue3中使用element-plus封装表单列表组件,一行代码实现一个页面

1。QhTable子组件

<template>
  <div class="qh-base-pages" v-loading="loading">
    <div class="qh-table-header" v-if="defaultForm.length > 0">
      <div class="l">
        <slot name="left"></slot>
      </div>
      <div class="default-form">
        <form>
          <div class="cell" v-for="(item, index) in defaultForm" :key="index">
            <Input
              v-if="item.type == 'input'"
              :item="item"
              :picon="item.picon == 'search' ? Search : ''"
              @returnItem="returnItem"
            />
            <SelectList
              v-if="item.type == 'select'"
              :item="item"
              @returnItem="returnItem"
            />
          </div>
          <div class="cell">
            <el-button @click="exportExcel">导出</el-button>
          </div>
          <div class="cell">
            <el-button @click="handleReset">重置</el-button>
          </div>
        </form>
      </div>
    </div>
    <div class="qh-table">
      <div class="qh-table-wrapper">
        <el-table
          :data="data?.list"
          stripe
          :height="data.height"
          :max-height="data.height || '72vh'"
          :show-overflow-tooltip="{ placement: 'left-end' }"
          :tooltip-options="{
            effect: 'dark',
            placement: 'top',
            showArrow: true,
          }"
          :row-class-name="tableRowClassName"
        >
          <template v-slot:empty>
            <div class="qh-no-data">
              <el-empty description="暂无数据" />
            </div>
          </template>
          <!-- 循环列表数据 -->
          <el-table-column
            v-for="(col, index) in data?.cols"
            :key="index"
            :prop="col.prop"
            :label="col.label"
            :width="col.width"
            :fixed="col.fixed"
            :align="col.align || 'center'"
            :sortable="col.sortable"
          >
            <!-- 自定义头部内容 -->
            <template #header>
              <div v-if="col.headerSlot" class="sub_header_tr_cell">
                {{ col.label }}
                <div class="sub_header_tr_title">
                  {{ col.headerSlot.title }}
                </div>
              </div>
            </template>

            <template #default="scope">
              <!-- // col格子按钮  tools -->
              <div v-if="col.tools">
                <div v-if="col.tools.name">
                  <template v-if="col.tools.isProp">
                    <span
                      v-if="col.tools.chind[scope.row[col.tools.isProp]] == '-'"
                      >{{ col.tools.chind[scope.row[col.tools.isProp]] }}</span
                    >
                    <span
                      v-else
                      class="link"
                      @click="openRowDialog(col.tools.prop, scope.row)"
                      >{{ col.tools.chind[scope.row[col.tools.isProp]] }}</span
                    >
                  </template>
                  <span
                    v-else
                    class="link"
                    @click="
                      openRowDialog(
                        col.tools.prop,
                        scope.row[col.tools.prop]
                          ? scope.row[col.tools.prop]
                          : scope.row
                      )
                    "
                    >{{ col.tools.name }}</span
                  >
                </div>
                <span
                  v-else
                  class="link"
                  @click="openRowDialog(scope.row, col.prop)"
                  >{{ scope.row[col.prop] }}</span
                >
              </div>
              <!-- // 是否开启switch切换按钮 -->
              <div v-if="col.switch">
                <el-switch
                  v-model="scope.row[col.prop]"
                  @change="changeSwitch(scope.row[col.prop], scope.row)"
                />
              </div>
              <!-- // 展示图片 isPic isVideo -->
              <div
                v-if="scope.row[col.prop] && (col.isPic || col.isVideo)"
                class="isPic"
                :class="{ isVideo: 'isVideo' }"
              >
                <el-icon
                  v-if="col.isVideo"
                  @click="openAvatarPopup(scope.row[col.prop], 'video')"
                  ><CaretRight
                /></el-icon>
                <el-avatar
                  shape="square"
                  :size="36"
                  fit="cover"
                  @click="openAvatarPopup(scope.row[col.prop])"
                  :src="scope.row[col.prop]"
                />
              </div>
              <!-- // 多颜色展示 colors -->
              <div v-if="col.colors">
                <span
                  v-for="colorEle in col.colors"
                  :key="colorEle.value"
                  :style="{
                    color:
                      colorEle.value == scope.row[col.prop] && colorEle.color,
                  }"
                >
                  {{
                    colorEle.value === scope.row[col.prop] ? colorEle.name : ""
                  }}
                </span>
              </div>
              <!-- // 单位 units  -->
              <div v-if="col.units" class="units">
                <template v-if="scope.row[col.prop] > 0">
                  <span v-if="col.units.dir == 'left'">{{
                    col.units.name
                  }}</span
                  >{{
                    col.units.value
                      ? (scope.row[col.prop] / col.units.value).toFixed(2)
                      : scope.row[col.prop]
                  }}<span v-if="col.units.dir == 'right'">{{
                    col.units.prop ? scope.row[col.units.prop] : col.units.name
                  }}</span>
                </template>
                <template v-else>-</template>
              </div>
              <!-- // 换算  mat -->
              <div class="mat" v-if="col.mat && scope.row[col.prop] > '0'">
                <span v-if="col.mat.dir == 'left'">{{ col.mat.name }}</span
                >{{ (scope.row[col.prop] / col.mat.value).toFixed(2)
                }}<span v-if="col.mat.dir == 'right'">{{ col.mat.name }}</span>
              </div>

              <!-- // 多字段显示 -->
              <div v-if="col.propElse">
                <div class="units">
                  {{ scope.row[col.prop] ? scope.row[col.prop] : "-" }}
                </div>
                <div
                  class="mat"
                  style="color: #273c62"
                  v-if="scope.row[col.propElse]"
                >
                  {{ scope.row[col.propElse] || "-" }}
                </div>
              </div>

              <!-- // 默认展示 base -->
              <span
                v-if="
                  !col.tools &&
                  !col.isPic &&
                  !col.isVideo &&
                  !col.colors &&
                  !col.units &&
                  !col.switch &&
                  !col.propElse
                "
              >
                {{ scope.row[col.prop] === "" ? "-" : scope.row[col.prop] }}
              </span>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="qh-pagination">
        <div class="total">
          当前共有 <span class="num">{{ props.data.total || "0" }}</span> 条数据
        </div>
        <el-pagination
          v-model:current-page="currentPage"
          background
          v-model:page-size="pageSize"
          :page-sizes="[20, 50, 100, 200]"
          layout="sizes, prev,  pager, next"
          :total="props.data.total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </div>
    <QhPopup
      :visible="avatarVisible"
      :data="popupData"
      @close="closePopup"
    ></QhPopup>
  </div>
</template>

<script setup>
import { ref, reactive } from "vue";
import { post, get } from "@/utils/http";
import table2Excel from "js-table2excel";
import { Input, SelectList, QhPopup } from "@/components";
import { Search, CaretRight } from "@element-plus/icons-vue";
import { ElLoading } from "element-plus";
//给父组件上报状态
const emit = defineEmits([
  "updaTable",
  "updaDefaultForm",
  "openRowDialog",
  "updataPostList",
]);
const props = defineProps({
  data: {
    type: Object,
    default: {},
  },
  loading: {
    type: Boolean,
    default: false,
  },
  defaultForm: {
    type: Array,
    default: [],
  },
  Sinit: {
    type: Object,
    default: {},
  },
  excelInit: {
    type: Object,
    default: {},
  },
});

const Tdata = props?.data;
const Sinit = props?.Sinit;
const excelInit = props?.excelInit;

// 重置表单
const handleReset = () => {
  const defaultForm = props?.defaultForm;
  for (const key in defaultForm) {
    defaultForm[key].value = "";
  }
  emit("updaDefaultForm", defaultForm);
};

// 点击cel链接
const openRowDialog = (rowVal, prop) => {
  emit("openRowDialog", rowVal, prop);
};
// changeSwitch切换
const changeSwitch = (v, row) => {
  emit("updataPostList", v, row);
};

// 当前页码
const currentPage = ref(Sinit.page || 1);
const pageSize = ref(Sinit.size || 20);

const returnItem = (data) => {
  emit("updaDefaultForm", props?.defaultForm);
};

// 页码改变
const handleSizeChange = (val) => {
  Sinit.size = val;
  emit("updaTable", Sinit);
};
const handleCurrentChange = (val) => {
  Sinit.page = val;
  emit("updaTable", Sinit);
};

// 导出exel表格
const exportExcel = () => {
  const loading = ElLoading.service({
    lock: true,
    text: "导出中请稍等...",
    background: "rgba(0, 0, 0, 0.6)",
  });
  post(excelInit.apiUrl, excelInit.data).then((res) => {
    if (res.code == 0) {
      const lists = res?.data?.list;
      let list = JSON.stringify(lists); // 用定义的数据
      list = formatExportData(JSON.parse(list));
      table2Excel(
        excelInit.exportCols,
        list,
        excelInit.name + new Date().getTime()
      );
      loading.close();
    } else {
      loading.close();
    }
  });
};
const formatExportData = (list) => {
  // 处理特殊字段
  list.forEach((item) => {
    excelInit.formatColumns.forEach((i) => {
      item[i.prop] = i.option[item[i.prop]];
    });

    for (let key in item) {
      if (!item[key] && item[key] == null) {
        item[key] = "";
      }
    }
  });
  return list;
};
</script>

<style lang="scss" scoped>
.c3 {
  color: rgba(39, 60, 98, 0.5);
}
.qh-table {
  position: relative;
  :deep(.el-table th .cell) {
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .link {
    color: #0084ff;
    text-decoration-line: underline;
    cursor: pointer;
  }
}
.default-form form {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
:deep(.el-popper.is-dark) {
  max-width: 300px;
}
</style>

 

2。页面组件(list.vue)

<template>
  <QhTable
    :defaultForm="defaultFormData"
    :Sinit="searchInit"
    :loading="loading"
    :data="defaultData"
    :excelInit="excelInit"
    @updaTable="getUpdaTable"
    @updaDefaultForm="updaDefaultForm"
  />
</template>
<script setup>
import { ref, reactive } from "vue";
import { QhTable } from "@/components";
</script>
<style lang="scss" scoped></style>

 

参数解释:

 
loading
表单加载中
const loading = ref(false);
 
Sinit
搜索字段 (Object)          
const searchInit = ref({
    page: 1,   // 页码
    size: 20,  // 数量
    w_time: defaultFormData[0].value,  //搜索字段1
    agent_id: defaultFormData[1].value,  //搜索字段2
  });
 
defaultFormData
 搜索配置 (数组)
const defaultFormData = reactive([
    {
      type: "select",               //下拉选择
      label: "时间周期",            //名称
      name: "w_time",            // 字段
      value: "",               // 默认值
      placeholder: "全部",          
      options: cofigStore.timePeriod,     // 下拉数据配置
    },
    
{
      type: "input",             // 输入框
      placeholder: "请输入用户ID",
      name: "user_id",                                // 字段
      value: "",
      picon: "search",  
      width: 210,
    },
  ]);
 
defaultData
 表格配置  (对象)
const defaultData = reactive({
    total: 0,               // 数据总数
    cols: cols,             // 表格cols
    list: [],              // 接口数据列表
  });
cols =[
{ prop: "regions", label: "国家地区", width: 150 },
]
 
excelInit
 导出excel配置
const excelInit = ref({
    apiUrl: "/v1/product_data/pay_data",        //导出接口api
    name: `name-`,      // 导出文档名称+时间戳
    exportCols: exportColsConfig,
    formatColumns: formatColumns,
    data: {},
  });
exportColsConfig=[  //表单配置
{ key: "stats_date", title: "统计日期", type: "text" },
]
// 特殊字符处理
formatColumns=[
{
    prop: "pay_status",
    option: {
      1: "支付中",
      2: "支付成功",
      3: "支付失败",
    },
  },
]
getUpdaTable
分页更新
const getUpdaTable = (data) => {
    searchInit.value = data;
    excelInit.value.data = { ...searchInit.value, export: 1 };
    getTableList(searchInit.value);
  };
 
updaDefaultForm
搜索字符更新
// 获取顶部输入框数据
  const updaDefaultForm = (data) => {
    for (const item of data) {
      searchInit.value[item.name] = item.value;
    }
    excelInit.value.data = { ...searchInit.value, export: 1 };
    getTableList(searchInit.value);
  };
 

 

posted @ 2024-10-23 15:42  蜗牛snail  阅读(37)  评论(0编辑  收藏  举报
蜗牛前端 蜗牛文学