vue3+element plus搭建后台管理系统

8 篇文章 0 订阅
4 篇文章 0 订阅

项目地址:https://gitee.com/mangoxin1/mango-fd
演示地址: https://mangoxin1.gitee.io/mango-fd

采用vue3和vite2和element plus搭建后台管理系统

内部封装多个组件 支持页面关闭 支持iframe内嵌跳转 新窗口打开 全屏打开当前组件

封装组件 表格crud

<script setup>
import { reactive, ref, toRaw } from "vue";
import { get } from "lodash";
import { getfrom } from "./minxin/index.js";
import mangoempty from "@/components/mango_empty/index.vue";
import pagina from "./pagination.vue";
const props = defineProps({
  listConfig: Object,
  tableData: Array,
  style: Object,
});
const multipleTableRef = ref();
let myform = ref();
let tabBox = ref();
console.log(tabBox)
debugger
const multipleSelection = [];
const emit = defineEmits(["handleAction", "pagination-change"]);
const handleRowClick = (row) => {
  multipleTableRef.value.toggleRowSelection(row, undefined);
};
const handleSelectionChange = (val) => {
  multipleSelection.value = val;
};
const handleAction = (command, position, selection, data) => {
  emit(
    "handleAction",
    command,
    position,
    selection,
    toRaw(multipleSelection.value)
  );
};
const getfromdata = () => {
  return getfrom(props);
};
/**
 * 清除输入框
 */
const clearfromdata = () => {
  let formdata = props.listConfig.searchForm.forms;
  formdata.map((item) => {
    item.modelValue = "";
  });
};
const paginationchange = (page) => {
  emit("pagination-change", page);
};
defineExpose({
  getfromdata,
  clearfromdata,
});
</script>
<template>
  <div class="mango_crud">
    <div class="fromdata" v-if="props?.listConfig?.searchForm?.forms">
      <el-card>
        <el-form
          ref="myform"
          :inline="true"
          :model="props.listConfig.searchForm.forms"
          class="demo-form-inline"
        >
          <el-form-item
            v-for="(item, i) in props.listConfig.searchForm.forms"
            :key="i"
            :label="item.label"
            :prop="item.prop"
          >
            <el-input
              v-if="item.fieldType === 'input' || item.fieldType === undefined"
              v-model="item['modelValue']"
              :placeholder="`请输入${item.label}`"
            />
            <el-select
              v-else-if="item.fieldType === 'select'"
              v-model="item.modelValue"
              :disabled="item.disabled"
              :placeholder="item.placeholder ? item.placeholder : '请选择'"
              clearable
            >
              <el-option
                v-for="(option, optionIndex) in item.options"
                :key="optionIndex + '_local'"
                :value="
                  typeof option === 'object'
                    ? option[item.valueKey || 'value']
                    : option
                "
                :label="
                  typeof option === 'object'
                    ? option[item.labelKey || 'label']
                    : option
                "
              />
            </el-select>
            <!-- 日期-->
            <el-date-picker
              v-else-if="item.fieldType === 'date'"
              v-model="item.modelValue"
              :placeholder="item.placeholder"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :editable="item.editable"
              :picker-options="item.pickerOptions || {}"
              :type="item.dateType || 'date'"
            />
            <!-- 日期范围-->
            <el-date-picker
              v-else-if="item.fieldType === 'daterange'"
              v-model="item.modelValue"
              :disabled="item.disabled"
              :readonly="item.readonly"
              :editable="item.editable"
              :placeholder="item.placeholder ? item.placeholder : '请选择'"
              :start-placeholder="
                item.startPlaceholder ? item.startPlaceholder : '请选择'
              "
              :end-placeholder="
                item.endPlaceholder ? item.endPlaceholder : '请选择'
              "
              :picker-options="item.pickerOptions || {}"
              type="daterange"
            />
            <template v-else-if="item.fieldType === 'slot'">
              <slot :name="item.slotName" :item="item" />
            </template>
          </el-form-item>
          <el-form-item>
            <el-button
              v-for="(btn, i) in props.listConfig.searchForm.toolbars"
              :key="i"
              :type="btn.type ? btn.type : 'primary'"
              @click="handleAction(btn.key)"
            >
              <span v-if="btn.key == 'search'">搜索</span>
              <span v-else>{{ btn.label }}</span>
            </el-button>
          </el-form-item>
        </el-form>
      </el-card>
    </div>
    <div class="tabledata">
      <el-card :style="props.style">
        <el-form>
          <el-form-item v-if="props?.listConfig?.operatebtn">
            <el-button
              v-for="(btn, i) in props.listConfig.operatebtn"
              :key="i"
              :type="btn.type ? btn.type : 'primary'"
              @click="handleAction(btn.key)"
            >
              <span v-if="btn.key == 'search'">搜索</span>
              <span v-else>{{ btn.label }}</span>
            </el-button>
          </el-form-item>
        </el-form>

       <div class="tabBox" ref="tabBox">
          <el-table
          ref="multipleTableRef"
          :data="props.tableData"
          style="width: 100%"
          @selection-change="handleSelectionChange"
          @row-click="handleRowClick"
        >
          <template #empty>
            <mangoempty />
          </template>
          <el-table-column v-if="props.listConfig.showindex" type="index" />
          <el-table-column
            v-if="props.listConfig.showselection"
            type="selection"
            width="55"
          />
          <el-table-column
            v-for="(o, i) in props.listConfig.columns"
            :property="o.property"
            :label="o.label"
            :key="i"
            :formatter="o.formatter"
          >
            <template #default="scope">
              <span v-if="o.slotName">
                <slot
                  :name="o.slotName"
                  :row="scope.row"
                  :value="scope.row[o.property]"
                  :column="o"
                  :scope="scope"
                />
              </span>
              <template v-else-if="o.formatter">
                {{
                  o.formatter
                    ? o.formatter(
                        scope.row,
                        scope,
                        get(scope.row, o.prop),
                        scope
                      )
                    : get(scope.row, o.prop)
                }}
              </template>
              <span v-else>
                {{ scope.row[o.property] }}
              </span>
            </template>
          </el-table-column>
        </el-table>
        
        <!-- :style="{width:tabBox}" -->
        <pagina
          v-if="props.listConfig?.pagination"
          @pagination-change="paginationchange"
          :pagination="props.listConfig.pagination"
        />
       </div>
      </el-card>
    </div>
  </div>
</template>

<style lang="scss">
.mango_crud {
  padding: 10px;
  height: 95%;
     .fromdata {
      margin-bottom: 10px;
    }
    .el-pagination{
          position: absolute;
    bottom: 5px;
    width: 96%;
    }
  .tabledata {
    height: 100%;
    .el-card {
      height: 100%;
      position: relative;
      .el-card__body {
        height: 100%;
      }
      .tabBox{
        border: 1px solid #ebeef5;
            height: 100%;
      }
    }
 
    .el-table--fit {
      // height: 60%;
      margin-bottom: 50px;
      // border: 1px solid #ebeef5;
    }
    .el-table__inner-wrapper::before {
      display: none;
    }
  }
}
</style>

封装分页器

<template>
  <el-pagination
    :current-page="currentPage.value"
    :page-size="pageSize.value"
    :total="pagination['totalKey']"
    v-bind="paginationOptions"
    @size-change="handlePaginationSizeChange"
    @current-change="handlePaginationCurrentChange"
    @prev-click="handlePaginationPrevClick"
    @next-click="handlePaginationNextClick"
  >
    <template #default>
      <span class="el-pagination__total">{{ pageInfo }}</span>
    </template>
  </el-pagination>
</template>
<script setup>
import {  computed, reactive,watch } from "vue";
const emit = defineEmits(["pagination-change"]);
const props = defineProps({
  pagination: Object,
  paginationOptions: {
    type: Object,
    default: () => {
      return {
        pagerCount: 5,
        pageSizes: [2,10, 20, 50, 100],
        layout: "prev, pager, next, jumper,sizes, ->,slot",
      };
    },
  },
  pageCountKey: {
    // 总页数
    type: String,
    default: "totalPages",
  },
});

const pagination = reactive(props.pagination);
const paginationOptions = reactive(props.paginationOptions);
const pageCountKey = reactive(props.pageCountKey);
const pageInfo = computed(() => {
  let currentPage = pagination.page;
  let pageSize = pagination.limit;
  const total = pagination["totalKey"];
  if (total && total > 0) {
    const start = (currentPage - 1) * pageSize + 1;
    let end = currentPage * pageSize;
    if (total <= end) {
      end = total;
    }
    return `第${start}到第${end}条 共${total}条`;
  } else {
    return "";
  }
});
const pageSize = computed(() => {
  return pagination["limit"] || 20;
});
const currentPage = computed(() => {
  return pagination["page"] || 1;
});
/**
 * @description 每页条数改变
 */
const handlePaginationSizeChange = (pageSize) => {
  handlePaginationChange({
    currentPage: 1,
    pageSize: pageSize,
  });
};
/**
 * @description 当前页码改变
 */
const handlePaginationCurrentChange = (currentPage) => {
  handlePaginationChange({
    pageSize: pagination["limit"],
    currentPage: currentPage,
  });
};
/**
 * @description 上一页
 */
const handlePaginationPrevClick = (currentPage) => {
  handlePaginationChange({
    pageSize: pagination["limit"],
    currentPage: currentPage,
  });
};
/**
 * @description 下一页
 */
const handlePaginationNextClick = (currentPage) => {
  handlePaginationChange({
    pageSize: pagination["limit"],
    currentPage: currentPage,
  });
};
const handlePaginationChange = ({ pageSize, currentPage }) => {
  if (pageSize === pagination["limit"] && currentPage === pagination["page"]) {
    return;
  }
  //解决分页改变触发页码改变 使得该方法触发俩边
  emit("pagination-change", {
    limit: pageSize || pagination["limit"],
    page: currentPage || pagination["page"],
  });
};
</script>
<style lang="scss">
.el-pagination {
  height: 50px;
  border-top: 1px solid rgb(235, 238, 245);
}
</style>

封装弹出框

import { ElMessage } from 'element-plus'
import util from './util'
const action = {
    /**
  * 操作警告提示
  */
    warning: function (message, showClose=true) {
        ElMessage({
            message: message,
            showClose: showClose,
            type: 'warning',
        })
    },
    /**
 * 操作成功提示
 */
    success: function (message, showClose=true) {
        ElMessage({
            message: message,
            showClose: showClose,
            type: 'success',
        })
    },
    error: function (message, showClose=true) {
        ElMessage({
            message: message,
            showClose: showClose,
            type: 'error',
        })
    },
    grouping: function (message, type,showClose=true) {
        ElMessage({
            message: message,
            grouping: true,
            showClose: showClose,
            type: type,
        })
    },
    /**
 * 下载
 */
    download: function (data, fileName, responseType = 'application/octet-stream') {
        const blob = data instanceof Blob ? data : new Blob([data], { type: responseType })
        if ('download' in document.createElement('a')) { // 非IE下载
            const url = window.URL.createObjectURL(blob)
            const link = document.createElement('a')
            link.style.display = 'none'
            link.href = url
            link.setAttribute('download', fileName)
            document.body.appendChild(link)
            link.click()
            window.URL.revokeObjectURL(link.href)
            document.body.removeChild(link)
        } else { // IE10+下载
            navigator.msSaveBlob(blob, fileName)
        }
    },

    /**
   * 导出文件
   */
    exportFile: function (data, fileName, responseType = 'application/octet-stream') {
        this.download(data, fileName, responseType)
    }
}
export default action
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mangoxin1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值