<template>
<div class="query query-page">
<a-form :form="form" layout="inline" class="top-filter" hideRequiredMark v-show="showToolbox">
<a-form-item v-for="item in searchItems" :key="item.id" :label="item.label">
<a-input
v-if="item.type == 'text'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:placeholder="item.placeholder"
:allowClear="item.allowClear"
:model="parameter[item.id]"
:style="item.style"
/>
<a-input
v-if="item.type == 'hidetext'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:model="parameter[item.id]"
v-show="false"
/>
<a-select
:style="item.width ? `width:${item.width}px` : item.mode === 'multiple' ? 'width:300px' : 'width:144px'"
v-if="item.type == 'select'"
:mode="item.mode || 'default'"
:model="parameter[item.id]"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:select="item.onSelected"
@change="item.onChange"
:allowClear="item.allowClear"
:maxTagCount="item.maxTagCount ? item.maxTagCount : 2"
:showArrow="true"
>
<a-select-option v-for="opt in item.data" :key="opt.label" :value="opt.value">{{ opt.label }}</a-select-option>
</a-select>
<district-calc-type-select
v-if="item.type == 'districtcalctypeselect'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
@onIsEmpty="hideFormItem(item.id)"
></district-calc-type-select>
<a-date-picker
v-if="item.type == 'yeardatepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
mode="year"
:format="item.format"
:style="item.style"
:open="dateOpen"
@openChange="openChange"
@panelChange="(value) => yearChange(value, item)"
>
<a-icon type="calendar" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
<div style="text-align: right" slot="renderExtraFooter">
<a-button size="small" type="primary" @click="dateOpen = false">确定</a-button>
</div>
</a-date-picker>
<a-date-picker
v-if="item.type == 'datepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
:show-time="item.showTime"
:style="item.style"
>
<a-icon v-if="item.showTime" type="clock-circle" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
</a-date-picker>
<a-month-picker
dropdownClassName="quarter-selecter"
v-if="item.type == 'quarterselecter'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="'YYYY年第Q季度'"
:style="item.style"
placeholder="请选择季度"
@change="(value) => singleQuarter(value, item)"
>
<!-- <div slot="monthCellContentRender" slot-scope="mode">
{{ formatQuarter(mode, 2) }}
</div>-->
</a-month-picker>
<a-range-picker
dropdownClassName="quarter-selecter"
v-if="item.type == 'quarterrangeselecter'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="'YYYY年第Q季度'"
:style="item.style"
:mode="['month', 'month']"
:placeholder="['请选择季度', '请选择季度']"
@panelChange="(value) => quarterChange(value, item)"
></a-range-picker>
<a-month-picker
v-if="item.type == 'monthdatepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
:style="item.style"
/>
<a-week-picker
v-if="item.type == 'weekdatepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
:style="item.style"
/>
<a-radio-group
v-if="item.type == 'radiobutton'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:mode="parameter[item.id]"
buttonStyle="solid"
:name="item.id"
@change="item.change"
>
<a-radio-button v-for="opt in item.data" :key="opt.label" :value="opt.value">
{{ opt.label.replace(')', ')').replace('(', '(') }}
</a-radio-button>
</a-radio-group>
<a-range-picker
v-if="item.type === 'rangepicker' && item.format === 'YYYY-MM-DD'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
:ranges="dayRange"
:disabled-date="disabledDate"
style="width: 200px"
>
<a-icon type="calendar" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
</a-range-picker>
<a-range-picker
v-else-if="item.type === 'rangepicker' && item.format.indexOf('YYYY-MM-DD H') !== -1"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
:ranges="hourRange"
:showTime="item.showTime"
:disabled-date="disabledDate"
:inputReadOnly="true"
style="width: 270px; min-width: auto"
>
<a-icon type="clock-circle" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
</a-range-picker>
<a-range-picker
v-if="item.type === 'monthrangepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:format="item.format"
style="width: 200px"
:mode="['month', 'month']"
@panelChange="(value) => monthChange(value, item)"
>
<a-icon type="clock-circle" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
</a-range-picker>
<a-range-picker
v-if="item.type === 'yearrangepicker'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
style="width: 170px"
:format="item.format"
:mode="['year', 'year']"
dropdownClassName="notimebtn"
showTime
@panelChange="(value) => yearChange(value, item)"
>
<a-icon type="clock-circle" slot="suffixIcon" style="color: rgba(0, 0, 0, 0.65)" />
</a-range-picker>
<district-station-select
v-if="item.type === 'districtstationselect'"
v-decorator="[item.id, { rules: item.rules }]"
:defaultValue="item.value"
@onLoad="query"
></district-station-select>
<station-select
v-if="item.type === 'stationselect'"
v-decorator="[item.id, { rules: item.rules }]"
:defaultValue="item.value"
@onLoad="query"
></station-select>
<district-select
v-if="item.type === 'districtselect'"
v-decorator="[item.id, { rules: item.rules }]"
:listSize="{ width: 600, height: 400 }"
:initialValue="item.value"
:syncId="item.syncId"
:useDefaultValue="item.useDefaultValue"
@onLoad="query"
></district-select>
<city-station-select
v-if="item.type === 'citystationselect'"
v-decorator="[item.id, { rules: item.rules }]"
:listSize="{ width: 600, height: 400 }"
:styles="`width: 200px;`"
:syncId="item.syncId"
:initialValue="item.value"
:defaultAll="item.defaultAll"
:stationTypeSelectTab="item.stationTypeSelectTab"
:hideOthersStationTypeTab="item.hideOthersStationTypeTab"
:useDefaultStationType="item.useDefaultStationType"
@onLoad="query"
></city-station-select>
<opa-city-station-select
v-if="item.type === 'opacitystationselect'"
v-decorator="[item.id, { rules: item.rules }]"
:listSize="{ width: 600, height: 400 }"
:styles="`width: 200px;`"
:syncId="item.syncId"
:initialValue="item.value"
:defaultAll="item.defaultAll"
:stationTypeSelectTab="item.stationTypeSelectTab"
:hideOthersStationTypeTab="item.hideOthersStationTypeTab"
:useDefaultStationType="item.useDefaultStationType"
@onLoad="query"
></opa-city-station-select>
<pollutant-select
v-if="item.type === 'pollutantselect'"
v-decorator="[item.id, { rules: item.rules }]"
:listSize="{ width: 600, height: 400 }"
:styles="`width: 200px;`"
:defaultType="item.defaultType"
:initialValue="item.value"
@change="item.ok"
@onLoad="query"
></pollutant-select>
<department-select
v-if="item.type === 'departmentselect'"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
></department-select>
<a-select
v-if="item.type == 'searchSelect'"
show-search
:allowClear="true"
option-filter-prop="children"
v-decorator="[item.id, { rules: item.rules, initialValue: item.value }]"
:filter-option="item.filterOption ? item.filterOption : filterOption"
style="width: 250px"
:disabled="item.disabled || false"
@focus="item.focus"
@blur="item.blur"
@change="item.change"
>
<a-select-option v-for="opt in item.data" :key="opt.label" :value="opt.value">{{ opt.label }}</a-select-option>
</a-select>
<city-select
v-if="item.type === 'cityselect'"
v-decorator="[item.id, { rules: item.rules }]"
:listSize="{ width: 600, height: 400 }"
:styles="`width: 200px;`"
:initialValue="item.value"
@onLoad="query"
></city-select>
<drop-select
v-if="item.type === 'dropdownselect'"
v-decorator="[item.id, { rules: item.rules }]"
:defaultValue="item.value"
:level="item.level"
:multiple="item.multiple"
></drop-select>
</a-form-item>
<a-form-item>
<a-popconfirm
v-if="loading"
title="正在查询中,是否重新查询"
ok-text="是"
cancel-text="否"
@confirm="confirm"
@cancel="cancel"
>
<a-button type="primary" style="margin-right: 5px">
查询
<a-icon type="search" />
</a-button>
</a-popconfirm>
<a-button v-else type="primary" style="margin-right: 5px" @click="search">
查询
<a-icon type="search" />
</a-button>
<a-button v-if="showExport" @click="exportExcel" :disabled="loading">
导出Excel
<a-icon type="file-excel" />
</a-button>
</a-form-item>
<slot name="button"></slot>
<a-form-item>
<my-timer class="refreshTimer" v-if="showTimer" :refreshSecond="refreshSecond" :query="query"></my-timer>
</a-form-item>
</a-form>
<div style="margin: 0 8px 8px" v-if="$slots.tip">
<slot name="tip"></slot>
</div>
<full-table @resize="tableSize">
<template v-slot:table>
<div ref="table">
<a-table
v-if="showTable"
:rowKey="rowKey"
bordered
:columns="widthFullColumns"
:dataSource="loadData"
:pagination="
isMemoryPaging
? {
class: 'ant-table-pagination',
pageSizeOptions: pageSizeOptions,
pageSize: pageSize,
showTotal: showTotal,
showSizeChanger: true
}
: false
"
:loading="loading"
:scroll="{ x: 500, y: loadData.length > 0 ? tableHeight : false }"
@change="onTableChange"
>
<span slot="serial" slot-scope="text, record, index">{{ index + 1 }}</span>
</a-table>
</div>
</template>
<template v-slot:page>
<a-pagination
v-if="showTable && !isMemoryPaging"
class="ant-table-pagination"
showSizeChanger
:total="total"
:pageSize="pageSize"
:pageSizeOptions="pageSizeOptions"
:showTotal="showTotal"
:current="currentPage"
:disabled="loading"
@change="pageChanged"
@showSizeChange="showSizeChange"
></a-pagination>
</template>
</full-table>
</div>
</template>
<script>
import { axios } from '../../utils/request'
import { exportExcel } from '@/components/ExcelExport'
import StationSelect from '@/components/StationSelect/StationSelect'
import DistrictSelect from '@/components/Selector/DistrictSelect'
import CitySelect from '@/components/Selector/CitySelect'
import DropSelect from '@/components/StationSelect/DropDownSelect'
import DistrictStationSelect from '@/components/StationSelect/DistrictStationSelect'
import CityStationSelect from '@/components/Selector/CityStationSelect'
import PollutantSelect from '@/components/Selector/PollutantSelect'
import FullTable from '@/components/Networking/FullTable'
import { formtTableColums } from '@/utils/formatTabelColums'
import DistrictCalcTypeSelect from '@/components/Selector/DistrictCalcTypeSelect'
import MyTimer from '@/components/tools/Timer'
import DepartmentSelect from '@/components/OperationBasic/DepartmentSelect'
import OpaCityStationSelect from '@/components/Selector/OpaCityStationSelect'
// import store from '@suncereltd/suncere-sys/src/store'
import moment from 'moment'
export default {
name: 'DataQuery',
components: {
StationSelect,
DistrictSelect,
CitySelect,
DistrictStationSelect,
CityStationSelect,
DropSelect,
FullTable,
PollutantSelect,
DistrictCalcTypeSelect,
MyTimer,
DepartmentSelect,
OpaCityStationSelect
},
props: {
// 是否内存分页
isMemoryPaging: {
type: Boolean,
default() {
return false
}
},
// 显示序号
showSerial: {
type: Boolean,
default() {
return false
}
},
// 列头
columns: {
type: Array,
default() {
return [{ title: 'ID', dataIndex: 'id', key: 'id', sorter: true }]
}
},
// 查询条件
searchItems: {
type: Array,
default() {
return []
}
},
// 主键名
rowKey: {
type: String,
default() {
return 'id'
}
},
// 查询URL
searchUrl: {
type: String,
default: ''
},
// 导出
report: {
type: Object,
default: null
},
pageSizeOptions: {
type: Array,
default() {
return ['20', '30', '40', '50']
}
},
pageSize: {
type: Number,
default: 20
},
parameter: {
type: Object,
default: () => {
return {
skipCount: 0,
maxResultCount: 20
}
}
},
showTable: {
type: Boolean,
default: () => {
return true
}
},
showExport: {
type: Boolean,
default: () => {
return true
}
},
showTimer: {
type: Boolean,
default: () => {
return false
}
},
refreshSecond: {
type: Number,
default: 300
},
createOrUpdate: {
type: Boolean,
default() {
return true
}
},
validateFieldsSuccess: {
type: Function,
default: null
},
// 查询前特殊处理
// eslint-disable-next-line vue/require-default-prop
beforeQuery: {
type: Function
},
// 查询后特殊处理
// eslint-disable-next-line vue/require-default-prop
afterQuery: {
type: Function
},
usePostQuery: {
// 使用post查询,针对请求url过长情况
type: Boolean
},
showToolbox: {
type: Boolean,
default() {
return true
}
}
},
data() {
const hDate = moment(moment().format('YYYY-MM-DD HH:00:00'))
const dDate = moment(moment().format('YYYY-MM-DD'))
return {
dateOpen: false,
hourRange: {
最近一周: [hDate.clone().subtract('week', 1), hDate],
最近一个月: [hDate.clone().subtract('month', 1), hDate],
最近三个月: [hDate.clone().subtract('month', 3), hDate]
},
dayRange: {
最近一周: [dDate.clone().subtract('week', 1), dDate],
最近一个月: [dDate.clone().subtract('month', 1), dDate],
最近三个月: [dDate.clone().subtract('month', 3), dDate]
},
tableHeight: 200,
total: 0,
loadData: [],
pageIndex: 0,
skipCount: 0,
currentPage: 0,
// pageSize: 20,
// pageSizeOptions: ['20', '30', '40', '50'],
loading: false,
form: this.$form.createForm(this, { name: 'search' }),
widthFullColumns: [{ title: 'ID', dataIndex: 'id', key: 'id', sorter: true }],
requestCancel: null,
currentDataSource: []
}
},
computed: {
showTotal: () => {
return (total) => `总共 ${total} 条`
},
// currentPage: function() {
// return this.skipCount + 1
// },
oprationColumns: function () {
let optColumn = []
if (this.showSerial) {
optColumn.push({
title: '序号',
scopedSlots: { customRender: 'serial' }
})
optColumn = optColumn.concat(this.columns)
} else {
optColumn = this.columns
}
return optColumn
}
},
mounted() {
this.setDefaultValue()
this.loading = false
// 如果配置站点、区县、城市选择器,并且赋予初始值,则页面加载完成即执行查询
const selectors = ['cityselect', 'opacitystationselect', 'citystationselect', 'districtselect']
const selectoritem = this.searchItems.filter((d) => selectors.indexOf(d.type) > -1)
if (!(selectoritem.length > 0 && !selectoritem[0].value)) {
this.searchUrl && this.search()
}
this.setMinTable()
// 页面加载时重新分配表格宽度
this.$nextTick(() => {
const fixeds = this.oprationColumns.filter((d) => d.fixed && (d.fixed === 'left' || d.fixed === 'right'))
if (fixeds.length > 0) {
this.widthFullColumns = formtTableColums(this.oprationColumns)
} else {
this.widthFullColumns = this.oprationColumns
}
})
const self = this
window.addEventListener('resize', function () {
const fixeds = self.oprationColumns.filter((d) => d.fixed && (d.fixed === 'left' || d.fixed === 'right'))
if (fixeds.length > 0) {
self.widthFullColumns = formtTableColums(self.oprationColumns)
} else {
self.widthFullColumns = self.oprationColumns
}
})
},
methods: {
openChange(data) {
this.dateOpen = data
},
// 季度格式化
formatQuarter(d, type) {
// const num = ['一', '二', '三', '四']
const year = d.year()
const quarter = d.quarter()
const text = type === 1 ? `${year}年第${quarter}季度` : `第${quarter}季度`
return text
},
changeValue(value, item) {
this.form.setFieldsValue({
[item.id]: value
})
},
// 获取表头有多少层
getHeightCount() {
let count = 0
const columns = this.widthFullColumns
let children = []
let temp = []
do {
if (count === 0) {
temp = columns
} else {
temp = children
}
children = []
temp.forEach((e) => {
if (e.children && e.children.length > 0) {
children = children.concat(e.children)
}
})
count++
} while (children.length > 0)
return count
},
tableSize(size) {
this.$nextTick(() => {
console.log('表头有多少层', this.getHeightCount())
const headHeight = 40 * this.getHeightCount()
let tableHeight = size - headHeight - 5
if (this.isMemoryPaging) {
tableHeight = tableHeight - 65
}
this.tableHeight = tableHeight
this.setMinTable()
})
},
onTimeTypeChange(e) {
this.$emit('onTimeTypeChange', e, this.form)
},
// select默认值
setDefaultValue() {
if (this.searchItems && this.searchItems.length > 0) {
this.searchItems.forEach((item, i) => {
if (
(item.type === 'select' ||
item.type === 'cityselect' ||
item.type === 'citystationselect' ||
item.type === 'opacitystationselect' ||
item.type === 'pollutantselect') &&
item.value
) {
this.form.setFieldsValue({
[item.id]: item.value
})
}
})
}
},
// moment值转换
convertMomentType(values, searchItems) {
const defaultFormatStr = 'YYYY-MM-DD HH:mm:ss'
const data = {}
for (const k in values) {
let v = values[k]
if (v !== undefined && v !== null) {
if (Array.isArray(v)) {
data[k] = [...v]
v = v.map((m, i) => {
if (m instanceof moment) {
data[k][i] = m.format(defaultFormatStr)
}
})
} else {
if (v instanceof moment) {
// 针对时间点选择器,先根据格式化字段生成后面为0的moment
const _item = searchItems.find((x) => x.id === k)
if (_item) {
const _formatStr = _item.format
if (_formatStr) {
const newMoment = moment(v.format(_formatStr), _formatStr)
data[k] = newMoment.format(defaultFormatStr)
} else {
data[k] = v.format(defaultFormatStr)
}
} else {
data[k] = v.format(defaultFormatStr)
}
} else {
data[k] = v
}
}
}
}
return data
},
init() {
this.total = 0
this.loadData = []
this.skipCount = 0
this.currentPage = 1
this.parameter.skipCount = 0
},
search() {
this.init()
this.query()
},
// 表格查找修改下标
formatTableData(data) {
return data.map((item) => {
const res = {}
for (const key in item) {
if (typeof item[key] == 'string') {
res[key] = this.formatPollutantSub(item[key])
} else {
res[key] = item[key]
}
}
return res
})
},
formatPollutantSub(str) {
return str
.replace(/PM2_5/gi, 'PM₂.₅')
.replace(/PM2.5/gi, 'PM₂.₅')
.replace(/PM10/gi, 'PM₁₀')
.replace(/O3/gi, 'O₃')
.replace(/SO2/gi, 'SO₂')
.replace(/NO2/gi, 'NO₂')
},
filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
},
query() {
const self = this
self.form.validateFields((err, values) => {
if (err) {
return
}
if (this.beforeQuery) {
values = this.beforeQuery(values)
if(values === 'ywfalse'){
this.$message.error('选择时间不能超过3个月!')
return
}
}
$('.ant-table-body').scrollLeft(0)
self.loading = true
if (self.validateFieldsSuccess && typeof self.validateFieldsSuccess === 'function') {
self.validateFieldsSuccess(values)
}
const formData = self.convertMomentType(values, self.searchItems)
self.params = { ...self.parameter, ...formData }
if (self.requestCancel && typeof self.requestCancel === 'function') {
self.requestCancel('取消上一次清求')
}
if (self.usePostQuery) {
axios
.postData(self.searchUrl, self.params)
.then((res) => {
self.loading = false
if (this.afterQuery) {
res = this.afterQuery(res)
}
self.total = res.result.totalCount
self.loadData = self.formatTableData(res.result.items)
self.currentDataSource = self.loadData
self.$emit('search', res.result.items)
})
.catch((err) => {
self.loading = false
self.total = 0
self.loadData = []
self.currentDataSource = self.loadData
this.parameter.skipCount = 0
})
} else {
axios
.getData(self.searchUrl, self.params)
.then((res) => {
if (this.afterQuery) {
res = this.afterQuery(res)
}
self.total = res.result.totalCount
self.loadData = self.formatTableData(res.result.items)
self.currentDataSource = self.loadData
self.loading = false
self.$emit('search', res.result.items)
})
.catch((err) => {
if (self.$axios.isCancel(err)) {
console.log('Request canceled', err.message)
} else {
// 处理错误
console.log(err)
self.total = 0
self.loadData = []
self.currentDataSource = self.loadData
this.parameter.skipCount = 0
self.loading = false
}
})
}
})
},
// 点击分页
pageChanged(page, pageSize) {
this.currentPage = page
this.skipCount = (page - 1) * pageSize
this.parameter.skipCount = this.skipCount
this.query()
},
// 单页大小改变
showSizeChange(current, pageSize) {
this.pageSize = pageSize
this.currentPage = 1
this.skipCount = 0
this.parameter.skipCount = 0
this.parameter.maxResultCount = this.pageSize
this.query()
},
// 按列排序
onTableChange(pagination, filters, sorter, obj) {
// 后台第一次加载需要排序
this.parameter.columnKey = sorter.columnKey
this.parameter.order = sorter.order
if (this.isMemoryPaging) {
const { currentDataSource } = obj
this.currentDataSource = currentDataSource
return
}
this.parameter.sorting = sorter.field
this.parameter.ascending = sorter.order === 'ascend'
this.query()
},
exportExcel() {
if (this.total === 0) {
this.$message.info('无数据可导出')
return
}
const header = this.columns.map((column) => {
if (column.children) {
column.children.forEach((c) => {
c.render = c.exportRender ? c.exportRender : c.customRender
})
}
return {
k: column.key || column.dataIndex,
v: column.reportTitle || column.title,
render: column.exportRender ? column.exportRender : column.customRender,
children: column.children
}
})
//正常导出不应该使用分页接口,历史遗留问题
const params = { ...this.params, skipCount: 0, maxResultCount: this.total > 1000 ? 1000 : this.total }
// 默认导出文件名称
let reportName = `${this.$route.meta.title}.xlsx`
if (this.report) {
if (this.report.name) {
if (typeof this.report.name === 'function') {
reportName = this.report.name(params)
} else {
reportName = this.report.name
}
}
if (this.report.url) {
this.loading = true
if (this.usePostQuery) {
axios
.postData(this.report.url, params)
.then((res) => {
if (res.result.items) {
// 调用了分页接口
exportExcel(header, res.result.items, reportName)
} else {
exportExcel(header, res.result, reportName)
}
this.loading = false
})
.catch(() => {
this.loading = false
})
} else {
axios
.getData(this.report.url, params)
.then((res) => {
if (res.result.items) {
// 调用了分页接口
exportExcel(header, res.result.items, reportName)
} else {
exportExcel(header, res.result, reportName)
}
this.loading = false
})
.catch(() => {
this.loading = false
})
}
} else {
exportExcel(header, this.currentDataSource, reportName)
}
}
},
setMinTable() {
const MIN_ITEM = 10
// 监听表格数据,表格数据少于MIN_ITEM时撑高表格
if (this.loadData.length < MIN_ITEM && this.loadData.length > 0) {
this.$nextTick(() => {
this.$refs.table.getElementsByClassName('ant-table-body')[0].style.minHeight = this.tableHeight + 'px'
})
} else {
this.$refs.table.getElementsByClassName('ant-table-body')[0].style.minHeight = 'none'
}
},
singleQuarter(value, item) {
this.form.setFieldsValue({
[item.id]: value.startOf('quarter')
})
},
quarterChange(value, item) {
this.form.setFieldsValue({
[item.id]: [value[0].startOf('quarter'), value[1].startOf('quarter')]
})
},
monthChange(value, item) {
this.form.setFieldsValue({
[item.id]: value
})
},
yearChange(value, item) {
this.form.setFieldsValue({
[item.id]: value
})
},
disabledDate(current) {
// 相关链接:https://3x.ant.design/docs/react/faq-cn#%E5%BD%93%E6%88%91%E6%8C%87%E5%AE%9A%E4%BA%86-DatePicker/RangePicker-%E7%9A%84-mode-%E5%B1%9E%E6%80%A7%E5%90%8E%EF%BC%8C%E7%82%B9%E5%87%BB%E5%90%8E%E6%97%A0%E6%B3%95%E9%80%89%E6%8B%A9%E5%B9%B4%E4%BB%BD/%E6%9C%88%E4%BB%BD%EF%BC%9F
// 这是因为 <DatePicker mode="year" /> 不等于 YearPicker,<RangePicker mode="month" /> 不等于 MonthRangePicker。 mode 属性是在 antd 3.0 时,为了控制面板展现状态而添加的属性,以支持展示时间面板等需求而添加的。mode 只会简单的改变当前显示的面板,不会修改默认的交互行为(比如 DatePicker 依然是点击日才会完成选择并关闭面板)。
return current && current > moment().endOf('day')
},
confirm() {
this.search()
},
cancel() {},
hideFormItem(id) {
this.searchItems = this.searchItems.filter((key) => key.id !== id)
},
pickerConfirm(data) {
console.log(data)
}
},
watch: {
tableHeight(data) {
this.setMinTable()
},
total() {
this.currentPage = 1
this.skipCount = 0
},
loadData() {
this.setMinTable()
},
oprationColumns(columns) {
this.$nextTick(() => {
const fixeds = columns.filter((d) => d.fixed && (d.fixed === 'left' || d.fixed === 'right'))
if (fixeds.length > 0) {
this.widthFullColumns = formtTableColums(columns)
} else {
this.widthFullColumns = columns
}
})
}
}
}
</script>
<style lang="less">
.query-page .ant-select-selection--multiple .ant-select-selection__choice__content {
max-width: 50px;
width: 50px;
}
.query-page .ant-table-thead > tr > th {
padding: 8px 8px;
font-weight: bold;
text-align: center;
background: #deefff;
}
.query-page .ant-table-tbody > tr > td {
padding: 8px 8px;
text-align: center;
}
.refreshTimer {
line-height: 30px;
font-weight: bold;
}
</style>
<style lang="less">
.quarter-selecter {
.ant-calendar-month-panel-cell:nth-child(n + 2) {
display: none !important;
}
.ant-calendar-month-panel-month {
font-size: 0;
&::after {
display: inline-block;
font-size: 14px;
}
}
tr:nth-child(1) .ant-calendar-month-panel-month::after {
content: '第1季度';
}
tr:nth-child(2) .ant-calendar-month-panel-month::after {
content: '第2季度';
}
tr:nth-child(3) .ant-calendar-month-panel-month::after {
content: '第3季度';
}
tr:nth-child(4) .ant-calendar-month-panel-month::after {
content: '第4季度';
}
}
._full-table {
padding: 0 12px;
}
/************ 时间选择器提示信息下面显示 Begin */
.top-filter .has-error .ant-form-explain {
margin-top: -4px;
padding-left: 0px;
}
/************ 时间选择器提示信息下面显示 End */
</style>
<template>
<query
ref="query"
:showSerial="false"
:columns="columns"
:searchUrl="searchUrl"
:report="report"
:searchItems="searchItems"
:validateFieldsSuccess="beforeQuery"
></query>
</template>
<script>
// 基本布局
import BaseLayout from '@/components/Networking/BaseLayout'
// 表格布局
import Query from '@/components/Page/QueryPage'
// 时间格式
import moment from 'moment'
export default {
name: 'AuditRecords',
components: { Query, BaseLayout },
data() {
return {
columns: [
{
title: '城市',
dataIndex: 'cityName'
},
{
title: '区县',
dataIndex: 'districtName'
},
{
title: '站点',
dataIndex: 'positionName'
},
{
title: '唯一编码',
dataIndex: 'uniqueCode'
},
{
title: '监测时间',
dataIndex: 'timePoint',
customRender: (v) => moment(v).format(this.$datefmt.hour)
},
{
title: '监测物',
dataIndex: 'pollutantName'
},
{
title: '审核类型',
dataIndex: 'auditType'
},
{
title: '操作人',
dataIndex: 'operator'
},
{
title: '审核操作',
dataIndex: 'operateDesc'
},
{
title: '审核时间',
width: 200,
dataIndex: 'operateTime',
customRender: (v) => moment(v).format(this.$datefmt.second)
},
{
title: '审核前',
dataIndex: 'beforeValue',
customRender: (v, row) => (row.beforeMark === '' ? v : v + `(${row.beforeMark})`)
},
{
title: '审核后',
dataIndex: 'afterValue',
customRender: (v, row) => (row.afterMark === '' ? v : v + `(${row.afterMark})`)
},
{
title: '审核描述',
dataIndex: 'auditDesc'
}
// ,
// {
// title: '备注',
// dataIndex: 'remarks'
// }
],
searchItems: [
{
label: '站点',
id: 'StationCode',
type: 'citystationselect',
rules: [{ required: true, message: '请选择站点!' }],
stationTypeSelectTab: ['2','3','4','5','6','7','8'],
hideOthersStationTypeTab: true
},
{
id: 'TimePoint',
type: 'rangepicker',
label: '时间',
format: 'YYYY-MM-DD',
rules: [{ required: true, message: '时间不能为空!' }],
value: [moment(moment().add(-1, 'days').format('YYYY-MM-DD')), moment(moment().format('YYYY-MM-DD'))]
}
// ,
// {
// id: 'StateCode',
// type: 'select',
// label: '审核状态',
// value: '',
// data: [
// { label: '全部', value: '' },
// { label: '待审核', value: 'WaitAudit' },
// { label: '待上报', value: 'WaitUpload' },
// { label: '待复核', value: 'WaitReview' },
// { label: '已复核', value: 'Reviewed' },
// { label: '已直审', value: 'DirectAudit' }
// ]
// }
],
searchUrl: 'airprovinceproduct/audit/AirCityDataAudit/GetAuditDatasLogsAsync',
report: {
url: 'airprovinceproduct/audit/AirCityDataAudit/GetAuditDatasLogsListAsync',
name: (v) => {
return this.exportName(v)
}
}
}
},
methods: {
moment,
beforeQuery(values) {
values.StartTime = moment(values.TimePoint[0]).format('YYYY-MM-DD')
values.EndTime = moment(values.TimePoint[1]).format('YYYY-MM-DD 23:59:59')
return values
},
exportName(values) {
return `审核记录[${values.StartTime}至${values.EndTime}].xlsx`
}
}
}
</script>
前端框架 VUE + suncere-ui ( Vue.js 2.6.14 的前端 UI 组件库,在 ant-vue-design 1.7.8 UI框架基础上 进行二次开发)
请根据给出的前端页面写出 乡镇站审核记录 页面,
页面内容
查询条件: 站点选择器,日期选择, 地方审核状态(全部、待审核、已审核) 选择 监测项 (默认为 空,SO₂、 NO₂、CO、O₃、PM₂.₅、PM₁₀、NO、NOx)选择
按钮:查询 前一天 后一天 点击前一天日期选择前一天 立刻查询 点击后一天日期选择前一天 立刻查询
table表格
字段如下:
地方审核状态 、站点名称、时间点(格式:8月15日)、监测项、原始值、审核值、操作、地方审核人员、地方审核意见、省站审核人员、省站审核意见