| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- <?php
- use common\helpers\ComponentHelper;
- ComponentHelper::loadComponentView('components/range-input');
- ?>
- <template id="com-list-table">
- <div class="content">
- <div class="header">
- <div class="left-panel">
- <slot name="header-left"></slot>
- </div>
- <div class="right-panel">
- <slot name="header-right">
- <div class="header-right-input">
- <slot name="custom-search"></slot>
- <template v-for="(item, index) in getOutSearch()">
- <el-input
- v-if="isTextInput(item)"
- size="mini"
- :placeholder="item.placeholder ?? item.title"
- v-model="searchParams[item.key]"
- :clearable="item.clearable ?? false"
- ></el-input>
- <el-select
- v-if="isSelectInput(item)"
- size="mini"
- :placeholder="item.placeholder ?? item.title"
- v-model="searchParams[item.key]"
- @change="(val) => selectChange(item.key, val)"
- :clearable="item.clearable ?? false"
- >
- <el-option
- v-for="(i, key) in item.options"
- :key="key"
- :label="getOptionLabel(item, i)"
- :value="getOptionValue(item, i)"
- >
- </el-option>
- </el-select>
- <el-time-picker
- v-if="isTimePickerInput(item)"
- size="mini"
- v-model="searchParams[item.key]"
- is-range
- range-separator="至"
- start-placeholder="开始时间"
- end-placeholder="结束时间"
- placeholder="选择时间范围"
- :value-format="item.valueFormat ? item.valueFormat : 'HH:mm:ss'"
- :clearable="item.clearable ?? false"
- >
- </el-time-picker>
- <el-date-picker
- v-if="isDatePickerInput(item)"
- size="mini"
- v-model="searchParams[item.key]"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :value-format="item.valueFormat ? item.valueFormat : 'yyyy-MM-dd'"
- :picker-options="item.pickerOptions ?? {}"
- :clearable="item.clearable ?? false"
- >
- </el-date-picker>
- <el-date-picker
- v-if="isDateTimeRangeInput(item)"
- size="mini"
- type="datetimerange"
- v-model="searchParams[item.key]"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :default-time="item.defaultTime ?? ['00:00:00', '00:00:00']"
- :picker-options="item.pickerOptions ?? {}"
- :clearable="item.clearable ?? false"
- >
- </el-date-picker>
- <el-cascader
- v-if="isCascader(item)"
- size="mini"
- v-model="searchParams[item.key]"
- :options="item.options"
- :props="item.props"
- :placeholder="item.title"
- clearable
- collapse-tags
- :clearable="item.clearable ?? false"
- >
- </el-cascader>
- <el-date-picker
- size="mini"
- v-if="isMonthRange(item)"
- v-model="searchParams[item.key]"
- type="monthrange"
- :value-format="item.valueFormat ? item.valueFormat : 'yyyy-MM'"
- :range-separator="item.rangeSeparator ?? '至'"
- :start-placeholder="item.startPlaceholder ?? '开始月份'"
- :end-placeholder="item.endPlaceholder ?? '结束月份'">
- </el-date-picker>
- <el-date-picker
- size="mini"
- v-if="isMonth(item)"
- v-model="searchParams[item.key]"
- :value-format="item.valueFormat ? item.valueFormat : 'yyyy-MM'"
- placeholder="选择月"
- type="month">
- </el-date-picker>
- </template>
- </div>
- <el-button size="mini" type="primary" icon="el-icon-search" @click="handleSearch" v-if="isOnSearch()"></el-button>
- <el-button size="mini" icon="el-icon-refresh" @click="handleSearchRefresh" v-if="isOnSearch()"></el-button>
- <el-popover
- placement="bottom-end"
- trigger="click"
- v-model="povpoerShow"
- v-if="getOnSearch().length"
- >
- <el-button slot="reference" type="text">
- 更多筛选<i class="el-icon-arrow-down"></i>
- </el-button>
- <el-form class="pop-form" ref="search" :model="searchParams" :label-width="labelWidth" size="mini">
- <slot name="custom-search-popover"></slot>
- <el-form-item :label="item.title" v-for="(item, index) in getOnSearch()" :key="index">
- <el-input
- v-if="isTextInput(item)"
- size="mini"
- :placeholder="item.placeholder ?? item.title"
- v-model="searchParams[item.key]"
- :clearable="item.clearable ?? false"
- ></el-input>
- <range-input
- v-if="isRangeInput(item)"
- v-model="searchParams[item.key]"
- :start-placeholder="item.startPlaceholder"
- :end-placeholder="item.endPlaceholder"
- :append-text="item.appendText"
- :separator="item.separator"
- ></range-input>
- <el-select
- v-if="isSelectInput(item)"
- size="mini"
- :placeholder="item.placeholder ?? item.title"
- v-model="searchParams[item.key]"
- @change="(val) => selectChange(item.key, val)"
- :clearable="item.clearable ?? false"
- >
- <el-option
- v-for="(i, key) in item.options"
- :key="key"
- :label="getOptionLabel(item, i)"
- :value="getOptionValue(item, i)"
- >
- </el-option>
- </el-select>
- <el-time-picker
- v-if="isTimePickerInput(item)"
- size="mini"
- v-model="searchParams[item.key]"
- is-range
- range-separator="至"
- start-placeholder="开始时间"
- end-placeholder="结束时间"
- placeholder="选择时间范围"
- :value-format="item.valueFormat ? item.valueFormat : 'HH:mm:ss'"
- :clearable="item.clearable ?? false"
- >
- </el-time-picker>
- <el-date-picker
- v-if="isDatePickerInput(item)"
- size="mini"
- v-model="searchParams[item.key]"
- type="daterange"
- range-separator="至"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :value-format="item.valueFormat ? item.valueFormat : 'yyyy-MM-dd'"
- :picker-options="item.pickerOptions ?? {}"
- :clearable="item.clearable ?? false"
- >
- </el-date-picker>
- <el-date-picker
- v-if="isDateTimeRangeInput(item)"
- type="datetimerange"
- v-model="searchParams[item.key]"
- start-placeholder="开始日期"
- end-placeholder="结束日期"
- :default-time="item.defaultTime ?? ['00:00:00', '00:00:00']"
- :picker-options="item.pickerOptions ?? {}"
- :clearable="item.clearable ?? false"
- >
- </el-date-picker>
- <el-cascader
- v-if="isCascader(item)"
- v-model="searchParams[item.key]"
- :options="item.options"
- :props="item.props"
- :placeholder="item.placeholder ?? item.title"
- clearable
- collapse-tags
- :clearable="item.clearable ?? false"
- >
- </el-cascader>
- <el-date-picker
- size="mini"
- v-if="isMonthRange(item)"
- v-model="searchParams[item.key]"
- type="monthrange"
- :value-format="item.valueFormat ? item.valueFormat : 'yyyy-MM'"
- :range-separator="item.rangeSeparator ?? '至'"
- :start-placeholder="item.startPlaceholder ?? '开始月份'"
- :end-placeholder="item.endPlaceholder ?? '结束月份'">
- </el-date-picker>
- <el-date-picker
- size="mini"
- v-if="isMonth(item)"
- v-model="searchParams[item.key]"
- placeholder="选择月"
- type="month">
- </el-date-picker>
- </el-form-item>
- </el-form>
- </el-popover>
- </slot>
- </div>
- </div>
- <div class="statistics">
- <slot name="statistics"></slot>
- </div>
- <!-- tabs -->
- <el-tabs v-model="active" @tab-click="handleChangeTab" v-if="isTabs()">
- <el-tab-pane :label="item.label" :name="item.name" v-for="(item, index) in tabs" :key="index"></el-tab-pane>
- </el-tabs>
- <el-table
- :data="tableData"
- v-loading="loading"
- :size="size"
- :height="height=='auto' ? 'null' : '100%'"
- @selection-change="handleSelectionChange"
- :show-summary="showSummary"
- :summary-method='summaryMethod'
- :span-method="spanMethod"
- :row-key="rowKey"
- >
- <el-empty v-if="!hasList()" :description="emptyDesc" slot="empty"></el-empty>
- <template v-if="isUseTabsSlot()">
- <template v-for="(item, index) in tabs">
- <slot :name="'tab-' + item.name"></slot>
- </template>
- </template>
- <template v-else>
- <slot></slot>
- </template>
- </el-table>
- <slot name="footer">
- <div class="footer">
- <div class="footer-button">
- <slot name="footer-button"></slot>
- </div>
- <div class="footer-page" v-if="hasPagination()">
- <el-pagination
- @size-change="handleSizeChange"
- @current-change="pagination"
- background
- layout="total, prev, pager, next, sizes, jumper"
- :page-count="pageCount"
- :page-sizes="[20, 50, 100, 500, 1000]"
- :page-size="pageSize"
- :total="total"
- :current-page.sync="currentPage"
- ></el-pagination>
- </div>
- </div>
- </slot>
- </div>
- </template>
- <script>
- Vue.component('com-list-table', {
- template: '#com-list-table',
- props: {
- size: 'small',
- height: 'auto',
- emptyDesc: {
- type: String,
- default: '暂无内容',
- },
- labelWidth: { //筛选label宽度
- type: String,
- default: '80',
- },
- searchList: {
- type: Array,
- default: () => {
- return []
- },
- },
- data: {
- type: Array,
- default: () => {
- return []
- },
- },
- api: {
- type: String,
- default: '',
- },
- apiParams: {
- type: Object,
- default: () => {
- return {}
- },
- },
- tabs: {
- type: Array,
- default: () => {
- return []
- },
- },
- activeName: {
- type: String,
- default: '',
- },
- // 使用tabs插槽
- useTabsSlot: {
- type: Boolean,
- default: false,
- },
- // 请求前,校验请求数据,必须返回布尔
- listParamsVerifyFun: {
- type: Function,
- default: () => true
- },
- showSummary: {
- type: Boolean,
- default: false,
- },
- summaryMethod: {
- type: Function,
- default: () => {}
- },
- spanMethod: {
- type: Function,
- default: () => {}
- },
- // 设置row-key
- rowKey: {
- type: [Function, String, Number],
- default: null
- },
- usePagination: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- loading: false,
- total: 0,
- tableData: [],
- pageCount: 0,
- searchParams: {},
- povpoerShow: false,
- currentPage: 1,
- }
- },
- computed: {
- active: {
- set() {
- },
- get() {
- return this.activeName != ''
- ? this.activeName
- : this.tabs[0].name
- },
- },
- },
- /* watch: {
- searchParams: {
- handler(newVal, oldVal) {
- for (let key in oldVal) {
- if (this.getCascaderKey().includes(key)) {
- }
- }
- },
- deep: true,
- }
- }, */
- mounted() {
- if (this.getRequestParams({}, 1)) {
- this.getList()
- } else if (this.data) {
- this.tableData = this.data;
- this.total = this.tableData.length
- }
- },
- methods: {
- async getList(params = {}, page = 1) {
- if (!this.listParamsVerifyFun(params)) {
- return
- }
- this.loading = true
- request({
- params: this.getRequestParams(params, page),
- method: 'get',
- }).then(e => {
- this.loading = false;
- if (e.data.code == 0) {
- this.tableData = e.data.data.list
- if (this.hasPagination()) {
- this.pageCount = e.data.data.page_count
- this.total = e.data.data.row_count
- this.pageSize = e.data.data.page_size
- }
- this.$emit('get-api-data', e.data.data)
- } else {
- this.$message.error(e.data.msg)
- }
- }).catch(e => {
- this.loading = false
- this.$message.error(e.data.msg)
- })
- },
- handleSizeChange(val) {
- this.searchParams.limit = val
- this.getList(this.searchParams, 1)
- this.$emit('search', this.searchParams)
- },
- reload() {
- this.getList(this.searchParams, this.currentPage)
- },
- hasList() {
- return this.tableData.length > 0
- },
- hasPagination() {
- return this.usePagination && this.tableData.length > 0;
- },
- pagination(currentPage) {
- this.getList(this.searchParams, currentPage)
- },
- handleSelectionChange(val) {
- this.$emit('selection-change', val)
- },
- handleSearch() {
- // if (this.isOnSearch() > 0) {
- this.getList(this.searchParams, 1)
- this.$emit('search', this.searchParams)
- // } else {
- // this.$emit('search', this.searchParams)
- // }
- },
- getOutSearch() {
- return this.searchList.slice(0, 3)
- },
- getOnSearch() {
- return this.searchList.slice(3)
- },
- isOnSearch() {
- return this.searchList.length > 0
- },
- isTextInput(item) {
- return item.type == 'text' || item.type == '' || item.type == undefined
- },
- isRangeInput(item) {
- return item.type === 'range-input'
- },
- isSelectInput(item) {
- return item.type == 'select'
- },
- /**
- * @see https://element.eleme.io/#/zh-CN/component/time-picker
- */
- isTimePickerInput(item) {
- return item.type == 'time-picker'
- },
- /**
- * @see https://element.eleme.io/#/zh-CN/component/date-picker
- */
- isDatePickerInput(item) {
- return item.type == 'date-picker'
- },
- /**
- * @see https://element.eleme.io/#/zh-CN/component/datetime-picker
- */
- isDateTimeRangeInput(item) {
- return item.type == 'date-time-range'
- },
- /**
- * @see https://element.eleme.io/#/zh-CN/component/cascader
- */
- isCascader(item) {
- return item.type == 'cascader'
- },
- isMonthRange(item) {
- return item.type == 'monthrange'
- },
- isMonth(item) {
- return item.type == 'month'
- },
- getCascaderKey() {
- return this.searchList.filter((item) => {
- return this.isCascader(item)
- }).map((item) => {
- return item.key
- })
- },
- getOptionLabel(item, i) {
- return item.valueKey
- ? (
- item.valueKey.label
- ? i[item.valueKey.label]
- : i.label
- )
- : i.label
- },
- getOptionValue(item, i) {
- return item.valueKey
- ? (
- item.valueKey.value
- ? i[item.valueKey.value]
- : i.value
- )
- : i.value
- },
- getRequestParams(params, page) {
- if (this.api != '') {
- let basic = {
- r: this.api,
- page: page
- }
- return {...basic, ...params}
- }
- if (JSON.stringify(this.apiParams) != '{}') {
- return {...this.apiParams, ...params, page: page}
- }
- return false
- },
- handleSearchRefresh() {
- this.currentPage = 1
- this.searchParams = {}
- this.$emit('search-refresh', this.searchParams)
- this.getList(this.searchParams, this.currentPage)
- },
- isTabs() {
- return this.tabs && this.tabs.length > 0
- },
- isUseTabsSlot() {
- return this.isTabs && this.useTabsSlot
- },
- handleChangeTab(tab, event) {
- this.$emit('set-action-name', tab.name)
- },
- selectChange(itemKey, value) {
- this.$emit('select-change', itemKey, value)
- }
- }
- })
- </script>
- <style lang="scss" scoped>
- #application .header {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- }
- #application .left-panel, #application .right-panel {
- display: flex;
- justify-content: space-evenly;
- flex-direction: row;
- align-items: center;
- /* flex: 0.3; */
- }
- #application .header .left-panel > * + *, #application .header .right-panel > * + *, #application .header-right-input > * + * {
- margin-left: 5px;
- }
- #application .content {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- height: 100%;
- }
- #application .footer {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- /* margin-top: 10px; */
- align-items: center;
- }
- #application .el-table::before {
- height: 0;
- }
- #application .pop-form .el-form-item:last-child {
- margin-bottom: 0;
- }
- #application .right-panel .el-date-editor .el-range-separator {
- width: auto;
- }
- #application .header-right-input {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: flex-end;
- input {
- width: 200px;
- }
- .el-date-editor {
- width: 350px;
- }
- .el-date-editor--month {
- width:200px;
- }
- }
- </style>
|