701 lines
20 KiB
Vue
701 lines
20 KiB
Vue
<template>
|
|
<div class="page-body">
|
|
<a-row type="flex">
|
|
<a-col :flex="$mk.config.ui.searchFlex">
|
|
<!-- 搜索区 -->
|
|
<vxe-form :data="options.searchFormData" :items="options.searchFormItems" titleColon @submit="onSearch2()">
|
|
<template #date="{ }">
|
|
<a-form-item label="创建时间" :style="{ display: 'inline-block', width: 120 }">
|
|
</a-form-item>
|
|
<a-form-item :style="{ display: 'inline-block', width: 'calc(100% - 120px )' }">
|
|
<a-range-picker @change="onDateChange" />
|
|
</a-form-item>
|
|
</template>
|
|
</vxe-form>
|
|
</a-col>
|
|
<a-col :flex="$mk.config.ui.toolbarFlex">
|
|
<!-- 工具条 -->
|
|
<mk-toolbar :buttons="options.toolbarButtons" :isShowAdd="options.disabledAdd !== true" :isShowDelete="false"
|
|
@toolbarClick="toolbarClick"></mk-toolbar>
|
|
</a-col>
|
|
</a-row>
|
|
|
|
<vxe-toolbar ref="xToolbar" custom>
|
|
<template #buttons>
|
|
<a-button type="primary" icon="delete" @click="pageDelete()" v-if="options.disabledDelete !== true">批量删除</a-button>
|
|
<a-button type="primary" style="margin-left: 5px;" icon="print" v-if="options.enabledPrint"
|
|
@click="pagePrint()">打印</a-button>
|
|
<a-button type="primary" style="margin-left: 5px;" icon="print" v-if="options.enabledPrint2"
|
|
@click="pagePrint2()">打印2</a-button>
|
|
|
|
<a-button type="primary" style="margin-left: 5px;" icon="export" v-if="options.enabledExport"
|
|
@click="pageExport()">导出</a-button>
|
|
<a-button type="primary" style="margin-left: 5px;" icon="import" v-if="options.enabledImport"
|
|
@click="pageImport()">导入</a-button>
|
|
<a-button type="default" style="margin-left: 5px;" v-if="options.enabledImportTemplate"
|
|
@click="pageImportTemplate()">下载导入模板</a-button>
|
|
|
|
|
|
|
|
</template>
|
|
</vxe-toolbar>
|
|
<!-- 表格区 -->
|
|
<div class="gridPanel">
|
|
<vxe-grid ref='xGrid' v-bind="options.gridOptions" class="mytable-style" :row-class-name="rowClassName">
|
|
<template #op="{ row }">
|
|
<div class="oplinks">
|
|
<a v-if="enabledOp({ name: 'edit', row: row })" @click.stop="pageEdit(row)" title="编辑"><a-icon
|
|
type="edit" /></a>
|
|
<a v-if="enabledOp({ name: 'delete', row: row })" @click.stop="pageDelete(row)" title="删除"><a-icon
|
|
type="delete" /></a>
|
|
</div>
|
|
</template>
|
|
|
|
<template #column1="{ row }">
|
|
<slot name="column1" :row="row"></slot>
|
|
</template>
|
|
|
|
<template #column2="{ row }">
|
|
<slot name="column2" :row="row"></slot>
|
|
</template>
|
|
<template #column3="{ row }">
|
|
<slot name="column3" :row="row"></slot>
|
|
</template>
|
|
<template #column4="{ row }">
|
|
<slot name="column4" :row="row"></slot>
|
|
</template>
|
|
<template #column5="{ row }">
|
|
<slot name="column5" :row="row"></slot>
|
|
</template>
|
|
<template #column6="{ row }">
|
|
<slot name="column6" :row="row"></slot>
|
|
</template>
|
|
</vxe-grid>
|
|
</div>
|
|
|
|
|
|
<vxe-modal v-model="showSheetNameSelector" width="500" height="400" title="选择表名">
|
|
<template #default>
|
|
<div>
|
|
<vxe-select v-model="excelSheetName" placeholder="选择表名" style="width:100%">
|
|
<vxe-option v-for="n in excelSheetNames" :key="n" :value="n" :label="n"></vxe-option>
|
|
</vxe-select>
|
|
</div>
|
|
<div style="margin-top:10px;">
|
|
<vxe-button status="primary" content="确定" @click="importOk"></vxe-button>
|
|
</div>
|
|
</template>
|
|
</vxe-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
|
|
import FileSaver from 'file-saver'
|
|
import * as XLSX from 'xlsx'
|
|
import { read, utils } from "xlsx"; // 注意处理方法引入方式
|
|
|
|
|
|
export default {
|
|
name: 'BasicPageList',
|
|
props: {
|
|
options: {
|
|
type: Object
|
|
}
|
|
},
|
|
data() {
|
|
|
|
return {
|
|
showSheetNameSelector: false,
|
|
excelSheetName: '',
|
|
excelSheetNames: [],
|
|
rowFilters: [],
|
|
|
|
bindSearchData: null
|
|
};
|
|
|
|
},
|
|
|
|
// 计算属性
|
|
computed: {
|
|
},
|
|
|
|
// 创建完成
|
|
created() {
|
|
|
|
let _this = this;
|
|
|
|
this.$nextTick(() => { // 在下次 DOM 更新循环结束之后执行延迟回调
|
|
// 将表格和工具栏进行关联
|
|
this.$refs.xGrid.connect(this.$refs.xToolbar) // 将表格和工具栏进行关联
|
|
});
|
|
|
|
this.options.gridOptions.proxyConfig = { // 配置代理
|
|
sort: true, // 启用排序代理,当点击排序时会自动触发 query 行为
|
|
filter: true, // 启用筛选代理,当点击筛选时会自动触发 query 行为
|
|
props: {
|
|
result: this.options.listFieldName, // 配置响应结果列表字段
|
|
total: 'total' // 配置响应结果总页数字段
|
|
},
|
|
// 接收Promise
|
|
ajax: {
|
|
// 当点击工具栏查询按钮或者手动提交指令 query或reload 时会被触发
|
|
query: (options) => { // options 为当前表格的配置项
|
|
const { page, sorts } = options; // 获取当前页码、每页条数、排序信息
|
|
var params = {}; // 定义请求参数
|
|
params.page = page.currentPage; // 当前页码
|
|
params.limit = page.pageSize; // 每页条数
|
|
params.order_bys = []; // 排序信息
|
|
params.search_rules = _this.getSearchParms(); // 搜索信息
|
|
if (sorts) { // 如果有排序信息
|
|
|
|
sorts.forEach((v) => { // 遍历排序信息
|
|
|
|
if (this.options.gridOptions.sortInit) {
|
|
this.options.gridOptions.sortInit({ sort: v, params: params })
|
|
} else {
|
|
params.order_bys.push({ // 添加排序信息
|
|
column: v.property, // 字段名
|
|
order: v.order // 排序方式
|
|
})
|
|
}
|
|
|
|
});
|
|
}
|
|
return _this.loadData({ params }); // 返回请求结果
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
},
|
|
// 挂载完成
|
|
onLoad() {
|
|
|
|
|
|
|
|
|
|
},
|
|
// 动作
|
|
methods: {
|
|
|
|
enabledOp({ name, row }) {
|
|
|
|
if (name == 'delete' && row.__hide_delete) {
|
|
return false
|
|
}
|
|
return true;
|
|
},
|
|
pagePrint() {
|
|
let tableData = JSON.parse(JSON.stringify(this.$refs.xGrid.getTableData().fullData));
|
|
this.$emit("print", { tableData: tableData });
|
|
|
|
},
|
|
pagePrint2() {
|
|
let tableData = JSON.parse(JSON.stringify(this.$refs.xGrid.getTableData().fullData));
|
|
this.$emit("print2", { tableData: tableData });
|
|
|
|
},
|
|
pageExport() {
|
|
let jsonRows = [];
|
|
let headerCells = [];
|
|
|
|
for (let i = 0; i < this.options.exportColumns.length; i++) {
|
|
let item = this.options.exportColumns[i];
|
|
headerCells.push(item.title);
|
|
}
|
|
|
|
|
|
|
|
|
|
let details = JSON.parse(JSON.stringify(this.$refs.xGrid.getTableData().fullData));
|
|
|
|
|
|
details.forEach(row => {
|
|
let jsonRow = {
|
|
};
|
|
for (let i = 0; i < this.options.exportColumns.length; i++) {
|
|
let item = this.options.exportColumns[i];
|
|
var v = "";
|
|
if (item.valueGetter) {
|
|
v = item.valueGetter({ row: row, column: item });
|
|
}
|
|
else if (item.dataField) {
|
|
v = row[item.dataField];
|
|
if (item.textField && v) {
|
|
v = v[item.textField]
|
|
}
|
|
} else {
|
|
v = row[item.field] || '';
|
|
}
|
|
|
|
jsonRow[item.title] = v;
|
|
}
|
|
jsonRows.push(jsonRow);
|
|
});
|
|
var worksheet = XLSX.utils.json_to_sheet(jsonRows, { header: headerCells, skipHeader: false });
|
|
|
|
const workbook = XLSX.utils.book_new();
|
|
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
|
|
|
|
/* get binary string as output */
|
|
var wbout = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'array' })
|
|
try {
|
|
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), (this.options.exportFileTitle || '导出数据') + '.xlsx')
|
|
} catch (e) {
|
|
if (typeof console !== 'undefined') {
|
|
console.log(e, wbout)
|
|
}
|
|
}
|
|
},
|
|
pageImportTemplate() {
|
|
let jsonRows = [];
|
|
let headerCells = [];
|
|
|
|
for (let i = 0; i < this.options.exportColumns.length; i++) {
|
|
let item = this.options.exportColumns[i];
|
|
headerCells.push(item.title);
|
|
}
|
|
var worksheet = XLSX.utils.json_to_sheet(jsonRows, { header: headerCells, skipHeader: false });
|
|
|
|
const workbook = XLSX.utils.book_new();
|
|
XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
|
|
/* get binary string as output */
|
|
var wbout = XLSX.write(workbook, { bookType: 'xlsx', bookSST: true, type: 'array' })
|
|
try {
|
|
FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), '导入模板.xlsx')
|
|
} catch (e) {
|
|
if (typeof console !== 'undefined') {
|
|
console.log(e, wbout)
|
|
}
|
|
}
|
|
},
|
|
pageImport() {
|
|
let fileForm = document.createElement('form');
|
|
let fileInput = document.createElement('input');
|
|
fileForm.className = 'vxe-table--file-form';
|
|
fileInput.name = 'file';
|
|
fileInput.type = 'file';
|
|
fileForm.appendChild(fileInput);
|
|
document.body.appendChild(fileForm);
|
|
|
|
fileInput.multiple = false;
|
|
fileInput.accept = '';
|
|
|
|
fileInput.onchange = (evnt) => {
|
|
var files = evnt.target.files;
|
|
var file = files[0];
|
|
this.readExcel(file)
|
|
};
|
|
|
|
fileForm.reset();
|
|
fileInput.click();
|
|
},
|
|
readExcel(file) {
|
|
const fileReader = new FileReader();
|
|
this.$mk.loading("读取中...");
|
|
fileReader.onload = ev => {
|
|
try {
|
|
const data = ev.target.result;
|
|
const workbook = read(data, { type: "binary" });
|
|
this.workbook = workbook;
|
|
this.excelSheetNames = workbook.SheetNames;
|
|
this.showSheetNameSelector = true;
|
|
this.$mk.hideLoading();
|
|
|
|
|
|
|
|
} catch (e) {
|
|
console.log("error:" + e);
|
|
return false;
|
|
}
|
|
}
|
|
fileReader.readAsBinaryString(file);
|
|
},
|
|
|
|
importOk() {
|
|
this.showSheetNameSelector = false;
|
|
|
|
const { workbook, excelSheetName } = this;
|
|
if (!excelSheetName) {
|
|
return;
|
|
}
|
|
let tableData = utils.sheet_to_json(workbook.Sheets[excelSheetName]);
|
|
|
|
this.$emit("importData", { data: tableData });
|
|
|
|
},
|
|
// 修改日期
|
|
onDateChange(date) { // 日期选择器事件
|
|
if (date && date.length) { // 如果有值
|
|
date[0]._d.setHours(0, 0, 0, 0);
|
|
date[1]._d.setHours(23, 59, 59, 59);
|
|
this.start_time = parseInt(date[0]._d.getTime() / 1000); // 将日期转换为时间戳
|
|
this.end_time = parseInt(date[1]._d.getTime() / 1000); // 将日期转换为时间戳
|
|
} else { // 如果没有值
|
|
this.start_time = 0; // 将日期转换为时间戳
|
|
this.end_time = 0; // 将日期转换为时间戳
|
|
}
|
|
},
|
|
// 获取搜索参数
|
|
getSearchParms() { // 获取搜索参数
|
|
var rules = []; // 定义搜索参数
|
|
this.rowFilters = [];
|
|
let findMode = k => { // 查找搜索模式
|
|
for (let i in this.options.searchRules) { // 遍历搜索规则
|
|
if (this.options.searchRules[i].key == k) return this.options.searchRules[i].mode; // 如果找到了就返回搜索模式
|
|
}
|
|
return "="; // 如果没有找到就返回等于
|
|
};
|
|
|
|
for (let key in this.options.searchFormData) { // 遍历搜索表单数据
|
|
let value = this.options.searchFormData[key]; // 获取值
|
|
if (value === 0 || value) { // 如果有值
|
|
let mode = findMode(key); // 获取搜索模式
|
|
if (typeof (mode) == "function") {
|
|
let v = mode({ value: value, key: key });
|
|
if (v.rules) {
|
|
rules = [...rules, v.rules];
|
|
} else if (v.filter) {
|
|
this.rowFilters.push(v.filter);
|
|
}
|
|
}
|
|
else {
|
|
if (mode == "like") { // 如果是模糊搜索
|
|
value = "%" + value + "%"; // 如果是模糊搜索就在两边加上%
|
|
}
|
|
if (typeof (value) == "object" && value.id) {
|
|
value = value.id;
|
|
}
|
|
rules.push({ // 添加搜索参数
|
|
column: key, // 字段名
|
|
mode: mode, // 搜索模式
|
|
value: value // 值
|
|
});
|
|
}
|
|
|
|
}
|
|
}
|
|
if (this.bindSearchData) {
|
|
for (let key in this.bindSearchData) { // 遍历搜索表单数据
|
|
let value = this.bindSearchData[key]; // 获取值
|
|
if (value) { // 如果有值
|
|
let mode = findMode(key); // 获取搜索模式
|
|
if (mode == "like") { // 如果是模糊搜索
|
|
value = "%" + value + "%"; // 如果是模糊搜索就在两边加上%
|
|
}
|
|
rules.push({ // 添加搜索参数
|
|
column: key, // 字段名
|
|
mode: mode, // 搜索模式
|
|
value: value // 值
|
|
});
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return rules; // 返回搜索参数
|
|
},
|
|
// 获取选中行
|
|
getSelectdRow() { // 获取选中行
|
|
let row = this.$refs.xGrid.getCurrentRecord(); // 获取当前行
|
|
if (!row) { // 如果没有选中行
|
|
let rows = this.$refs.xGrid.getCheckboxRecords(); // 获取选中行
|
|
if (rows && rows.length) { row = rows[0]; } // 如果有选中行就取第一行
|
|
}
|
|
return row; // 返回选中行
|
|
},
|
|
// 加载数据
|
|
loadData({ params }) {
|
|
params.start_time = this.start_time; // 开始时间
|
|
params.end_time = this.end_time; // 结束时间
|
|
return this.$mk.getPagedData({
|
|
url: this.options.actions.getList,
|
|
data: params,
|
|
listFieldName: this.options.listFieldName,
|
|
callback: (e) => {
|
|
this.$emit("loadData", e)
|
|
},
|
|
rowFilters: this.rowFilters
|
|
});
|
|
},
|
|
|
|
// 工具栏点击事件 add / log / setting
|
|
toolbarClick(e) {
|
|
if (e.name == "add") { // 如果是添加
|
|
|
|
if (this.options.editPage) {
|
|
this.$mk.dialog.open({
|
|
page: this.options.editPage,
|
|
title: this.options.editPageTitle,
|
|
pageOptions: {
|
|
},
|
|
width: this.$mk.getWindowSize().width * 0.9,
|
|
height: this.$mk.getWindowSize().height * 0.9,
|
|
dataId: 0,
|
|
callback: ({ success }) => {
|
|
if (success) {
|
|
this.$refs.xGrid.commitProxy('query')
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
this.$openPage(this.options.addPageUrl); // 打开页面
|
|
}
|
|
|
|
|
|
|
|
}
|
|
else if (e.name == "setting") {
|
|
this.openSettingPage();
|
|
|
|
}
|
|
this.$emit("toolbarClick", e)
|
|
},
|
|
openSettingPage() {
|
|
this.$mk.dialog.open({
|
|
page: () => import("./setting"),
|
|
title: "配置",
|
|
pageOptions: this.options.settings,
|
|
width: 800,
|
|
height: 600,
|
|
dataId: 0,
|
|
callback: ({ success }) => {
|
|
if (success) {
|
|
this.$refs.gridRouter.commitProxy('query')
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
getPageList() {
|
|
|
|
let target = [];
|
|
|
|
let find = (component) => {
|
|
|
|
if (component && component.pageList) {
|
|
target = component.pageList;
|
|
}
|
|
if (component.$parent) {
|
|
find(component.$parent)
|
|
}
|
|
}
|
|
|
|
find(this.$parent);
|
|
|
|
|
|
return target;
|
|
},
|
|
isEditPageOpen() {
|
|
let pageList = this.getPageList();
|
|
if (pageList.filter(a => a.keyPath && a.keyPath.indexOf(this.options.editPageUrl) == 0).length) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
getTabsViewPageComponent() {
|
|
|
|
let target = null;
|
|
|
|
let find = (component) => {
|
|
|
|
if (component && component.pageList) {
|
|
target = component;
|
|
}
|
|
if (component.$parent) {
|
|
find(component.$parent)
|
|
}
|
|
}
|
|
|
|
find(this.$parent);
|
|
|
|
|
|
return target;
|
|
},
|
|
//找到定义了beforeTabClose方法 的页面组件
|
|
findEditPageComponent(key) {
|
|
if (!key) {
|
|
return null;
|
|
}
|
|
let target = null;
|
|
|
|
|
|
let find = (children) => {
|
|
children.forEach(item => {
|
|
if (item.beforeTabClose && item.pageKeys && item.pageKeys.filter(a => key.indexOf(a) == 0).length) {
|
|
target = item;
|
|
return;
|
|
}
|
|
if (item.$children && item.$children.length) {
|
|
find(item.$children)
|
|
}
|
|
})
|
|
}
|
|
let tabsview = this.getTabsViewPageComponent();
|
|
if (tabsview == null) {
|
|
return null;
|
|
}
|
|
find(tabsview.$children);
|
|
|
|
|
|
return target;
|
|
},
|
|
// 编辑
|
|
pageEdit(row) {
|
|
if (!row) { // 如果没有选中行
|
|
this.$mk.msg("请选择行"); // 提示
|
|
return; // 返回
|
|
}
|
|
if (this.isEditPageOpen()) {
|
|
let editPage = this.findEditPageComponent(this.options.editPageUrl);
|
|
if (editPage != null) {
|
|
editPage.beforeTabClose().then(() => {
|
|
this.$closePage(this.options.editPageUrl);
|
|
this.showPageEdit(row[this.options.keyName]); // 打开页面
|
|
});
|
|
} else {
|
|
this.showPageEdit(row[this.options.keyName]); // 打开页面
|
|
}
|
|
|
|
} else {
|
|
this.showPageEdit(row[this.options.keyName]); // 打开页面
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
showPageEdit(dataId) {
|
|
|
|
if (this.options.editPage) {
|
|
this.$mk.dialog.open({
|
|
page: this.options.editPage,
|
|
title: this.options.editPageTitle,
|
|
pageOptions: {
|
|
},
|
|
width: this.$mk.getWindowSize().width * 0.9,
|
|
height: this.$mk.getWindowSize().height * 0.9,
|
|
dataId: dataId,
|
|
callback: ({ success }) => {
|
|
if (success) {
|
|
this.$refs.xGrid.commitProxy('query')
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
this.$openPage(this.options.editPageUrl + dataId);
|
|
}
|
|
|
|
},
|
|
|
|
|
|
// 删除
|
|
pageDelete(row) {
|
|
let rows = row ? [row] : this.$refs.xGrid.getCheckboxRecords(); // 获取选中行
|
|
let ids = []; // 定义id数组
|
|
rows.forEach((row) => { // 遍历选中行
|
|
ids.push(row[this.options.keyName]); // 将选择行的id添加到id数组
|
|
});
|
|
|
|
if (!ids.length) { // 如果没有选中行
|
|
this.$mk.error("请选择行"); // 提示
|
|
return;
|
|
}
|
|
|
|
let delParms = {};
|
|
let url = this.options.actions.delete;
|
|
|
|
|
|
if (url.indexOf('batchDelete') != -1) {
|
|
delParms = {
|
|
ids: ids
|
|
}
|
|
} else {
|
|
delParms = {
|
|
id: ids[0]
|
|
}
|
|
}
|
|
|
|
this.$mk.confirm('您确定要删除吗?').then(type => { // 确认删除
|
|
if (type == 'confirm') { // 如果确认删除
|
|
this.$mk.post({
|
|
url: url, // 请求删除数据地址
|
|
loading: "删除中...", // 加载提示
|
|
data: delParms,
|
|
useBigInt: true
|
|
}).then((r) => { // 成功
|
|
if(r.code == 200){
|
|
this.$mk.success("删除成功"); // 提示成功
|
|
this.$refs.xGrid.commitProxy('query') // 提交搜索
|
|
}else{
|
|
this.$mk.error(r.msg);
|
|
}
|
|
|
|
|
|
}).catch((a) => { // 失败
|
|
this.$mk.error(a.data.msg); // 提示错误信息
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// 搜索
|
|
onSearch2() {
|
|
this.$refs.xGrid.commitProxy('query') // 提交搜索
|
|
},
|
|
|
|
onSearch(arg) {
|
|
this.bindSearchData = arg;
|
|
this.$refs.xGrid.commitProxy('query') // 提交搜索
|
|
},
|
|
|
|
gridReload() {
|
|
this.$refs.xGrid.commitProxy('query')
|
|
},
|
|
|
|
getConfirmData() {
|
|
let rows = this.$refs.xGrid.getCheckboxRecords();
|
|
return rows;
|
|
},
|
|
|
|
rowClassName({ row }) {
|
|
return row.row_class_name || '';
|
|
},
|
|
},
|
|
// 监听属性
|
|
watch: {
|
|
|
|
}
|
|
};
|
|
|
|
</script>
|
|
<style lang="less">
|
|
.mytable-style .row-lightred td {
|
|
background-color: #ff9b9b9e;
|
|
}
|
|
|
|
.mytable-style .row-lightyellow td {
|
|
background-color: #ffe09b9e;
|
|
}
|
|
|
|
|
|
|
|
.page-body {
|
|
padding: 15px;
|
|
background: @base-bg-color;
|
|
}
|
|
|
|
.gridPanel {
|
|
height: calc(100vh - 220px);
|
|
}
|
|
|
|
.oplinks svg {
|
|
width: 22px;
|
|
height: 22px;
|
|
margin: 0 5px 0 0;
|
|
}
|
|
</style> |