709 lines
26 KiB
Vue
709 lines
26 KiB
Vue
<template>
|
||
<div class="manage-list-container">
|
||
<div v-if="tableData">
|
||
<!-- {{ query }} -->
|
||
<!-- 筛选 -->
|
||
<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" :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>
|
||
<el-date-picker v-else-if="field.searchType == 'time-interval'" v-model="query[field.field]"
|
||
type="datetimerange" :shortcuts="dateTimePickerRangeShotcut" range-separator="至"
|
||
:start-placeholder="field.placeholder + ' 起始时间'" :end-placeholder="field.placeholder + '结束时间'"
|
||
:prefix-icon="Filter" style="width: 350px; margin-right: 10px;" />
|
||
<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"
|
||
v-if="props.addFunc">新增记录</el-button>
|
||
<el-button type="primary" :icon="Download" @click="exportFormVisible = true" v-permiss="props.editPermiss"
|
||
v-if="props.exportFunc">导出到文件</el-button>
|
||
</div>
|
||
<!-- 表格 -->
|
||
<el-table :data="tableData" border class="table" ref="multipleTable" header-cell-class-name="table-header">
|
||
<el-table-column prop="id" label="ID" align="center"></el-table-column>
|
||
<el-table-column v-for="(field, index) in tableFields" :prop="field.prop" :label="field.label" :key="index"
|
||
align="center">
|
||
<template #default="scope" v-if="field.type == 'image'">
|
||
<el-image style="width: 100%; height: 100%;" :src="scope.row[field.prop]" fit="cover" />
|
||
</template>
|
||
<template #default="scope" v-else-if="field.type == 'time'">
|
||
{{
|
||
new Date(scope.row[field.prop] + 8 * 3600 * 1000).toISOString().replace('T', ' ').substring(0,19)
|
||
}}
|
||
</template>
|
||
<template #default="scope" v-else-if="field.type == 'longtext'">
|
||
<el-tooltip placement="top">
|
||
<template #content>
|
||
<p v-for="line in scope.row[field.prop].split(/[\r\n]/g)" style="max-width: 300px;">
|
||
{{ line }}
|
||
</p>
|
||
</template>
|
||
<div class="oneLine">
|
||
{{ scope.row[field.prop] }}
|
||
</div>
|
||
</el-tooltip>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="220" align="center" v-if="props.editFunc || props.deleteFunc">
|
||
<template #default="scope">
|
||
<el-button text :icon="Edit" @click="handleEdit(scope.$index, scope.row)"
|
||
v-permiss="props.editPermiss" v-if="props.editFunc">
|
||
编辑
|
||
</el-button>
|
||
<el-button text :icon="Delete" class="red" @click="handleDelete(scope.$index, scope.row)"
|
||
v-permiss="props.editPermiss" v-if="props.deleteFunc">
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<!-- 分页 -->
|
||
<div class="pagination">
|
||
<el-pagination background layout="total, prev, pager, next" :current-page="query.pageIndex"
|
||
:page-size="query.pageSize" :total="pageTotal" @current-change="handlePageChange"></el-pagination>
|
||
</div>
|
||
</div>
|
||
<div v-else style="padding-top: 11vh;">
|
||
<el-empty description="暂无数据" />
|
||
</div>
|
||
|
||
<!-- 新增 / 编辑弹出框 -->
|
||
<el-dialog :title="formId > 0 ? '编辑' : '新增'" v-model="editVisible" style="width: 40%; min-width: 280px;">
|
||
<!-- {{ form }} -->
|
||
<el-form ref="editForm" label-width="80px" :rules="rules" :model="form">
|
||
<el-form-item v-if="editVisible" v-for="field in dialogFields" :label="field.label" :prop="field.field">
|
||
<el-input v-if="(formId > 0 ? field.editType : field.addType) == 'input'"
|
||
:placeholder="formId > 0 ? field.editPlaceholder : field.addPlaceholder" class="popup-item"
|
||
v-model="form[field.field]"></el-input>
|
||
<el-input v-else-if="(formId > 0 ? field.editType : field.addType) == 'textarea'"
|
||
:placeholder="formId > 0 ? field.editPlaceholder : field.addPlaceholder" class="popup-item"
|
||
v-model="form[field.field]" type="textarea" :rows="4"></el-input>
|
||
<el-select v-else-if="(formId > 0 ? field.editType : field.addType) == 'select'" class="popup-item"
|
||
v-model="form[field.field]" :clearable="true">
|
||
<el-option v-for="optKey in Object.keys(field.options)" :key="optKey" :label="field.options[optKey]"
|
||
:value="optKey"></el-option>
|
||
</el-select>
|
||
<ImageUpload v-else-if="(formId > 0 ? field.editType : field.addType) == 'image'"
|
||
:imageUrl="form[field.field]" @change="(value: any) => form[field.field] = value" />
|
||
<el-input v-else-if="(formId > 0 ? field.editType : field.addType) == 'plainText'" class="popup-item"
|
||
v-model="form[field.field]" :disabled="true"></el-input>
|
||
<!-- {{ field }} -->
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="doMockData(formId > 0)" type="danger" round>随机填充测试数据</el-button>
|
||
<el-button @click="editVisible = false">取 消</el-button>
|
||
<el-button type="primary" @click="saveEdit(editForm)">确 定</el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<!-- 导出 Excel 弹窗 -->
|
||
<el-dialog v-model="exportFormVisible" title="导出选项">
|
||
<!-- {{ exportConfig }} -->
|
||
<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, computed } from 'vue';
|
||
import { FormInstance, FormRules, ElMessage, ElMessageBox } from 'element-plus';
|
||
import { Delete, Edit, Search, Plus, Filter, Download } from '@element-plus/icons-vue';
|
||
import * as xlsx from 'xlsx';
|
||
import Mock from 'mockjs';
|
||
import ImageUpload from './image-upload.vue';
|
||
|
||
const props = defineProps({
|
||
// 获取列表 接口函数
|
||
'listFunc': {
|
||
type: Function,
|
||
required: true,
|
||
},
|
||
// 新增 接口函数
|
||
'addFunc': {
|
||
type: Function,
|
||
required: false,
|
||
},
|
||
// 修改 接口函数
|
||
'editFunc': {
|
||
type: Function,
|
||
required: false,
|
||
},
|
||
// 删除 接口函数
|
||
'deleteFunc': {
|
||
type: Function,
|
||
required: false,
|
||
},
|
||
// 导出 接口函数
|
||
'exportFunc': {
|
||
type: Function,
|
||
required: true,
|
||
},
|
||
// 修改、删除、导出权限
|
||
'editPermiss': {
|
||
type: String,
|
||
required: true,
|
||
}
|
||
})
|
||
|
||
// 筛选条件
|
||
const searchFields: any = ref([]); // 筛选条件字段
|
||
const query = reactive({
|
||
pageIndex: 1,
|
||
pageSize: 10
|
||
// 其他筛选条件
|
||
}); // 筛选条件的值
|
||
|
||
// 字段翻译字典(如 roleId -> roleName)
|
||
let fieldsMapper: any;
|
||
|
||
// 表格
|
||
const tableData: any = ref(null); // 表格数据
|
||
const tableFields: any = ref([]); // 表格列
|
||
const pageTotal = ref(0); // 总页数
|
||
|
||
// 新增/编辑 弹窗
|
||
const dialogFields: any = ref([]); // 弹窗字段
|
||
const editVisible = ref(false); // 是否显示弹窗
|
||
let form = reactive({} as any); // 弹窗字段的值
|
||
let idx: number = -1; // 表格中编辑行的 index; 新增为 -1
|
||
let formId: number = -1; // 数据库 id; 新增为 -1
|
||
let idFieldName: string = ''; // id列列名
|
||
|
||
// 添加/修改记录时表单验证
|
||
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) => {
|
||
console.log(data)
|
||
|
||
// 深拷贝一份
|
||
let _tableData = JSON.parse(JSON.stringify(data.list));
|
||
// 字段映射
|
||
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 // 塞回新值
|
||
return row
|
||
})
|
||
}
|
||
}
|
||
|
||
console.log("data.columns", data.columns)
|
||
|
||
// 表格列
|
||
tableFields.value = data.columns
|
||
.filter((field: any) => field.fieldType != "null")
|
||
.map((field: any) => {
|
||
// query 填充默认空字符串
|
||
if (typeof (query[field.field]) === "undefined") {
|
||
query[field.field] = ''
|
||
}
|
||
return { prop: field.prop, label: field.label, type: field.fieldType }
|
||
});
|
||
console.log("tableFields", tableFields.value)
|
||
// 表格数据
|
||
tableData.value = _tableData;
|
||
// 总页数
|
||
pageTotal.value = data.total;
|
||
|
||
// id列列名
|
||
idFieldName = data.idFieldName;
|
||
console.log("idFieldName", idFieldName)
|
||
|
||
// 筛选字段
|
||
searchFields.value = data.columns
|
||
.filter((field: any) => field.searchType != "null")
|
||
.map((field: any) => {
|
||
let f: any = {
|
||
placeholder: field.label,
|
||
field: field.field,
|
||
searchType: field.searchType,
|
||
}
|
||
switch (field.searchType) {
|
||
case 'select':
|
||
// 如果是下拉框,那么找到下拉框的 option 数据
|
||
f.options = fieldsMapper.find((field: any) => field.key == f.field).mapper
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return f
|
||
});
|
||
console.log("searchFields", searchFields.value);
|
||
|
||
// 新增/修改弹窗列
|
||
dialogFields.value = data.columns
|
||
.map((field: any) => {
|
||
let f: any = {
|
||
label: field.label,
|
||
field: field.field,
|
||
addType: field.addType,
|
||
addPlaceholder: field.addPlaceholder,
|
||
editType: field.editType,
|
||
editPlaceholder: field.editPlaceholder,
|
||
default: field.default,
|
||
}
|
||
switch (field.searchType) {
|
||
case 'select':
|
||
// 如果是下拉框,那么找到下拉框的 option 数据
|
||
f.options = fieldsMapper.find((field: any) => field.key == f.field).mapper
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return f
|
||
});
|
||
console.log("dialogFields", dialogFields.value);
|
||
|
||
// 导出 excel 字段映射
|
||
exportFields = data.columns
|
||
.filter((field: any) => field.fieldType != "null")
|
||
.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
|
||
}
|
||
console.log("rules", rules.value)
|
||
|
||
// 测试数据
|
||
mockData = data.columns
|
||
.filter((field: any) => field.mockRegex)
|
||
.map((field: any) => {
|
||
let spaceIndex = field.mockRegex.indexOf(' ')
|
||
if (spaceIndex == -1) return
|
||
let type = field.mockRegex.substring(0, spaceIndex)
|
||
let str = field.mockRegex.substring(spaceIndex + 1)
|
||
return {
|
||
canEdit: field.editType != "plainText",
|
||
field: field.field,
|
||
type: type,
|
||
str: str,
|
||
}
|
||
})
|
||
console.log("mockData", mockData)
|
||
})
|
||
};
|
||
|
||
// 查询按钮
|
||
const handleSearch = () => {
|
||
query.pageIndex = 1;
|
||
getData();
|
||
};
|
||
|
||
// 分页导航
|
||
const handlePageChange = (val: number) => {
|
||
query.pageIndex = val;
|
||
getData();
|
||
};
|
||
|
||
// 点击进入编辑框
|
||
const handleEdit = (index: number, row: any) => {
|
||
idx = index;
|
||
formId = row[idFieldName];
|
||
form[idFieldName] = formId;
|
||
// 遍历所有编辑项,并将 row 的值赋给表格
|
||
for (let f of dialogFields.value) {
|
||
switch (f.editType) {
|
||
case "select":
|
||
// 下拉框的值要为 string 类型
|
||
form[f.field] = String(row[f.field]);
|
||
break;
|
||
default:
|
||
form[f.field] = row[f.field];
|
||
break;
|
||
}
|
||
}
|
||
editVisible.value = true;
|
||
};
|
||
|
||
// 点击进入新建框
|
||
const handleNew = () => {
|
||
idx = -1;
|
||
formId = -1;
|
||
form[idFieldName] = -1;
|
||
// 遍历所有编辑项,并将 row 的值赋给表格
|
||
for (let f of dialogFields.value) {
|
||
switch (f.editType) {
|
||
case "select":
|
||
// 下拉框的值要为 string 类型
|
||
form[f.field] = String(f.default);
|
||
break;
|
||
default:
|
||
form[f.field] = f.default;
|
||
break;
|
||
}
|
||
}
|
||
editVisible.value = true;
|
||
};
|
||
|
||
// 编辑保存到数据库
|
||
const saveEdit = async (formEl: FormInstance | undefined) => {
|
||
if (!formEl) return;
|
||
console.log("formEl", formEl);
|
||
formEl.validate(async (valid: boolean, invalidFields: any) => {
|
||
// 表单校验
|
||
if (!valid) {
|
||
// console.log("invalidFields", invalidFields);
|
||
// 对表单中的每一个不合法输入框进行遍历
|
||
Object.values(invalidFields).forEach((input: any) => {
|
||
// 对该不合法输入框的提示信息进行遍历
|
||
input.forEach((element: any) => {
|
||
ElMessage.error({ message: element.message, grouping: true });
|
||
});
|
||
});
|
||
return;
|
||
}
|
||
|
||
var result;
|
||
if (formId > 0) {
|
||
// 修改记录
|
||
var result = await props.editFunc(form)
|
||
} else {
|
||
// 新增记录
|
||
var result = await props.addFunc(form)
|
||
query.pageIndex = Math.ceil((pageTotal.value + 1) / query.pageSize);
|
||
}
|
||
console.log("result", result)
|
||
|
||
if (!result) {
|
||
ElMessage.error({ message: "添加失败" });
|
||
return
|
||
}
|
||
|
||
// 关闭弹窗
|
||
editVisible.value = false;
|
||
|
||
// 更新表格中数据
|
||
await getData();
|
||
|
||
ElMessage.success(formId > 0 ? `修改成功` : `添加成功`);
|
||
});
|
||
};
|
||
|
||
// 删除操作
|
||
const handleDelete = (index: number, row: any) => {
|
||
idx = index;
|
||
// 二次确认删除
|
||
ElMessageBox.confirm('确定要删除吗?', '提示', { type: 'warning' })
|
||
.then(async () => {
|
||
var result = await props.deleteFunc({
|
||
id: row[idFieldName],
|
||
})
|
||
if (result) {
|
||
ElMessage.success('删除成功');
|
||
if (tableData.value.length == 1) {
|
||
// 删除了当前页面的最后一条记录,那么往前翻一页
|
||
if (query.pageIndex > 0) {
|
||
query.pageIndex -= 1;
|
||
}
|
||
}
|
||
tableData.value.splice(idx, 1);
|
||
// 更新表格中数据
|
||
await getData();
|
||
} else {
|
||
ElMessage.error('删除失败');
|
||
}
|
||
})
|
||
.catch(() => { });
|
||
};
|
||
|
||
// 导出数据到文件
|
||
const handleExport = async () => {
|
||
let params = {};
|
||
// 如果选择仅导出满肚条件的数据,那么这里就填上查询参数
|
||
if (exportConfig.value.withFilter) {
|
||
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) {
|
||
if (isEdit && !mock.canEdit) continue; // 跳过不允许修改的列,例如 用户名
|
||
switch (mock.type) {
|
||
case "DTD":
|
||
let regexp = new RegExp(mock.str.substring(1, mock.str.length - 2))
|
||
// console.log(regexp)
|
||
form[mock.field] = Mock.mock({ 'regexp': regexp })['regexp']
|
||
break;
|
||
case "DPD":
|
||
form[mock.field] = Mock.mock(mock.str)
|
||
break;
|
||
case "IMG":
|
||
form[mock.field] = Mock.Random.dataImage(...mock.str.split(','))
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 网页加载完成后加载数据
|
||
onMounted(() => {
|
||
getData();
|
||
});
|
||
|
||
|
||
|
||
// 附加内容
|
||
const dateTimePickerRangeShotcut = [
|
||
{
|
||
text: '今天',
|
||
value: () => {
|
||
const start = new Date()
|
||
start.setHours(0)
|
||
start.setMinutes(0)
|
||
start.setSeconds(0)
|
||
start.setMilliseconds(0)
|
||
const end = new Date(start.getTime() + 24 * 3600 * 1000)
|
||
return [start, end]
|
||
},
|
||
},
|
||
{
|
||
text: '昨天',
|
||
value: () => {
|
||
const end = new Date()
|
||
end.setHours(0)
|
||
end.setMinutes(0)
|
||
end.setSeconds(0)
|
||
end.setMilliseconds(0)
|
||
const start = new Date(end.getTime() - 24 * 3600 * 1000)
|
||
return [start, end]
|
||
},
|
||
},
|
||
{
|
||
text: '过去24小时',
|
||
value: () => {
|
||
const end = new Date()
|
||
const start = new Date()
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1)
|
||
return [start, end]
|
||
},
|
||
},
|
||
{
|
||
text: '过去7天',
|
||
value: () => {
|
||
const end = new Date()
|
||
const start = new Date()
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
|
||
return [start, end]
|
||
},
|
||
},
|
||
{
|
||
text: '过去30天',
|
||
value: () => {
|
||
const end = new Date()
|
||
const start = new Date()
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
|
||
return [start, end]
|
||
},
|
||
},
|
||
{
|
||
text: '过去90天',
|
||
value: () => {
|
||
const end = new Date()
|
||
const start = new Date()
|
||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
|
||
return [start, end]
|
||
},
|
||
},
|
||
]
|
||
|
||
</script>
|
||
|
||
<style scoped>
|
||
.handle-box {
|
||
margin-bottom: 20px;
|
||
line-height: 2.5em;
|
||
}
|
||
|
||
.handle-select {
|
||
width: 150px;
|
||
}
|
||
|
||
.handle-input {
|
||
width: 150px;
|
||
}
|
||
|
||
.table {
|
||
width: 100%;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.red {
|
||
color: #F56C6C;
|
||
}
|
||
|
||
.mr10 {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.table-td-thumb {
|
||
display: block;
|
||
margin: auto;
|
||
width: 40px;
|
||
height: 40px;
|
||
}
|
||
|
||
.popup-item {
|
||
width: 100%;
|
||
}
|
||
|
||
.oneLine {
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
}
|
||
</style>
|