这段实例代码是使用 ElementPlus完成的 由代码生成器生成
包含了表单验证 添删改查 表格排序 字段筛选 JS端的打印与导出
望vue3开发人员 开发越来越顺 赚钱越来越多
由于使用了自动引用 所以没有import
看好的客观请点赞
<template>
<!-- 搜索 -->
<el-card>
<el-form :inline="true">
<el-form-item label="姓名">
<el-input v-model="Ms.searchForm.name" placeholder="请输入姓名" clearable/>
</el-form-item>
<el-form-item label="年龄">
<el-input-number v-model="Ms.searchForm.age" placeholder="请输入年龄" />
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="Ms.searchForm.email" placeholder="请输入邮箱" clearable/>
</el-form-item>
<el-form-item label="加入时间">
<el-date-picker v-model="Ms.searchForm.enterTime" type="datetimerange" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择" clearable range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间"/>
</el-form-item>
<el-form-item label="价格">
<el-input-number v-model="Ms.searchForm.price" placeholder="请输入价格" />
</el-form-item>
<el-form-item>
<el-button @click="searchData()" type="primary" icon="Search">查询</el-button>
<el-button @click="resetSearchData()">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card style="margin-top:15px">
<!-- 工具栏 -->
<el-button type="primary" @click="addOrUpdateHandle()" icon="CirclePlus">新增</el-button>
<el-button type="danger" :disabled="Ms.dataListSelections.length <= 0" @click="deleteConfirmHandle()" icon="Delete">批量删除</el-button>
<el-button type="success" :disabled="Ms.dataListSelections.length <= 0" @click="exportExcel" icon="Download">导出</el-button>
<el-button type="success" :disabled="Ms.dataListSelections.length <= 0" @click="printTable" icon="Printer">打印</el-button>
<el-button @click="getDataList()" icon="Refresh">刷新</el-button>
<el-dropdown :hide-on-click="false" trigger="click" style="float:right">
<el-button size="small" icon="Grid"></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-scrollbar style="height:200px;">
<el-checkbox-group v-model="Ms.selectedColList">
<el-dropdown-item v-for="(item,index) in Ms.colList" :key="index">
<el-checkbox :key="item.value" :label="item">{{item.label}}</el-checkbox>
</el-dropdown-item>
</el-checkbox-group>
</el-scrollbar>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- 主表 -->
<el-table style="margin-top:15px;width: 100%;"
header-cell-class-name="headerStyle"
stripe
@cell-dblclick="celldblclick"
:data="Ms.dataList"
:border="true"
sortable="custom"
@sort-change="sortChangeHandle"
@selection-change="selectionChangeHandle">
<el-table-column type="selection" header-align="center" align="center" width="50" />
<el-table-column prop="id" header-align="center" align="center" label="主键ID" v-if="showCol('id')" sortable="custom"/>
<el-table-column prop="name" header-align="center" align="center" label="姓名" v-if="showCol('name')" />
<el-table-column prop="age" header-align="center" align="center" label="年龄" v-if="showCol('age')" sortable="custom"/>
<el-table-column prop="email" header-align="center" align="center" label="邮箱" v-if="showCol('email')" />
<el-table-column prop="createDate" header-align="center" align="center" label="创建时间" v-if="showCol('createDate')" sortable="custom"/>
<el-table-column prop="photos" header-align="center" align="center" label="照片" v-if="showCol('photos')" />
<el-table-column prop="lat" header-align="center" align="center" label="经度" v-if="showCol('lat')" sortable="custom"/>
<el-table-column prop="lng" header-align="center" align="center" label="纬度" v-if="showCol('lng')" sortable="custom"/>
<el-table-column prop="enterTime" header-align="center" align="center" label="加入时间" v-if="showCol('enterTime')" sortable="custom"/>
<el-table-column prop="price" header-align="center" align="center" label="价格" v-if="showCol('price')" sortable="custom"/>
<el-table-column prop="mark" header-align="center" align="center" label="备注" v-if="showCol('mark')" />
<el-table-column fixed="right" header-align="center" align="center" width="180" label="操作">
<template #default="scope">
<el-button link type="primary" size="small" @click="showHandle(scope.$index)">查看</el-button>
<el-button link type="primary" size="small" @click="addOrUpdateHandle(scope.$index)">修改</el-button>
<el-button link type="primary" size="small" @click="deleteConfirmHandle(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 翻页器 -->
<el-pagination
style="margin-top:15px;width: 100%;"
background
:current-page="Ms.pageData.pageIndex"
:page-sizes="[10, 20, 50, 100]"
:default-page-size="Ms.pageData.pageSize"
:total="Ms.pageData.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
/>
</el-card>
<!-- 弹窗, 新增 / 修改 -->
<el-dialog v-model="Ms.editDialog" width="75%" :close-on-click-modal="true" :append-to-body="true" :destroy-on-close="true">
<el-form ref="formRef" :model="Ms.formData" :rules="Ms.rules" label-width="100px" @keyup.enter.native="submitHandle()">
<el-row :gutter="15">
<el-col :span="24">
<el-form-item label="姓名" prop="name">
<el-input v-model="Ms.formData.name" placeholder="请输入姓名" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="年龄" prop="age">
<el-input-number v-model="Ms.formData.age" placeholder="请输入年龄" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="邮箱" prop="email">
<el-input v-model="Ms.formData.email" type="textarea" :rows="3" placeholder="请输入邮箱" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="创建时间" prop="createDate">
<el-date-picker v-model="Ms.formData.createDate" type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="加入时间" prop="enterTime">
<el-date-picker v-model="Ms.formData.enterTime" type="datetime" format="YYYY/MM/DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择" clearable/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="价格" prop="price">
<el-input-number v-model="Ms.formData.price" placeholder="请输入价格" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="mark">
<el-input v-model="Ms.formData.mark" placeholder="请输入备注" clearable/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="Ms.editDialog=false">关闭</el-button>
<el-button type="primary" @click="submitHandle">确定</el-button>
</template>
</el-dialog>
<!-- 详细信息 -->
<el-dialog v-model="Ms.showDialog" :close-on-click-modal="true" :append-to-body="true" :destroy-on-close="true">
<el-descriptions :column="2" border id="desc">
<el-descriptions-item label="主键ID">
{{ Ms.formData.id? Ms.formData.id : " "}}
</el-descriptions-item>
<el-descriptions-item label="姓名">
{{ Ms.formData.name? Ms.formData.name : " "}}
</el-descriptions-item>
<el-descriptions-item label="年龄">
{{ Ms.formData.age? Ms.formData.age : " "}}
</el-descriptions-item>
<el-descriptions-item label="邮箱">
{{ Ms.formData.email? Ms.formData.email : " "}}
</el-descriptions-item>
<el-descriptions-item label="创建时间">
{{ Ms.formData.createDate? Ms.formData.createDate : " "}}
</el-descriptions-item>
<el-descriptions-item label="照片">
{{ Ms.formData.photos? Ms.formData.photos : " "}}
</el-descriptions-item>
<el-descriptions-item label="经度">
{{ Ms.formData.lat? Ms.formData.lat : " "}}
</el-descriptions-item>
<el-descriptions-item label="纬度">
{{ Ms.formData.lng? Ms.formData.lng : " "}}
</el-descriptions-item>
<el-descriptions-item label="加入时间">
{{ Ms.formData.enterTime? Ms.formData.enterTime : " "}}
</el-descriptions-item>
<el-descriptions-item label="价格">
{{ Ms.formData.price? Ms.formData.price : " "}}
</el-descriptions-item>
<el-descriptions-item label="备注">
{{ Ms.formData.mark? Ms.formData.mark : " "}}
</el-descriptions-item>
</el-descriptions>
<template #footer>
<el-button @click="Ms.showDialog=false">关闭</el-button>
<el-button type="success" @click="printForm" icon="Printer">打印</el-button>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import {downloadByJson,printByJson,printById} from '@/utils/excelTools'
import {useUUID} from '@/hooks/tools'
//=====================================>data
const Ms:any = reactive({
// dataList:[],
pageData:{
total:0,
pageSize:20,
pageIndex:1,
sortProp:'createDate',
sortOrder:'descending',
},
defaultSearchForm:{},
searchForm:{},
formData:{},
dictMap:{},
dataListSelections:[],
showDialog:false,
editDialog:false,
colList:[
{value:'id',label:'主键ID'},
{value:'name',label:'姓名'},
{value:'age',label:'年龄'},
{value:'email',label:'邮箱'},
{value:'createDate',label:'创建时间'},
{value:'photos',label:'照片'},
{value:'lat',label:'经度'},
{value:'lng',label:'纬度'},
{value:'enterTime',label:'加入时间'},
{value:'price',label:'价格'},
{value:'mark',label:'备注'},
],
rules:{
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' }
],
createDate: [
{ required: true, message: '请输入创建时间', trigger: 'blur' }
],
photos: [
{ required: true, message: '请输入照片', trigger: 'blur' }
],
lat: [
{ required: true, message: '请输入经度', trigger: 'blur' }
],
lng: [
{ required: true, message: '请输入纬度', trigger: 'blur' }
],
enterTime: [
{ required: true, message: '请输入加入时间', trigger: 'blur' }
],
price: [
{ required: true, message: '请输入价格', trigger: 'blur' }
],
mark: [
{ required: true, message: '请输入备注', trigger: 'blur' }
],
},
// selectedColList:[]
})
const {proxy} = getCurrentInstance() as any
//接受参数 route.query.name
const route = useRoute()
//跳转传参 router.push({path:'/path',query:{name:'ligang'}})
const router = useRouter()
Ms.selectedColList = [...Ms.colList]
//=====================================>onMounted
onMounted(() => {
getDataList()
});
//=====================================>watch
watch(Ms, (newValue, oldValue) => {
if(import.meta.env.DEV){
console.log('Ms 数据发生改变', newValue)
}
})
//=====================================>computed
Ms._temp=computed(()=>{
return "bo"+"tan"
})
//=====================================>methods
//获取主表数据
const getDataList = async() => {
const sortInfo = Ms.pageData.sortProp + (Ms.pageData.sortOrder === 'descending' ? ' desc' : ' asc')
const {data} = await http.post("/api/greenelec_demo/findByEntity",Ms.searchForm,{params:{page:Ms.pageData.pageIndex,size:Ms.pageData.pageSize,sort:sortInfo}})
if(data.success){
Ms.dataList = data.data.records;
Ms.pageData.total = data.data.total;
}
}
//重置搜索
const resetSearchData = () => {
Ms.searchForm = {...Ms.defaultSearchForm}
Ms.pageData.pageIndex = 1
getDataList()
}
const showHandle = (index?:any) => {
Ms.formData = Ms.dataList[index]
Ms.showDialog=true
}
//打开新增或修改窗体
const addOrUpdateHandle = (index?:any) => {
if(index===undefined){
Ms.formData = {}
}else{
Ms.formData = {...Ms.dataList[index]}
}
Ms.editDialog=true
}
//排序发生改变
const sortChangeHandle = (sort) =>{
Ms.pageData.sortProp = sort.prop
Ms.pageData.sortOrder = sort.order
Ms.pageData.pageIndex = 1
getDataList()
}
//选择主表数据
const selectionChangeHandle = (selection) =>{
Ms.dataListSelections = selection
}
//搜索
const searchData = () => {
Ms.pageData.pageIndex = 1
getDataList()
}
//页面size修改
const sizeChangeHandle = (size) =>{
Ms.pageData.pageSize = size
Ms.pageData.pageIndex = 1
getDataList()
}
//翻页
const currentChangeHandle = (num) => {
Ms.pageData.pageIndex = num
getDataList()
}
//显示列
const showCol = (colName) => {
return Ms.selectedColList.findIndex(item=>item.value===colName)>=0;
}
//双击复制
const celldblclick = (row,col) => {
if(!col.property) return
navigator.clipboard.writeText(row[col.property]).then(() => {
ElMessage({message: '内容已复制',type: 'success',})
});
}
//提交数据
const submitHandle = async() =>{
proxy.$refs['formRef'].validate(async valid => {
if (!valid) return
let resp:any = null
if(!Ms.formData.id){
resp = await http.post("/api/greenelec_demo/add",Ms.formData)
}else{
resp = await http.post("/api/greenelec_demo/updateById",Ms.formData)
}
if(resp.data.success){
Ms.editDialog = false
getDataList()
ElNotification({title: '操作成功',message: '更新数据成功',type: 'success'})
}else{
ElMessage({type: 'error',message: '错误:'+resp.msg})
}
})
}
//删除确认
const deleteConfirmHandle = async(id?:any) => {
// 处理IDS
let ids = id ? [id] : Ms.dataListSelections.map(item => {
return item.id
})
ElMessageBox.confirm('确认真的删除吗?','警告',{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const resp = await http.get('/api/greenelec_demo/removeByIds', { params: { ids: ids.join(',') }})
if(resp.data.success){
ElNotification({title: '操作成功',message: '删除数据成功',type: 'success'})
getDataList()
}
}).catch((e)=>{})
}
//导出excle
const exportExcel = () => {
downloadByJson(Ms.selectedColList,Ms.dataListSelections,useUUID()+".xlsx")
}
const printTable = () => {
printByJson(Ms.selectedColList,Ms.dataListSelections,"数据报表")
}
const printForm = () => {
printById("desc")
}
</script>
<style>
.el-table {
--el-table-header-bg-color: #eee;
}
.headerStyle .cell{
color:'#000';
font-weight: bold !important;
}
</style>
ExcelTools.ts 工具 使用到了 js库 print-js 和 xlsx 请自行安装
import printJS from 'print-js';
import {utils,writeFile} from 'xlsx'
/**
* 下载选中的json数据
* @param selectColList 选中的列
* @param dataList 数据
* @param fileName 文件名
*/
const downloadByJson = (selectColList,dataList,fileName) =>{
let excelData:any = [];
const excelHead:any = selectColList.map(item=>item.label)
const excelCol = selectColList.map(item=>item.value)
excelData.push(excelHead)
for (let row of dataList) {
let obj:any = []
for(let col of excelCol){
obj.push(row[col])
}
excelData.push(obj)
}
const ws = utils.json_to_sheet(excelData,{skipHeader: true});
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "sheet1");
writeFile(wb, fileName);
}
/**
* 打印选中的数据
* @param selectColList 选中的列
* @param dataList 数据
*/
const printByJson = (selectColList,dataList,title) =>{
let printColumns = selectColList.map(item => {
return {
field: item.value,
displayName: item.label,
};
});
//整理并过滤掉null
const printData:any = [];
for (let row of dataList) {
let obj:any = {}
for(let col of selectColList){
obj[col.value] = row[col.value]?row[col.value]:''
}
printData.push(obj)
}
printJS({
printable: printData,
maxWidth: 2500,
properties: printColumns,
header: `
<div class="titleDiv">
<div class="title">${title}</div>
</div>
`,
//size: landscape;
style: `@page { margin: 0.5cm; margin-right: 0.5cm; margin-top: 0.5cm; margin-bottom: 0.3cm; padding-bottom: 0px; }
.title {
margin-top: 10px;
font-size: 20px;
text-align: center;
padding:10px;
}
`,
gridStyle: 'text-align: center; border: 1px solid black;',
gridHeaderStyle:
'border-top: 1px solid black; border-right: 1px solid black; border-left: 1px solid black; border-bottom: 0px;',
type: 'json',
});
}
const printById = (id) => {
printJS({
printable:id,
type:'html',
targetStyles: ['*'],
header:'',
style: `@page { margin: 0.5cm; margin-right: 0.5cm; margin-top: 0.5cm; margin-bottom: 0.3cm; padding-bottom: 0px; }`
})
}
export{
downloadByJson,
printByJson,
printById
}