javascript
复制代码
<!-- Header 标题搜索栏 -->
<template>
<div>
<div class="header">
<div class="h-left">
<div class="title">
<div class="desc-test">
<i class="el-icon-s-grid"></i>
<span>{{ title }}</span>
</div>
</div>
</div>
<div class="h-right">
<el-input
v-if="inputType === 'input'"
:placeholder="inputPlaceholder"
v-model="searchValue"
size="small"
class="search"
clearable
>
</el-input>
<el-select
v-else-if="inputType === 'select'"
:placeholder="selectPlaceholder"
v-model="searchValue"
size="small"
class="search"
clearable
>
<!-- 添加select选项 -->
<el-option
v-for="(option, index) in options"
:key="index"
:label="option.label"
:value="option.value"
></el-option>
</el-select>
<!-- 按钮组 -->
<slot name="button-list"> </slot>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: '测试管理',
},
inputType: {
type: String,
default: 'select', // 默认为下拉框类型
},
inputPlaceholder: {
type: String,
default: '请输入内容', // 默认提示内容
},
selectPlaceholder: {
type: String,
default: '请选择内容', // 默认提示内容
},
options: {
type: Array,
default: () => [],
},
},
data() {
return {
searchValue: '',
}
},
methods: {
// handleSearchClick() {
// this.$emit('search-clicked', this.searchValue)
// },
},
}
</script>
<style lang="less" scoped>
.header {
display: flex;
height: 35px;
line-height: 35px;
justify-content: space-between;
width: 100%;
.h-left {
width: 25%;
.title {
line-height: 26px;
.desc-test {
margin-top: 5px;
font-weight: bold;
margin-bottom: 3px;
font-size: 14px;
color: #313131;
white-space: nowrap;
width: fit-content;
border-bottom: 2px solid #646565;
i {
font-size: 16px;
position: relative;
top: 1px;
margin-right: 2px;
}
}
}
}
.h-right {
display: flex;
flex-direction: row;
justify-content: flex-end;
/deep/ .el-input__inner {
height: 35px;
line-height: 35px;
}
.search {
margin-right: 20px;
}
}
}
</style>
二、高级查询 (SearchCondition)
javascript
复制代码
<!--
*名称:弹窗的搜索条件组件
*功能:methods
1.点击搜索的方法:@search
2.搜索条件 props : formItemList
-->
<template>
<div class="searchBox" v-show="isShowSearch">
<div class="dialog-search">
<!-- inline 行内表单域 -->
<el-form
:inline="true"
ref="ruleForm"
:model="formInline"
class="demo-form-inline"
>
<el-form-item
v-for="(item, index) in formItemList"
:key="index"
:label="
item.label.length > 7 ? item.label.slice(0, 7) + '...' : item.label
"
label-width="115px"
>
<div class="icon-input">
<!-- effect= light / dark -->
<div class="slotIcon" slot="label">
<el-tooltip effect="dark" :content="item.label" placement="top">
<i class="el-icon-question" />
</el-tooltip>
</div>
<div class="inputBox">
<!-- 普通 input 框 -->
<el-input
v-if="item.type == 'input'"
v-model.trim="formInline[item.param]"
:size="getSize(item.param, item.type) || 'small'"
placeholder="请输入"
></el-input>
<div style="width: 256px;" v-if="item.type === 'interval'">
<!-- 区间输入框 - 起始值 -->
<el-input
style="width:47%;"
v-model.trim="formInline[item.param].start"
:size="getSize(item.param, item.type) || 'small'"
placeholder="起始值"
></el-input>
<span> - </span>
<!-- 区间输入框 - 结束值 -->
<el-input
style="width:48%;"
v-model.trim="formInline[item.param].end"
:size="getSize(item.param, item.type) || 'small'"
placeholder="结束值"
></el-input>
</div>
<!-- 时间区间选择器 -->
<el-date-picker
style="width: 257px;"
v-if="item.type == 'daterange'"
v-model="formInline[item.param]"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:size="getSize(item.param, item.type) || 'small'"
>
</el-date-picker>
<!-- 单个日期 -->
<el-date-picker
v-if="item.type == 'date'"
v-model="formInline[item.param]"
type="date"
placeholder="选择日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
:size="getSize(item.param, item.type) || 'small'"
>
</el-date-picker>
<!-- 数字输入框 -->
<el-input
v-if="item.type == 'inputNumber'"
v-model="formInline[item.param]"
type="number"
placeholder="请输入数字"
:min="getLimit(item.param, item.type, 'min') || ''"
:max="getLimit(item.param, item.type, 'max') || ''"
:maxlength="getMaxLength(item.param, item.type) || ''"
:size="getSize(item.param, item.type) || 'small'"
@change="handleChange(item)"
@blur="handleBlur(item)"
>
</el-input>
<!-- 文本输入框 -->
<el-input
v-if="item.type == 'inputText'"
v-model="formInline[item.param]"
type="text"
placeholder="请输入文本"
:maxlength="getMaxLength(item.param, item.type) || ''"
:size="getSize(item.param, item.type) || 'small'"
show-word-limit
>
</el-input>
<!-- select 框 单选-->
<el-select
v-if="item.type == 'select'"
v-model="formInline[item.param]"
placeholder="请选择内容"
:size="getSize(item.param, item.type) || 'small'"
>
<el-option
v-for="(item2, index2) in item.selectOptions"
:key="index2"
:label="item2.key"
:value="item2.value"
></el-option>
</el-select>
<!-- 省 的 select -->
<el-select
v-if="item.type == 'proSelect'"
v-model="formInline[item.param]"
placeholder="请选择内容"
@change="provChange"
:size="getSize(item.param, item.type) || 'small'"
>
<el-option
v-for="(item2, index2) in item.selectOptions"
:key="index2"
:label="item2.key"
:value="item2.id"
></el-option>
</el-select>
<!-- 市 的 select -->
<el-select
v-if="item.type == 'citySelect'"
v-model="formInline[item.param]"
placeholder="请选择内容"
@change="cityChange"
:size="getSize(item.param, item.type) || 'small'"
>
<el-option
v-for="(item2, index2) in cityList"
:key="index2"
:label="item2.key"
:value="item2.id"
></el-option>
</el-select>
<!-- 区县 的 select -->
<el-select
v-if="item.type == 'xzqSelect'"
v-model="formInline[item.param]"
placeholder="请选择内容"
@change="xzqChange"
:size="getSize(item.param, item.type) || 'small'"
>
<el-option
v-for="(item2, index2) in quList"
:key="index2"
:label="item2.value"
:value="item2.id"
></el-option>
</el-select>
</div>
</div>
</el-form-item>
<!-- 可用于显示其他按钮 -->
<slot></slot>
</el-form>
<div class="btn">
<el-form-item>
<el-button type="primary" plain size="mini" @click="onSubmit"
>查询</el-button
>
<el-button
type="success"
plain
size="mini"
@click="resetForm('ruleForm')"
>重置</el-button
>
<el-button type="warning" plain size="mini" @click="onClose"
>关闭</el-button
>
</el-form-item>
</div>
</div>
</div>
</template>
<script>
import { regionData, CodeToText } from 'element-china-area-data'
export default {
name: 'BaseSearch',
props: {
formItemList: {
type: Array,
default() {
return [
{
label: '下拉框',
type: 'select',
selectOptions: [{ name: 111, value: 111 }],
param: 'company',
defaultSelect: '222', // 下拉框默认选中项
},
{
label: '输入框',
type: 'input',
param: 'name',
},
]
},
},
// 是否显示 弹窗的搜索条件组件
isShowSearch: {
type: Boolean,
default: false,
},
},
data() {
// 获取父组件传过来的 params
let formInline = {}
for (const obj of this.formItemList) {
if (obj.type === 'interval') {
// 对于区间输入框,初始化为对象
formInline[obj.param] = obj.defaultSelect || { start: '', end: '' }
} else {
formInline[obj.param] = obj.defaultSelect || ''
}
}
// let a = this.formItemList.find((item) => {
// console.log("@formInline", formInline);
// if ("maxlength" in item) return item;
// });
// console.log("@aaaaa", a);
// console.log("@regionData[0]", regionData[0]);
// console.log("@regionData", regionData);
// console.log("@this.formItemList", formInline);
return {
formInline,
options: regionData, // 必须是数组 ==》 获取单个省 [regionData[0]]
selectedOptions: [],
cityList: [],
quList: [],
intervalParam: { start: '', end: '' }, // input 区间
}
},
watch: {
formItemList: {
handler(newVal, oldVal) {
for (const obj of this.formItemList) {
if (obj.defaultSelect) {
formInline[obj.param] = obj.defaultSelect
}
}
},
deep: true,
},
},
mounted() {
// console.log("@传过去的值", this.formItemList);
},
methods: {
onSubmit() {
// console.log("submit!", this.formInline);
for (const item of this.formItemList) {
// 确保将区间值设置到 formInline.intervalParam 中
if (item.type === 'interval') {
this.formInline[item.param] = {
start: this.formInline[item.param].start,
end: this.formInline[item.param].end,
}
}
}
this.$emit('search', this.formInline)
// this.resetForm('ruleForm') // 查询后清空搜索条件
this.$emit('isShowHSearchFn')
},
resetForm(formName) {
// console.log('清空条件')
this.$refs[formName].resetFields()
let formInline = {}
for (const obj of this.formItemList) {
// formInline[obj.param] = obj.defaultSelect || ""; // 重置时下拉框的默认值如果要保留就选用这个
if (obj.type === 'interval') {
// 处理 区间 input 的清除
formInline[obj.param] = { start: '', end: '' }
} else {
formInline[obj.param] = '' // 所有筛选条件清空
}
}
this.formInline = formInline
this.cityList = [] // 清空市级下拉
this.quList = [] // 清空区县下拉
},
// 关闭 高级查询
onClose() {
this.resetForm('ruleForm')
this.$emit('isShowHSearchFn')
},
// 获取输入框的最大长度
getMaxLength(param, type) {
let maxlength = this.formItemList.find(
(item) => item.param === param && item.type === type
).maxlength
return maxlength
},
// 获取 输入框的 最大位数 和最小位数
getLimit(param, type, limitType) {
let limit = ''
if (limitType === 'min') {
limit = this.formItemList.find(
(item) => item.param === param && item.type === type
).min
} else if (limitType === 'max') {
limit = this.formItemList.find(
(item) => item.param === param && item.type === type
).max
}
return limit
},
// 获取 input的 大小 getSize、
getSize(param, type) {
let size = this.formItemList.find(
(item) => item.param === param && item.type === type
).size
return size
},
// 数字输入框 值改变的事件
handleChange(item) {
let value = this.formInline[item.param]
if (item.min && value < Number(item.min)) {
this.formInline[item.param] = item.min
} else if (item.max && value > Number(item.max)) {
this.formInline[item.param] = item.max
} else {
this.formInline[item.param] = value
}
},
// 数字输入框 失去焦点的事件
handleBlur(item) {
let value = this.formInline[item.param]
if (item.min && value < Number(item.min)) {
this.formInline[item.param] = item.min
} else if (item.max && value > Number(item.max)) {
this.formInline[item.param] = item.max
} else {
this.formInline[item.param] = value
}
},
provChange(val) {
this.cityList = []
this.quList = []
this.formInline.City = ''
this.formInline.AreaCounty = ''
this.cityList = this.formItemList[3].selectOptions.filter((item) => {
if (val === item.parentId) {
return item
}
})
},
cityChange(val) {
this.quList = []
// console.log("@市", val);
this.formInline.AreaCounty = ''
this.quList = this.formItemList[4].selectOptions.filter((item) => {
if (val === item.parentId) {
return item
}
})
},
xzqChange(val) {
// console.log("@区", val);
},
},
}
</script>
<style lang="less" scoped>
.searchBox {
// height: 300px;
width: 100%;
// width: calc(100% - 32px);
box-sizing: border-box;
background: #fefefe;
// margin-top: 45px;
border: 1px solid #ececec;
position: absolute;
z-index: 999;
// left: 10%;
// right: 10%;
padding: 25px 20px;
// padding-bottom: 0;
box-shadow: 0 7px 18px -12px #bdc0bb;
}
.dialog-search {
margin: 0 1rem;
text-align: left;
// position: relative;
// input 框 label的内边距
.icon-input {
display: flex;
}
/deep/ .el-form-item__label {
padding: 0;
}
/deep/ .el-form-item__content {
// width: 16rem;
// 插槽里面的图标
// border: 1px solid green;
.slotIcon {
// border: 1px solid green;
margin-right: 0.3125rem /* 5px -> .3125rem */;
}
// input 框
.el-input {
width: 16rem;
}
// select 框
.el-select {
// border: 1px solid green;
.el-input__inner {
// width: 16rem;
}
}
}
.btn {
display: flex;
justify-content: flex-end;
width: 100%;
height: 1.875rem /* 30px -> 1.875rem */;
// border: 1px solid red;
}
}
</style>
三、表格组件 (Tables2)
javascript
复制代码
<!-- Tables2 表格组件 -->
<template>
<div>
<!-- tableData.slice((currentPage - 1) * pageSize,currentPage * pageSize) -->
<div class="tables">
<el-table
ref="multipleTable"
:data="displayedData"
:max-height="tableHeight"
border
row-key="id"
style="width: 100%"
tooltip-effect="dark"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
align="center"
:reserve-selection="true"
>
</el-table-column>
<el-table-column
:align="item.align"
v-for="(item, index) in columns"
:key="item.prop"
:prop="item.prop"
:label="item.label"
:fixed="item.fixed"
:width="item.width"
:formatter="item.formatter"
:sortable="item.prop !== 'index' ? false : true"
:filters="item.prop !== 'index' ? dateFilters(item.prop) : ''"
:filter-method="item.prop !== 'index' ? filterHandler : ''"
>
</el-table-column>
<el-table-column fixed="right" label="操作" width="210" align="center">
<template #default="{ scope }">
<!-- 使用插槽来展示自定义的操作按钮 -->
<slot name="action-buttons" :scope="scope" />
</template>
</el-table-column>
</el-table>
</div>
<!-- 分页器 -->
<div class="footer">
<span class="demonstration">
当前选中
<el-tag>{{ multipleSelection.length }}</el-tag> 条</span
>
<!-- computed -->
<el-pagination
align="center"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
</div>
</div>
</template>
<script>
export default {
props: {
tableData: {
type: Array,
default: () => [],
required: true,
},
columns: {
type: Array,
default: () => [],
},
currentPage: {
type: Number,
default: 1,
}, // 当前页码
total: {
type: Number,
default: 20,
}, // 总条数
pageSize: {
type: Number,
default: 10,
}, // 每页的数据条数
tableHeight: {
type: Number,
default: 600,
},
},
data() {
return {
multipleSelection: [], // 选中的值,用于以后操作
}
},
components: {},
computed: {
displayedData() {
return this.tableData
},
displayedColumns() {
return this.columns
},
displayedCurrentPage: {
get() {
return this.currentPage
},
set(newValue) {
this.$emit('update:currentPage', newValue)
},
},
displayedPageSize: {
get() {
return this.pageSize
},
set(newValue) {
this.$emit('update:pageSize', newValue)
},
},
dateFilters() {
return (columnName) => {
const values = new Set(this.tableData.map((item) => item[columnName]))
return Array.from(values).map((value) => ({
text: value,
value: value,
}))
}
},
},
mounted() {},
watch: {},
methods: {
// 获取选中的值
handleSelectionChange(val) {
console.log('@选中的值', val)
this.multipleSelection = val
},
/****** computed *******/
handleSizeChange(val) {
console.log(`每页 ${val} 条`)
this.$emit('update:currentPage', 1) // 修改依赖的值,会触发 displayedCurrentPage 的 set 方法
this.$emit('update:pageSize', val) // 修改依赖的值,会触发 displayedPageSize 的 set 方法
this.$emit('getDataList')
},
handleCurrentChange(val) {
console.log(`当前页: ${val}`)
this.$emit('update:currentPage', val) // 修改依赖的值,会触发 displayedCurrentPage 的 set 方法
this.$emit('getDataList')
},
// 根据该列 对应的选项 返回对应的行
filterHandler(value, row, column) {
const property = column['property']
return row[property] === value
},
},
}
</script>
<style lang="less" scoped>
.footer {
position: absolute;
// bottom: 0;
right: 0;
padding-top: 15px;
font-size: 14px;
width: 100%;
// border-top: 1px solid #a29696;
line-height: 2.25rem /* 36px -> 2.25rem */;
display: flex;
justify-content: flex-end;
.demonstration {
margin-right: 0.625rem /* 10px -> .625rem */;
}
/deep/ .el-pagination {
padding-top: 5px;
line-height: 30px;
}
}
</style>
四、配置项
javascript
复制代码
/******* 表格列的配置 (字段) ********/
const columns = [
{
prop: 'index',
label: '序号',
width: '80',
fixed: 'left',
align: 'center',
},
{
prop: 'name',
label: '姓名',
// width: '180',
align: 'center',
},
{
prop: 'issue',
label: '期次',
// width: '180',
align: 'center',
formatter: function(row, column, cellValue, index) {
if (row.issue === '6') {
return <el-tag style="backgroundColor: #bf933f;">{row.issue}</el-tag>
} else {
return <el-tag type="success">{row.issue}</el-tag>
}
},
},
{
prop: 'creator',
label: '上传人',
// width: '180',
align: 'center',
},
{
prop: 'createDate',
label: '上传时间',
// width: '180',
align: 'center',
},
{
prop: 'size',
label: '文件大小',
// width: '180',
align: 'center',
},
]
export { columns }
javascript
复制代码
/******* 高级查询的配置 ********/
const formItemList = [
{
label: '单位名称:',
type: 'input',
param: 'unit_name',
},
{
label: '省:',
type: 'proSelect',
selectOptions: [],
param: 'prov',
},
{
label: '市:',
type: 'citySelect',
selectOptions: [],
param: 'city',
},
{
label: '区县:',
type: 'xzqSelect',
selectOptions: [],
param: 'xzqdm',
},
{
label: '联系人:',
type: 'input',
param: 'linkman',
},
]
export { formItemList }
五、父页面
javascript
复制代码
<!-- 测试页面 -->
<template>
<div>
<div class="wrap">
<Header
ref="Header"
:title="title"
:input-type="inputType"
:input-placeholder="inputPlaceholder"
:select-placeholder="selectPlaceholder"
:options="options"
>
<template v-slot:button-list>
<!-- 按钮列表 -->
<el-button
type="primary"
size="small"
icon="el-icon-search"
@click="search"
>
查询
</el-button>
<el-button
type="primary"
size="small"
icon="el-icon-search"
plain
@click="showHsearch"
>
高级查询
</el-button>
<el-button type="primary" size="small" icon="el-icon-search" plain>
添加
</el-button>
</template>
</Header>
<div class="content">
<!-- 高级查询 -->
<SearchCondition
:formItemList="formItemList"
:emitSearch="emitSearch"
@search="hSearch"
@isShowHSearchFn="isShowHSearchFn"
:isShowSearch="isShowHSearch"
/>
<!-- 表格 v-model 对应 computed -->
<Tables
v-model:tableData="tableData"
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:columns="columns"
:tableHeight="tableHeight"
@getDataList="getWeekList"
>
<!-- 使用插槽来配置自定义的操作按钮 -->
<template #action-buttons="scope">
<el-button
link
type="primary"
size="mini"
@click.prevent="viewRow(scope)"
>
查看
</el-button>
<el-button
link
type="primary"
size="mini"
@click.prevent="editRow(scope)"
>
编辑
</el-button>
<el-button
link
type="primary"
size="mini"
@click.prevent="deleteRow(scope)"
>
删除
</el-button>
</template>
</Tables>
</div>
</div>
</div>
</template>
<script>
import SearchCondition from '@/Tcomponents/SearchCondition.vue'
import Header from '@/Tcomponents/Header.vue'
import Tables from '@/Tcomponents/Tables2.vue'
import { WeeklyReportReq } from '@/api/methods'
import { columns } from './options/column'
import { formItemList } from './options/formItemList'
export default {
data() {
return {
/********* Header 组件 - start ***********/
title: '测试页面',
inputType: 'input',
inputPlaceholder: '请输入内容',
selectPlaceholder: '请选择内容',
// inputType 是 select 的时候需要配置
options: [
{ label: '选项11', value: 'value11' },
{ label: '选项22', value: 'value22' },
{ label: '选项33', value: 'value33' },
// 添加更多选项...
],
/********* Header 组件 - end ***********/
/********* 高级查询组件 - start *********/
// 是否显示高级查询
isShowHSearch: false,
emitSearch: false,
// 查询组件的配置项
formItemList: formItemList,
/********* 高级查询组件 - end *********/
/********* 表格组件 - start *********/
tableData: [
{
createDate: '2023-08-08 15:22:25',
createID: 1,
creator: '超级管理员',
id: '868191e5-df45-446a-b759-2e38e1cac95c',
issue: '2',
name: '20230726153935新建 DOCX 文档',
size: '9KB',
},
{
createDate: '2023-08-08 15:22:25',
createID: 1,
creator: '超级管理员',
id: '868191e5-df45-446a-b759-2e38e1cac95c',
issue: '2',
name: '20230726153935新建 DOCX 文档',
size: '9KB',
},
{
createDate: '2023-08-08 15:22:25',
createID: 1,
creator: '超级管理员',
id: '868191e5-df45-446a-b759-2e38e1cac95c',
issue: '2',
name: '20230726153935新建 DOCX 文档',
size: '9KB',
},
{
createDate: '2023-08-08 15:22:25',
createID: 1,
creator: '超级管理员',
id: '868191e5-df45-446a-b759-2e38e1cac95c',
issue: '2',
name: '20230726153935新建 DOCX 文档',
size: '9KB',
},
],
columns: columns,
// multipleSelection: [],
currentPage: 1, // 当前页码
total: 20, // 总条数
pageSize: 10, // 每页的数据条数
tableHeight: null,
/********* 表格组件 - end *********/
}
},
components: { SearchCondition, Header, Tables },
computed: {},
mounted() {
this.getDomHeight()
this.getWeekList()
},
methods: {
// 查询
search() {
console.log('@点击查询=获取参数', this.$refs.Header.searchValue)
this.getWeekList()
},
// 高级查询(打开高级查询)
showHsearch() {
this.$refs.Header.searchValue = ''
this.isShowHSearch = !this.isShowHSearch
},
// 获取高级查询参数
hSearch(params) {
console.log('高级查询的参数', params)
},
// 高级查询里面的关闭
isShowHSearchFn() {
this.isShowHSearch = !this.isShowHSearch
},
// 动态获取表格的高度
getDomHeight() {
setTimeout(() => {
const content = document.querySelector('.content').offsetHeight
const footer = document.querySelector('.footer').offsetHeight
this.tableHeight = content - footer
}, 200)
},
viewRow(row) {
console.log('@viewRow', row)
},
editRow(row) {
console.log('@editRow', row)
},
deleteRow(row) {
console.log('@deleteRow', row)
},
// 测试 调用数据
async getWeekList() {
let params = {
pageindex: this.currentPage,
pagesize: this.pageSize,
name: this.$refs.Header.searchValue,
}
let res = await WeeklyReportReq(params)
res.data.data.forEach((item, index) => {
item.index = ++index
})
// this.tableData = res.data.data
// console.log('@this.tableData', this.tableData)
this.total = res.data.total
},
},
}
</script>
<style lang="less" scoped>
// @import '@/assets/css/page.less';
/* page.less */
.wrap {
height: calc(100vh - 95px);
width: 100%;
padding: 15px;
.content {
margin-top: 15px;
height: calc(100% - 50px);
position: relative;
.footer {
position: absolute;
right: 0;
padding-top: 15px;
font-size: 14px;
width: 100%;
line-height: 2.25rem;
display: flex;
justify-content: flex-end;
.demonstration {
margin-right: 0.625rem;
}
/deep/ .el-pagination {
padding-top: 5px;
line-height: 30px;
}
}
}
}
</style>