vue3+element plus搭建后台管理系统
项目地址:https://gitee.com/mangoxin1/mango-fd采用vue3和vite2和element plus搭建后台管理系统内部封装多个组件 支持页面关闭 支持iframe内嵌跳转新窗口打开 全屏打开当前组件封装组件 表格crud<script setup>import { reactive, ref, toRaw } from "vue";import { g
·
项目地址: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
更多推荐
已为社区贡献4条内容
所有评论(0)