用户管理添加导出到文件;一些改动;删除多余页面
This commit is contained in:
@@ -6,17 +6,24 @@
|
||||
<div class="handle-box">
|
||||
<template v-for="field in searchFields">
|
||||
<el-input v-if="field.searchType == 'input'" v-model="query[field.field]"
|
||||
@keyup.enter.native="handleSearch" :placeholder="field.placeholder"
|
||||
@keyup.enter.native="handleSearch" :placeholder="field.placeholder" :prefix-icon="Filter"
|
||||
class="handle-input mr10"></el-input>
|
||||
<el-select v-else-if="field.searchType == 'select'" v-model="query[field.field]" :clearable="true"
|
||||
@change="handleSearch" :placeholder="field.placeholder" class="handle-select mr10">
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Filter />
|
||||
</el-icon>
|
||||
</template>
|
||||
<el-option v-for="optKey in Object.keys(field.options)" :key="optKey" :label="field.options[optKey]"
|
||||
:value="optKey"></el-option>
|
||||
</el-select>
|
||||
<template v-else>{{ field }}</template>
|
||||
</template>
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">搜索</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleNew" v-permiss="props.editPermiss">新增</el-button>
|
||||
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
|
||||
<el-button type="primary" :icon="Plus" @click="handleNew" v-permiss="props.editPermiss">新增记录</el-button>
|
||||
<el-button type="primary" :icon="Download" @click="exportFormVisible = true"
|
||||
v-permiss="props.editPermiss">导出到文件</el-button>
|
||||
</div>
|
||||
<!-- 表格 -->
|
||||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
||||
@@ -72,14 +79,38 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 导出 Excel 弹窗 -->
|
||||
<el-dialog v-model="exportFormVisible" title="导出选项">
|
||||
<el-form :model="form" label-width="80px">
|
||||
<el-form-item label="数据范围">
|
||||
<el-radio-group v-model="exportConfig.withFilter">
|
||||
<el-radio :label="false">全部数据</el-radio>
|
||||
<el-radio :label="true">满足筛选条件的数据</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件格式">
|
||||
<el-radio-group v-model="exportConfig.ext">
|
||||
<el-radio v-for="ext in supportExportFormatList" :label="ext">{{ ext }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-alert v-if="exportInfo" :title="exportInfo.info" :type="exportInfo.type" :closable="false" show-icon />
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="exportFormVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleExport">导出</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { ref, reactive, onMounted, computed } from 'vue';
|
||||
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Delete, Edit, Search, Plus } from '@element-plus/icons-vue';
|
||||
import send_request from '../utils/send_request';
|
||||
import { Delete, Edit, Search, Plus, Filter, Download } from '@element-plus/icons-vue';
|
||||
import * as xlsx from 'xlsx';
|
||||
import Mock from 'mockjs';
|
||||
|
||||
const props = defineProps({
|
||||
@@ -103,7 +134,12 @@ const props = defineProps({
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
// 修改、删除权限
|
||||
// 导出 接口函数
|
||||
'exportFunc': {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
// 修改、删除、导出权限
|
||||
'editPermiss': {
|
||||
type: String,
|
||||
required: true,
|
||||
@@ -118,6 +154,9 @@ const query = reactive({
|
||||
// 其他筛选条件
|
||||
}); // 筛选条件的值
|
||||
|
||||
// 字段翻译字典(如 roleId -> roleName)
|
||||
let fieldsMapper: any;
|
||||
|
||||
// 表格
|
||||
const tableData: any = ref(null); // 表格数据
|
||||
const tableFields: any = ref([]); // 表格列
|
||||
@@ -136,9 +175,34 @@ const editForm = ref<FormInstance>();
|
||||
// const rules: FormRules = {};
|
||||
const rules = ref({} as FormRules);
|
||||
|
||||
//
|
||||
// mock数据
|
||||
let mockData: any = []
|
||||
|
||||
// 导出 Excel 弹窗
|
||||
const exportFormVisible: any = ref(false);
|
||||
let exportFields: any = [] // 导出 excel 列表对应中文
|
||||
const supportExportFormatList = ref(['xlsx', 'xls', 'csv', 'html', 'txt', 'json', 'rtf'] as Array<String>); // 支持的导出格式
|
||||
const exportConfig = ref({
|
||||
withFilter: false, // 导出时是否携带筛选条件
|
||||
ext: "xlsx", // 所选导出格式
|
||||
} as any);
|
||||
const exportInfo = computed(() => {
|
||||
if (['xlsx', 'xls'].includes(exportConfig.value.ext)) {
|
||||
return null
|
||||
}
|
||||
let info = '建议选择 xlsx 或 xls 格式'
|
||||
let type = 'info'
|
||||
if (['rtf'].includes(exportConfig.value.ext)) {
|
||||
// 不推荐的导出格式
|
||||
info = '该格式易出现编码问题,' + info
|
||||
type = 'warning'
|
||||
} else if (['json'].includes(exportConfig.value.ext)) {
|
||||
info = '该格式方便程序读取,若您不了解该格式,建议选择其他格式进行导出'
|
||||
type = 'warning'
|
||||
}
|
||||
return { info, type }
|
||||
})
|
||||
|
||||
// 获取表格数据
|
||||
const getData = async () => {
|
||||
props.listFunc(query).then((data: any) => {
|
||||
@@ -147,15 +211,15 @@ const getData = async () => {
|
||||
// 深拷贝一份
|
||||
let _tableData = JSON.parse(JSON.stringify(data.list));
|
||||
// 字段映射
|
||||
let fieldsMapper = data.fieldMapper;
|
||||
fieldsMapper = data.fieldMapper;
|
||||
if (fieldsMapper) {
|
||||
// 对于每一个需要映射的字段
|
||||
for (let m of fieldsMapper) {
|
||||
// console.log("mapper", m)
|
||||
_tableData = _tableData.map((row: any) => {
|
||||
let oldValue = row[m.key]
|
||||
let newValue = m.mapper[oldValue]
|
||||
row[m.value] = newValue
|
||||
let oldValue = row[m.key] // 取得旧值
|
||||
let newValue = m.mapper[oldValue] // 翻译新值
|
||||
row[m.value] = newValue // 塞回新值
|
||||
return row
|
||||
})
|
||||
}
|
||||
@@ -167,6 +231,10 @@ const getData = async () => {
|
||||
tableFields.value = data.columns
|
||||
.filter((field: any) => field.showInTable)
|
||||
.map((field: any) => {
|
||||
// query 填充默认空字符串
|
||||
if (typeof (query[field.field]) === "undefined") {
|
||||
query[field.field] = ''
|
||||
}
|
||||
return { prop: field.prop, label: field.label }
|
||||
});
|
||||
console.log("tableFields", tableFields.value)
|
||||
@@ -203,10 +271,6 @@ const getData = async () => {
|
||||
// 新增/修改弹窗列
|
||||
dialogFields.value = data.columns
|
||||
.map((field: any) => {
|
||||
// 拼装 新增/修改弹窗 字段
|
||||
if (typeof (query[field.field]) === "undefined") {
|
||||
query[field.field] = ''
|
||||
}
|
||||
let f: any = {
|
||||
label: field.label,
|
||||
field: field.field,
|
||||
@@ -228,16 +292,17 @@ const getData = async () => {
|
||||
});
|
||||
console.log("dialogFields", dialogFields.value);
|
||||
|
||||
// 导出 excel 字段映射
|
||||
exportFields = data.columns
|
||||
.filter((field: any) => field.showInTable)
|
||||
.map((field: any) => {
|
||||
return { field: field.field, label: field.label }
|
||||
});
|
||||
console.log("exportFields", exportFields)
|
||||
|
||||
// 表单验证
|
||||
for (let field of data.columns) {
|
||||
rules.value[field.field] = field.validateRules
|
||||
// .map((rule: any) => {
|
||||
// if (rule.pattern) {
|
||||
// rule.pattern = new RegExp(rule.pattern)
|
||||
// console.log(rule.pattern)
|
||||
// }
|
||||
// return rule
|
||||
// })
|
||||
}
|
||||
console.log("rules", rules.value)
|
||||
|
||||
@@ -382,6 +447,90 @@ const handleDelete = (index: number, row: any) => {
|
||||
.catch(() => { });
|
||||
};
|
||||
|
||||
// 导出数据到文件
|
||||
const handleExport = async () => {
|
||||
// 去除分页参数
|
||||
let params = JSON.parse(JSON.stringify(query))
|
||||
delete params["pageIndex"]
|
||||
delete params["pageSize"]
|
||||
props.exportFunc(params).then((data: any) => {
|
||||
console.log("exportData", data)
|
||||
let sheetName = data.sheetName
|
||||
let fileName = data.fileName
|
||||
console.log("data.list", data.list)
|
||||
|
||||
// 字段翻译
|
||||
let dataList = JSON.parse(JSON.stringify(data.list))
|
||||
if (fieldsMapper) {
|
||||
// 对于每一个需要映射的字段
|
||||
for (let m of fieldsMapper) {
|
||||
// console.log("mapper", m)
|
||||
dataList = dataList.map((row: any) => {
|
||||
let oldValue = row[m.key] // 取得旧值
|
||||
let newValue = m.mapper[oldValue] // 翻译新值
|
||||
row[m.key] = newValue // 直接在旧 key 塞回新值
|
||||
// 因为后续是通过翻译前的 key 拿的数据,所以这里不翻译 key 只翻译 value
|
||||
return row
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log("dataList", dataList)
|
||||
|
||||
// 所有列的 field
|
||||
let fieldNameList = exportFields.map((f: any) => f.field)
|
||||
fieldNameList.unshift(idFieldName)
|
||||
|
||||
// 第一行表头
|
||||
let firstRow = exportFields.map((f: any) => f.label)
|
||||
firstRow.unshift("ID")
|
||||
|
||||
// 列宽
|
||||
let rowWidth = exportFields.map(() => { return { wch: 13 } })
|
||||
rowWidth.unshift({ wch: 5 })
|
||||
|
||||
// 数据部分
|
||||
let excelList = dataList.map((row: any) => {
|
||||
// 通过翻译前的 key 拿数据
|
||||
return fieldNameList.map((field: any) => String(row[field]))
|
||||
})
|
||||
excelList.unshift(firstRow) // 插入表头
|
||||
|
||||
console.log("excelList", excelList)
|
||||
|
||||
function downloadFile(text: string, fileName: string, contentType: string) {
|
||||
const blob = new Blob([text], { type: contentType });
|
||||
const href = URL.createObjectURL(blob);
|
||||
const alink = document.createElement("a");
|
||||
alink.style.display = "none";
|
||||
alink.download = fileName; // 下载后文件名
|
||||
alink.href = href;
|
||||
document.body.appendChild(alink);
|
||||
alink.click();
|
||||
document.body.removeChild(alink); // 下载完成移除元素
|
||||
URL.revokeObjectURL(href); // 释放掉blob对象
|
||||
}
|
||||
|
||||
// 生成文件
|
||||
let _fileName: string = `${fileName || '数据导出'}.${exportConfig.value.ext || 'xlsx'}`
|
||||
if (exportConfig.value.ext === "json") {
|
||||
let text = JSON.stringify(excelList)
|
||||
downloadFile(text, _fileName, "application/json;charset=utf-8")
|
||||
} else if (exportConfig.value.ext === "txt") {
|
||||
let text = excelList.map((row: Array<any>) => row.join('\t')).join('\n')
|
||||
downloadFile(text, _fileName, "text/plain;charset=utf-8")
|
||||
} else {
|
||||
let worksheet = xlsx.utils.aoa_to_sheet(excelList)
|
||||
let workbook = xlsx.utils.book_new()
|
||||
worksheet["!cols"] = rowWidth; // 指定列宽
|
||||
xlsx.utils.book_append_sheet(workbook, worksheet, sheetName || 'Sheet1')
|
||||
xlsx.writeFile(workbook, _fileName)
|
||||
}
|
||||
|
||||
ElMessage.success({ message: "导出成功" })
|
||||
exportFormVisible.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 生成测试数据
|
||||
const doMockData = (isEdit: boolean) => {
|
||||
for (let mock of mockData) {
|
||||
|
Reference in New Issue
Block a user