表格组件
<script lang="tsx"> import { Component, Vue, Prop, Mixins, Watch } from 'vue-property-decorator'; import { Card, Row, Col, Button, Table, TableColumn } from 'element-ui'; import { TableColumnType } from 'element-ui/types/table-column'; import Pagination from '@/components/Pagination/index.vue'; import SearchAblePage from '@/lib/utils/mixin/searchable'; import cacheSearchQuery from '@/lib/utils/mixin/cacheSearchQuery'; import busEvent, { EventName } from '@/lib/utils/busEvent'; import commonHelper, { deepCopy } from '@/lib/utils/commonHelper'; const isChrome = window.navigator.userAgent.includes('Chrome'); const screenWidth = isChrome ? 0 : 17; // tslint: disable @Component({ components: { Pagination }, }) export default class CommonSearchPage extends Mixins(SearchAblePage, cacheSearchQuery) { @Prop({ required: true, type: Array, default: () => [] }) private columnFields!: any[]; @Prop({ required: true }) protected dataSearchApi!: string; @Prop({ required: true }) protected requestMethod!: string; @Prop({ default: 0 }) private addTopSpace!: number; @Prop({ default: 0 }) private addRightSpace!: number; @Prop({ default: false }) private parentLoading!: boolean; @Prop({ default: 20 }) private setPageSize!: number; @Prop({ default: () => {}, }) @Prop({ default: false }) private orderType!: boolean; private getData!: (data: any,pageQuery) => {}; @Watch('listLoading') loadingChangeHandle(newVal: boolean) { this.$emit('update:parentLoading', newVal); } render() { const { tableActionSection, searchSection, tableSection, manualFooter } = this.$scopedSlots; return ( <div class="app-container table-page"> <Card class="page-card"> <div class="scroll-container" id="scroll-container"> {searchSection && ( <Row class="hengxing-search-section"> {searchSection('')} <Col class="search-col change-btn-padding" span={2}> <Button type="primary" size="medium" icon="el-icon-search" onClick={this.search}> 搜索 </Button> <Button type="primary" size="medium" onClick={this.resetData}> 重置 </Button> </Col> </Row> )} <div class="kdd-table-action">{tableActionSection && tableActionSection('')}</div> {tableSection ? ( tableSection(this.tableDataList) ) : ( <Table v-loading={this.listLoading} header-cell-style={{ height: '58px' }} cell-style={{ height: '58px' }} data={this.tableDataList} fit highlight-current-row class="kdd-table" ref="kdd-table" on={{ 'sort-change': (data: any) => this.sortChangeHandle(data), }} > {this.columnFields.map((column) => ( <TableColumn align={column.align || 'center'} width={column.width} sortable={column.sortable ? 'custom' : false} label={column.title} min-width={column.minWidth} type={column.columnType} class-name={column.className} fixed={column.fixed} prop={column.key} scopedSlots={{ header: ({ row }) => column.renderHeader ? column.renderHeader(this.$createElement, row) : column.title, default: ({ row }) => column.render ? column.render(this.$createElement, row) : commonHelper.getDeepValue(row, column.key), }} ></TableColumn> ))} </Table> )} </div> {manualFooter ? ( manualFooter('') ) : ( <Pagination total={this.totalCount} class="pagination-block" props={{ page: this.pageIndex, limit: this.pageSize }} on={{ pagination: ({ page, limit }: { page: number; limit: number }) => { this.pagination(page, limit); }, 'update:page': (page: number) => (this.pageIndex = page), 'update:limit': (limit: number) => (this.pageSize = limit), }} /> )} </Card> </div> ); } protected searchApi = this.dataSearchApi; protected myMethods = this.requestMethod; // 保存传过来的搜索字段 private originSearchData = deepCopy(this.searchQuery); protected searchFields = this.searchQuery; protected pageSize: number = this.setPageSize; private mounted() { this.startWatchScrollHandle(); } private pagination(page: number, limit: number) { this.pageIndex = page; this.pageSize = limit; this.searchFields.pageIndex = page; this.searchFields.pageSize = limit; this.setCacheData(); this.dataLoad(); } protected async search() { this.pageIndex = 1; this.searchFields.pageIndex = 1; this.setCacheData(); this.dataLoad(); } // 重置数据 private resetData() { Object.keys(this.searchFields).forEach((key) => { this.$set(this.searchFields, key, this.originSearchData[key]); }); this.pageIndex = 1; this.searchFields.pageIndex = 1; this.setCacheData(); this.dataLoad(); } protected operationTabelData(tableList: any) { // console.log(tableList, 'tableList'); if (this.getData) { let pageQuery = { pageNo: this.pageIndex, pageSize: this.pageSize, }; // @ts-ignore this.getData(tableList, pageQuery); } } protected created() { this.columns = this.columnFields; if (this.searchFields.pageIndex && this.searchFields.pageSize) { this.pageIndex = this.searchFields.pageIndex; this.pageSize = this.searchFields.pageSize; } this.dataLoad(); busEvent.$on(EventName.updateCommonTableList + this.$route.name, (data: boolean) => { this.reload(data); }); const tempBus = busEvent as any; Object.keys(tempBus._events).forEach((key) => { try { if (tempBus._events[key].length > 1) { tempBus._events[key].shift(); } } catch (error) {} }); } private sortChangeHandle({ column, prop, order }: any) { if(this.orderType){ if(column.property==="sortShopsCount"){ this.searchFields['sortDepositAvailableAmount']='' }else{ this.searchFields['sortShopsCount']='' } this.searchFields[prop]=order.replace("ending", "").toUpperCase()=='DESC'?1:2 }else{ if (order) { this.searchFields.orderBy = [ { field: prop, direct: order.replace("ending", "").toUpperCase(), }, ]; } else { this.searchFields.orderBy = []; } } this.reload(true); console.log(column, prop, order); } public reload(isResetPageIndex: boolean = false) { if (isResetPageIndex) { this.pageIndex = 1; } this.dataLoad(); } private startWatchScrollHandle() { const container = document.querySelector('#scroll-container') as HTMLElement; const tableHeader = container.querySelector('.el-table__header-wrapper') as HTMLElement; const searchSection = container.querySelector('.hengxing-search-section') as HTMLElement; const actionEle = container.querySelector('.kdd-table-action') as HTMLElement; const searchSectionHeight = searchSection ? (window.getComputedStyle(searchSection).height as string).replace(/(px)$/, '') : 0; const actionEleHeight = actionEle ? (window.getComputedStyle(actionEle).height as string).replace(/(px)$/, '') : 0; const placeEle = document.createElement('div'); placeEle.style.height = '59px'; if (!tableHeader) { return; } container.addEventListener('scroll', () => { const scrllTop = container.scrollTop; if (scrllTop > +actionEleHeight + +searchSectionHeight) { (tableHeader.parentElement as HTMLElement).insertBefore(placeEle, tableHeader); tableHeader.style.position = 'fixed'; this.setTableHeaderPosition(tableHeader); } else { tableHeader.style.position = 'static'; try { (tableHeader.parentElement as HTMLElement).removeChild(placeEle); } catch (error) {} } }); window.addEventListener('resize', this.setTableHeaderPosition.bind(this, tableHeader)); window.addEventListener('scroll', this.setTableHeaderPosition.bind(this, tableHeader)); } private setTableHeaderPosition(tableHeader: HTMLElement) { const innerWidth = window.innerWidth; const tableHeaderChild = tableHeader.querySelector('table') as HTMLElement; tableHeader.style.width = `${tableHeader.parentElement.clientWidth}px`; if (innerWidth < 1300) { const pageXOffset = window.pageXOffset; const count = 1300 - innerWidth - pageXOffset - screenWidth; tableHeader.style.right = count - 21 > 0 ? `-${count - 21}px` : `${21 - count}px`; } else { tableHeader.style.right = `${21 + this.addRightSpace + screenWidth}px`; } tableHeader.style.top = `${71 + this.addTopSpace}px`; tableHeader.style.zIndex = '300'; // tableHeader.style.width = window.getComputedStyle(tableHeaderChild).width; } private removeEvent() { const container = document.querySelector('#scroll-container') as HTMLElement; const tableHeader = container.querySelector('.el-table__header-wrapper') as HTMLElement; window.removeEventListener('scroll', this.setTableHeaderPosition.bind(this, tableHeader)); window.removeEventListener('scroll', this.setTableHeaderPosition.bind(this, tableHeader)); } private destroyed() { this.removeEvent(); } } </script> <style lang="scss" scoped> /deep/.pagination-block { padding: 20px 26px; } .table-page { /deep/.el-table { .el-table__header, .el-table__body { unset !important; } tbody { .overflow-hidden { .cell { display: -webkit-box; white-space: normal !important; -webkit-line-clamp: 3; -webkit-box-orient: vertical; } } } } } .scroll-container { flex: 1; overflow: auto; &::-webkit-scrollbar { display: none; } @media screen and (max- 1680px) and (min- 1600px) { /deep/.change-btn-padding { .el-button.el-button--medium { padding: 8px 9px !important; } } } @media screen and (max- 1600px) and (min- 1360px) { /deep/.change-btn-padding { .el-button.el-button--medium { padding: 8px 4px !important; } } } } </style>
typescript 组件使用(可能引入文件不全单独使用会报错)
<template> <div> <CommonSearchPage ref="commonSearchPage" dataSearchApi="/admin/purchase/orderMainList" :searchQuery="searchFields" :columnFields="columnFields" requestMethod="post" > <template slot="searchSection"> <el-col :span="22"> <el-col :span="6" class="search-col"> <label class="search-label for-selector">合作商名称</label> <!-- <kddLoadMoreSelector :value.sync="searchFields.franchiseeId" EnumApi="/api/admin/franchisee/franchisees" searchKeyword="keyword" :defaultSelectData="searchFields.defaultSelectedFranchiseeData" @getSelectedData="getSelectedFranchiseeData" /> --> <el-select size="small" v-model="searchFields.franchiseeId" clearable filterable :defaultSelectData="searchFields.defaultSelectedFranchiseeData" class="form-field" > <el-option v-for="item in franchiseeList" :key="item.id" :value="item.id" :label="item.name" ></el-option> </el-select> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">门店名称</label> <!-- <kddLoadMoreSelector :value.sync="searchFields.shopId" EnumApi="/api/admin/shop/shops/list" searchKeyword="likeKeyword" :defaultSelectData="searchFields.defaultSelectedShopIdData" @getSelectedData="getSelectedShopIdData" /> --> <el-select size="small" filterable v-model="searchFields.shopId" :defaultSelectData="searchFields.defaultSelectedShopIdData" clearable class="form-field" > <el-option v-for="item in shopList" :key="item.id" :value="item.id" :label="item.name" ></el-option> </el-select> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">合作商编码</label> <el-input placeholder="请输入合作商编码" size="small" clearable v-model="searchFields.franchiseeSn" @keyup.enter.native="toSearch" ></el-input> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">门店编码</label> <el-input placeholder="请输入门店编码" size="small" clearable v-model="searchFields.shopSn" @keyup.enter.native="toSearch" ></el-input> </el-col> <el-col :span="24" class="mt10"> <el-col :span="6" class="search-col"> <label class="search-label for-selector">采购单号</label> <el-input placeholder="请输入采购单号" size="small" clearable v-model="searchFields.purchaseOrderSn" @keyup.enter.native="toSearch" ></el-input> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">入库状态</label> <el-select size="small" v-model="searchFields.storageStatus" clearable class="form-field" > <el-option v-for="item in storageStatusList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> <!-- <el-col :span="6" class="search-col"> <label class="search-label for-selector">下发状态</label> <el-select size="small" v-model="searchFields.issueStatus" clearable class="form-field" > <el-option v-for="item in issueStatusList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> --> <el-col :span="6" class="search-col"> <label class="search-label for-selector">下发状态</label> <el-select size="small" v-model="searchFields.issueStatus" clearable class="form-field" > <el-option v-for="item in issueStatusList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">单据状态</label> <el-select size="small" v-model="searchFields.status" clearable class="form-field" > <el-option v-for="item in statusNameList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> </el-col> <el-col :span="24" class="mt10"> <el-col :span="6" class="search-col"> <el-date-picker v-model="searchFields.date" value-format="yyyy-MM-dd" start-placeholder="下单开始时间" end-placeholder="下单结束时间" :editable="false" size="small" :picker-options="pickerOptions" type="daterange" style=" 100%" ></el-date-picker> </el-col> <el-col :span="6" class="search-col"> <el-date-picker v-model="searchFields.payDate" value-format="yyyy-MM-dd" start-placeholder="审核开始时间" end-placeholder="审核结束时间" :editable="false" size="small" :picker-options="pickerOptions" type="daterange" style=" 100%" ></el-date-picker> </el-col> <el-col :span="6" class="search-col"> <el-date-picker v-model="searchFields.deliveryDate" value-format="yyyy-MM-dd" start-placeholder="订单完成开始时间" end-placeholder="订单完成结束时间" :editable="false" size="small" :picker-options="pickerOptions" type="daterange" style=" 100%" ></el-date-picker> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">创建人角色</label> <el-select size="small" v-model="searchFields.creatorRole" clearable class="form-field" > <el-option v-for="item in creatorRoleList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> </el-col> <el-col :span="24" class="mt10"> <el-col :span="6" class="search-col"> <label class="search-label for-selector">排序筛选</label> <el-select size="small" v-model="searchFields.sortType" clearable class="form-field" > <el-option v-for="item in sortList" :key="item.id" :value="item.id" :label="item.label" ></el-option> </el-select> </el-col> <el-col :span="6" class="search-col"> <label class="search-label for-selector">门店组合</label> <el-select size="small" v-model="searchFields.combinationId" clearable class="form-field" > <el-option v-for="item in combinationList" :key="item.id" :value="item.id" :label="item.name" ></el-option> </el-select> </el-col> </el-col> </el-col> </template> <template slot="tableActionSection"> <!-- <el-button type="primary" size="small" :loading="exportBtnLoading" v-auth="'franchisee.purchaseOrderMain.export'" @click="exportPurchaseOrder" >导出采购单</el-button> <el-button type="primary" size="small" v-auth="'franchisee.purchaseOrderMain.detailExport'" :loading="exportSkuLoading" @click="purchaseOrderMaindetailExport" >导出采购明细</el-button> --> <el-button type="primary" size="small" @click="exportPurchaseOrder" :loading="exportBtnLoading" >导出采购单</el-button > <el-button type="primary" size="small" :loading="exportSkuLoading" @click="purchaseOrderMaindetailExport" >导出采购明细</el-button> </template> </CommonSearchPage> </div> </template> <script lang="ts"> import { Component, Vue, Watch } from "vue-property-decorator"; import CommonSearchPage from "@/components/webPart/commonSearchPage1.vue"; import kddLoadMoreSelector from "@/components/common/kddLoadMoreSelector.vue"; import { DateRangeModule } from "@/store/module/dateRange"; import { Button, Message } from "element-ui"; import busEvent, { EventName } from "@/lib/utils/busEvent"; import { AsyncExportModule } from "@/store/module/asyncExportModule"; import { BreadcrumbModule } from "@/store/module/breadcrumbModule"; import purchaseOrderListApi from "@/apis2/joinIn/purchaseOrderList"; @Component({ components: { CommonSearchPage, kddLoadMoreSelector }, }) export default class PurchaseOrderList extends Vue { static ROUTER_NAME: string = "purchaseMasterOrderList"; static ROUTER_TITLE: string = "采购主单列表"; private searchFields = { sortType:1, creatorRole: "", franchiseeId: "", outWarehouseId: "", shopId: "", storageStatus: "", issueStatus: "", storageWarehouseId: "", createStartTime: "", createEndTime: "", keyword: "", status: "", date: "", payDate: [], deliveryDate: [], auditAtStartTime: "", auditAtEndTime: "", finishAtStartTime: "", finishAtEndTime: "", defaultSelectedWarehouseData: {}, defaultSelectedFranchiseeData: {}, defaultSelectedShopIdData: {}, combinationId:"", }; // private searchData = { // defaultSelectedWarehouseData: {}, // defaultSelectedFranchiseeData: {} // }; // 仓库 private getSelectedWarehouseData({ id, name }) { this.searchFields.defaultSelectedWarehouseData = { id, name }; } // 合作商 private getSelectedFranchiseeData({ id, name }) { this.searchFields.defaultSelectedFranchiseeData = { id, name }; } // 门店 private getSelectedShopIdData({ id, name }) { this.searchFields.defaultSelectedShopIdData = { id, name }; } /** * 待审核 1 * 待支付 2 * 待入库 3 * 部分入库 4 * 已完成 5 * 已驳回 6 * 已取消 7 */ private columnFields = [ { title: "采购主单号", key: "sn" }, { title: "合作商名称", key: "franchiseeName" }, { title: "入库仓库", key: "storageWarehouseName" }, { title: "采购总数量", key: "totalQuantity" }, // { title: '采购总金额', key: 'totalAmountYuan' }, { title: "采购总金额", render: (h, row) => { return h("span", row.totalAmountDecimal); }, }, { title: "到货数量", key: "enteredNumber" }, // { title: '入库总金额', key: 'enteredAmountYuan' }, { title: "到货金额", render: (h, row) => { return h("span", row.enteredAmountDecimal); }, }, { title: "采购单状态", key: "statusDesc" }, // { title: "同步状态", key: "statusDesc" }, { title: "下发状态", key: "issueStatusDesc" }, { title: "入库状态", key: "storageStatusDesc" }, { title: "创建人角色", key: "creatorRoleDesc" }, { title: "公司名称", key: "companyName" }, { title: "创建时间", key: "createdAt" }, { title: "完成时间", key: "finishAt" }, { title: "操作", 250, render: (h, row) => h("div", [ h( Button, { props: { type: "text", size: "small" }, // directives: [ // { name: 'auth', value: 'franchisee.purchaseOrderMain.read' }, // ], on: { click: () => this.gotoDetail(row.id), }, }, "查看详情" ), h( Button, { props: { type: "text", size: "small" }, directives: [ // { name: 'auth', value: 'franchisee.PurchaseOrder.read' }, { name: 'show', value: (row.status ==3 || row.status == 4|| row.status == 7)}, ], on: { click: () => this.goPurchaseChildOrderList(row), }, }, "查看采购子单" ), h( Button, { props: { type: "text", size: "small", loading: row.cancelLoading, }, directives: [ // { name: 'auth', value: 'franchisee.PurchaseOrder.read' }, { name: 'show', value: (row.status ==1 || row.status == 2)}, ], on: { click: () => this.cancelRowHandle(row), }, }, "取消" ), h( Button, { props: { type: "text", size: "small", }, directives: [ // { name: 'auth', value: 'franchisee.PurchaseOrder.read' }, { name: 'show', value: row.issueStatus !== 1 && (row.storageStatus !== 1 || row.issueStatus !== 4)}, ], on: { click: () => this.toBatchList(row), }, }, "查看入库信息" ), ]), }, ]; private statusList = []; private inWarehousList = []; private inWarehouseSearchList = []; private EnumApi = "/api/admin/franchisee/franchisees?status=true"; private pickerOptions = { shortcuts: DateRangeModule.shortcuts, }; private formData = { name: "", file: undefined, }; private loading = false; @Watch("searchFields.date") private onDateChangeHandle(newVal: any) { this.searchFields.createStartTime = newVal ? newVal[0] : ""; this.searchFields.createEndTime = newVal ? newVal[1] : ""; } @Watch("searchFields.payDate") private onPayDateChange(newVal) { this.searchFields.auditAtStartTime = newVal ? newVal[0] : ""; this.searchFields.auditAtEndTime = newVal ? newVal[1] : ""; } @Watch("searchFields.deliveryDate") private onDeliveryDateChange(newVal) { this.searchFields.finishAtStartTime = newVal ? newVal[0] : ""; this.searchFields.finishAtEndTime = newVal ? newVal[1] : ""; } private cancelRowHandle(row) { this.$confirm("您确定要取消么?", { type: "warning" }).then(async () => { this.$set(row, "cancelLoading", true); await purchaseOrderListApi.cancelMainOrder({ id: row.id }); this.$set(row, "cancelLoading", false); busEvent.$emit(EventName.updateCommonTableList + this.$route.name); this.$message.success("操作成功"); }); } // 查看入库信息 private toBatchList(row) { this.$router.push({ name: "incomingBatchesList", query: { orderNumbers: row.sn }, }); } private exportBtnLoading = false; private exportSkuLoading = false; // 导出采购单 private async exportPurchaseOrder() { this.exportBtnLoading = true; try { let result= await purchaseOrderListApi.exportOrderMain(this.searchFields); AsyncExportModule.exportHandleToUrl(result.data.data) this.exportBtnLoading = false; } catch (error) { this.exportBtnLoading = false; } } // 导出采购明细-新增 private async purchaseOrderMaindetailExport() { this.exportSkuLoading = true; try { let result= await purchaseOrderListApi.exportOrderMainSkusList(this.searchFields); AsyncExportModule.exportHandleToUrl(result.data.data) this.exportSkuLoading = false; } catch (error) { this.exportSkuLoading = false; } } // 回车搜索 private toSearch() { (this.$refs.commonSearchPage as any).search(); } // 详情页面 private gotoDetail(id) { BreadcrumbModule.addBreadcrumbs({ name: "purchaseMasterOrderDetails", title: "采购主单详情", }); this.$router.push({ name: "purchaseMasterOrderDetails", query: { id }, }); } // 查看子单 private goPurchaseChildOrderList(row) { this.$router.push({ name: "purchaseChildOrderList", query: { orderNumbers: row.sn }, }); } private combinationList=[] private creatorRoleList = [ { id: 1, label: "合作商" }, { id: 2, label: "门店" }, ]; // 创建人角色 private sortList=[ { id: 1, label: "时间倒序" }, { id: 2, label: "采购总数倒序" }, { id: 3, label: "采购总金额倒序 " }, ] private storageStatusList = [ { id: 1, label: "未入库" }, { id: 2, label: "部分入库" }, { id: 3, label: "全部入库" }, ]; // 入库状态 private issueStatusList = [ { id: 1, label: "待下发" }, { id: 2, label: "部分成功" }, { id: 3, label: "下发成功" }, { id: 4, label: "停止下发" }, ]; // 下发状态 private statusNameList = [ { id: 1, label: "待审核" }, { id: 2, label: "待支付" }, { id: 3, label: "进行中" }, { id: 4, label: "已完成" }, { id: 5, label: "已驳回" }, { id: 6, label: "取消" }, { id: 7, label: "已终止" }, ]; private franchiseeList = []; private shopList = []; private created() { busEvent.$on("announceTableData", (data) => { // this.statusList = data.syncStatus; // this.creatorRoleList = data.createRole; // this.storageStatusList = data.storageStatus; // this.issueStatusList = data.issueStatus; // this.statusNameList = data.status; }); this.getShopList() this.getFranchiseeList() this.getCombination() } private async getCombination (){ try { const params = {}; const { data } = await purchaseOrderListApi.selectCombination(params); this.combinationList = data.data.list; } catch (error) { } } private async getShopList(){ try { const params = {}; const { data } = await purchaseOrderListApi.selectShopList(params); this.shopList = data.data; } catch (error) { } } private async getFranchiseeList(){ try { const params = {}; const { data } = await purchaseOrderListApi.franchiseeForShop(params); this.franchiseeList = data.data; } catch (error) { } } private destroyed() { busEvent.$off("announceTableData"); delete BreadcrumbModule.cacheBreadCrumbs.purchaseMasterOrderDetails; } } </script> <style lang="scss" scoped> .mt10 { margin-top: 10px; } .post-form { .el-form-item { margin-bottom: 0; } } .in-warehouse { 250px; } </style>