vue3+elmentPlus 后台系统数据增删改查模板
列表页面
/index.vue
<template>
<div v-loading.fullscreen.lock="loading">
<div class="app-container">
<el-form :model="searchFrom">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="名称" prop="name">
<el-input v-model="searchFrom.name" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="类型:">
<el-select v-model="searchFrom.iType" clearable filterable>
<el-option v-for="item in typeOptions" :key="item.value" :label="item.name" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="状态:">
<el-select v-model="searchFrom.status" clearable filterable>
<el-option v-for="item in statusOptions" :key="item.value" :label="item.name" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-bottom: 20px">
<el-col :span="24" class="text-center">
<el-button @click="handleReset">重置</el-button>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="success" @click="handleAdd">新建</el-button>
</el-col>
</el-row>
</el-form>
<div class="page-main">
<el-table
:data="tableData"
border
style="width: 100%"
@select="selectChangeEvent"
@select-all="selectAllChangeEvent"
>
<el-table-column type="selection" width="60" label="全选" align="center" />
<el-table-column prop="name" label="名称" align="center"></el-table-column>
<el-table-column prop="iType" label="类型" align="center">
<template #default="scope">{{ formatterType(scope.row.iType) }}</template>
</el-table-column>
<el-table-column prop="course" label="课程" align="center">
<template #default="scope">{{ scope.row.course.text }}</template>
</el-table-column>
<el-table-column prop="status" label="状态" align="center">
<template #default="scope">{{ formatterStatus(scope.row.status) }}</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button size="small" type="primary" @click="handleEdit(scope.row)">修改</el-button>
<el-button size="small" type="primary" @click="seeDetails(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination">
<el-pagination
v-model:currentPage="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
<!-- 新建 修改 详情-->
<Edit
v-if="showDialog"
ref="RefSelectPolicies"
v-model:show="showDialog"
:permission="permission"
:row="currentRow"
@flushed="handleSearch"
>
</Edit>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUpdated, reactive, ref, watch, watchEffect } from "vue";
import { funcResetObj } from "/@/utils/index";
import Edit from "./edit.vue";
import { useRequest } from "@xus/vue-reuse";
import { ElMessage } from "element-plus";
import { confirmMessage, errorMessage, successMessage } from "/@/utils/message";
import { nextTick } from "process";
import deepcopy from 'deepcopy'
// 列表查询
const searchFrom = reactive({
name: "",
iType: "",
course: "",
status: "",
});
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const tableData = ref([]);
const currentRow = ref();
const loading = ref(false)
const relationshipOptions = ref([])
// 假数据
const tableData1 = [
{
name: "1",
iType: "2",
course: {text:'c',code:'3'},
status: 0,
},
]
const tableData2 = [
{
name: "11",
iType: "22",
course: {text:'cc',code:'33'},
status: 1,
},
]
const tableData3 = [
{
name: "111",
iType: "222",
course: {text:'ccc',code:'333'},
status: 0,
},
]
// 数据格式化,字典
const typeOptions = [
{
name:'类型1',
value:'1'
},
{
name:'类型2',
value:'2'
},
]
const statusOptions = [
{
name:'开启',
value:0
},
{
name:'关闭',
value:1
},
]
const formatterType = (val)=>{
console.log('formatterType',val);
return val+'!'
}
const formatterStatus = (val)=>{
console.log('formatterStatus',val);
return statusOptions.filter(item=>item.value===val)[0].name
}
// 勾选
const selectChangeEvent = (row)=>{
console.log('selectChangeEvent',row);
}
const selectAllChangeEvent = (all)=>{
console.log('selectAllChangeEvent',all);
}
// 请求数据
const getList = () => {
const req = {
...searchFrom,
pageNum: currentPage.value,
pageSize: pageSize.value,
};
// 请求接口,获取数据
total.value = 35
if(currentPage.value===1){
tableData.value = tableData1
}else if(currentPage.value===2){
tableData.value = tableData2
}else if(currentPage.value===3){
tableData.value = tableData3
}
};
// 查询
const handleSearch = () => {
currentPage.value = 1;
getList();
};
//重置按钮
const handleReset = () => {
funcResetObj(searchFrom);
currentPage.value = 1;
getList();
};
// 改变条数
const handleSizeChange = (val: number) => {
pageSize.value = val
getList();
};
// 改变页数
const handleCurrentChange = (val: number) => {
currentPage.value = val;
getList();
};
const permission = ref('')
const showDialog = ref(false)
// 新建
const handleAdd = ()=>{
permission.value = 'add'
showDialog.value = true;
}
// 修改
const handleEdit = async(obj) => {
currentRow.value = obj
permission.value = 'edit'
showDialog.value = true;
};
// 详情
const seeDetails = async(obj) => {
currentRow.value = obj
permission.value = 'look'
showDialog.value = true;
};
onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
.app-container{
margin: 10px;
padding: 20px;
font-size: 14px;
background-color: #fff;
border-radius: 5px;
.page-main{
margin-top:30px;
}
.text-center {
text-align: center;
}
.pagination {
display: flex;
justify-content: right;
margin-top: 30px;
}
}
</style>
新增/修改/详情页面
/add.vue
<template>
<el-dialog
v-model="props.show"
:title="title"
width="60%"
:before-close="close"
>
<el-form :model="form" :disabled="disabled" ref="formRef" :rules="rules" class="container" label-width="100px">
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="名称:" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="类型:" prop="iType">
<el-select v-model="form.iType" clearable filterable>
<el-option v-for="item in typeOptions" :key="item.value" :label="item.name" :value="item.value"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-bottom: 20px" v-if="permission!=='look'">
<el-col :span="24" class="text-center">
<el-button @click="cancel">取消</el-button>
<el-button type="primary" @click="confirm">提交</el-button>
</el-col>
</el-row>
</el-form>
</el-dialog>
</template>
<script lang="ts" setup>
import { reactive, watch, ref } from "vue";
import { useRequest } from "@xus/vue-reuse";
import { ElMessage, FormInstance, FormRules } from "element-plus";
const props = defineProps({
show: {
type: Boolean,
default: false,
},
row: {
type: Object,
default: null,
},
permission:{
type: String,
default:''
},
});
const emit = defineEmits(["update:show",'flushed']);
console.log("props", props);
// 弹框设置
const disabled = ref(true)
const title = ref('详情')
if(props.permission!=='look'){
disabled.value = false
if(props.permission==='add'){
title.value='新建'
}else{
title.value='修改'
}
}
// 表单设置
const form = reactive({
id:null,
name: "",
iType:""
});
const formRef = ref<FormInstance>()
const rules = reactive<FormRules>({
name: [
{ required: true, message: '请输入名字', trigger: 'blur' },
],
iType: [
{ required: true, message: '请选择类型', trigger: 'change' },
],
})
// 字典
interface IOption{
name:string
value:string
}
const typeOptions = ref([] as IOption[]);
typeOptions.value = [
{
name:'类型1',
value:'1'
},
{
name:'类型2',
value:'2'
},
]
// 修改/详情 数据反显
if (props.permission!=='add') {
form.name = props.row.name;
form.iType = props.row.iType;
console.log("form", form);
}
// 取消
const cancel = () => {
console.log("cancel");
emit("update:show");
};
// 确认
const confirm = () => {
console.log("confirm", form);
formRef.value?.validate().then(()=>{
// const data = {
// };
// if(props.permission=='add'){
// }else{
// data.id = props.row.id
// runPolicyEsimEdit(data)
// }
emit("update:show");
})
};
const close = () => {
console.log("close");
emit("update:show");
};
</script>
<style scoped>
.container{
margin: 0 20px;
}
.text-center {
text-align: center;
}
</style>
通用弹框组件
当弹框内容较多,或者弹框内逻辑比较复杂时,可以将弹框及弹框中的内容封装为一个组件,降低主页面的复杂度
/index.vue 中使用组件
<operateDialog v-if="showEditDialog" v-model:show="showEditDialog" :row="curRow" :title="dialogTitle" @refresh="refreshList"/>
/operateDialog.vue 弹框组件
<template>
<el-dialog
v-model="show"
:title="title"
width="30%"
:before-close="handleClose"
>
<span>xxx</span>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="confirm"> 确定 </el-button>
</span>
</template>
</el-dialog>
</template>
<script lang='ts' setup>
const props = defineProps({
show:{
type:Boolean,
default:false
},
title:{
type:String,
default:''
},
row: {
type: Object,
default: null,
},
})
const emits = defineEmits(['update:show','refresh'])
const handleClose = ()=>{
emits('update:show')
}
const confirm = ()=>{
emits('update:show')
// 操作成功 刷新列表
emits('refresh')
}
</script>
<style scoped>
</style>