zb-tables.vue 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. <template>
  2. <!-- #ifdef H5 || APP-PLUS -->
  3. <view :class="['zb-table','zb-table-fixed-header',!border&&(bodyTableLeft>50||headerTableLeft>50)&&'scroll-left-fixed']">
  4. <view class="zb-table-content" style="flex: 1">
  5. <view class="zb-table-scroll" style="height: 100%;">
  6. <template v-if="showHeader">
  7. <view class="zb-table-header top-header-uni" :style="{paddingRight:`${scrollbarSize}rpx`,background:`${headbgColor}`}"
  8. >
  9. <scroll-view class="zb-table-headers"
  10. @touchmove.stop="getMove"
  11. @scroll="handleTableScrollLeft"
  12. scroll-x="true"
  13. scroll-y="false"
  14. id="tableHeaders"
  15. scroll-anchoring="true"
  16. :scroll-left="headerTableLeft"
  17. style="
  18. height: 100%">
  19. <view class="zb-table-fixed" >
  20. <view class="zb-table-thead" style="position: relative;" >
  21. <view class="item-tr">
  22. <view
  23. @click.stop="sortAction(item,index)"
  24. class="item-th"
  25. :class="border?'':'nborder'"
  26. :style="[{
  27. width:`${item.width?item.width:'200'}rpx`,
  28. flex:index===transColumns.length-1?1:'none',
  29. minWidth:`${item.width?item.width:'200'}rpx`,
  30. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  31. borderRight:`${(scrollbarSize&&index===transColumns.length-1)?'':border&&borderr?'2rpx solid #e8e8e8':''}`,
  32. borderTop:`${border?'2rpx solid #e8e8e8':''}`,
  33. textAlign:item.align||'left',
  34. paddingRight:`${item.paddingRight?item.paddingRight:'8'}rpx`,
  35. },getHeaderCellStyle(item,index)]"
  36. v-for="(item,index) in transColumns" :key="index">
  37. <template v-if="item.type==='selection'">
  38. <view class="checkbox-item">
  39. <tableCheckbox
  40. :indeterminate="indeterminate" :checked="checkedAll" @checkboxSelected="checkboxSelectedAll"></tableCheckbox>
  41. </view>
  42. </template>
  43. <template v-else>
  44. {{ item.label }}
  45. <block v-if="item.manfen">/{{item.manfen}}</block>
  46. <view class="sorter-table" v-if="item.sorter">
  47. <view :class="['sorter-table-icon',item.sorterMode==='_asc'&&`sorting${item.sorterMode||''}`]"></view>
  48. <view :class="['sorter-table-icon',item.sorterMode==='_desc'&&`sorting${item.sorterMode||''}`]"></view>
  49. </view>
  50. </template>
  51. </view>
  52. </view>
  53. </view>
  54. </view>
  55. </scroll-view>
  56. </view>
  57. </template>
  58. <template v-if="!data.length">
  59. <view class="no-data">暂无数据~~</view>
  60. </template>
  61. <scroll-view
  62. class="zb-table-body" ref="tableBody" scroll-x="true" scroll-y="true" id="tableBody"
  63. :lower-threshold="40"
  64. :upper-threshold="10"
  65. @touchmove.stop="getMove"
  66. @scrolltolower="scrolltolower"
  67. @scrolltoupper="(e)=>debounce(scrollToLeft)(e)"
  68. @scroll="handleBodyScroll" :scroll-left="bodyTableLeft" :scroll-top="bodyScrollTop"
  69. :style=" `height: calc(100% - ${showSummary?160:80}rpx)`" >
  70. <view class="zb-table-fixed">
  71. <view class="zb-table-tbody">
  72. <view :class="['item-tr',highlight&&isHighlight(item,index)?'current-row':'']"
  73. @click.stop="rowClick(item,index)"
  74. v-for="(item,index) in transData" :key="item.key" >
  75. <view
  76. :style="[{
  77. width:`${ite.width?ite.width:'200'}rpx`,
  78. flex:i===transColumns.length-1?1:'none',
  79. minWidth:`${ite.width?ite.width:'200'}rpx`,
  80. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  81. textAlign:ite.align||'left',
  82. },cellStyle&&getCellStyle(item,ite,index,i)]"
  83. :class="['item-td',stripe?(index % 2) != 0?'odd':'even':'',border?'':'nborder']"
  84. v-for="(ite,i) in transColumns" :key="i">
  85. <template v-if="ite.type==='operation'">
  86. <view style="display: flex;align-items: center;height: 100%">
  87. <view
  88. v-for="ren,ind in permission(item,ite.renders,index)"
  89. :key="ind"
  90. @click.stop="$emit(ren.func,item,index)"
  91. :style="{
  92. display:'flex',
  93. alignItems: 'center',
  94. marginRight:ite.renders.length>1?'16rpx':'0'
  95. }">
  96. <template v-if="ren.type==='custom'">
  97. <view :class="ren.class||''" style="cursor: pointer">
  98. {{ren.name}}
  99. </view>
  100. </template>
  101. <template v-else>
  102. <button
  103. :class="ren.class||''"
  104. :type="ren.type||'primary'" :size="ren.size||'mini'">{{ren.name}}</button>
  105. </template>
  106. </view>
  107. </view>
  108. </template>
  109. <template v-else-if="ite.type==='selection'">
  110. <view class="checkbox-item">
  111. <tableCheckbox @checkboxSelected="(e)=>checkboxSelected(e,item)" :cellData="item" :checked="item.checked"/>
  112. </view>
  113. </template>
  114. <template v-else-if="ite.type==='index'">
  115. {{index+1}}
  116. </template>
  117. <template v-else-if="ite.type==='img'">
  118. <view class="checkbox-item">
  119. <image
  120. @click.stop="previewImage(item,item[ite.name],index)"
  121. v-if="item[ite.name]"
  122. :show-menu-by-longpress="false"
  123. :src="item[ite.name]" style="width: 80rpx;height:60rpx; " mode="aspectFit"></image>
  124. <text v-else>{{ite.emptyString}}</text>
  125. </view>
  126. </template>
  127. <template v-else>
  128. <!-- {{ ite.filters?itemFilter(item,ite):(item[ite.name]==null||item[ite.name]==='')?ite.emptyString:item[ite.name] }}-->
  129. {{ ite.filters?itemFilter(item,ite):formatterAction(item,ite,index,i) }}
  130. </template>
  131. </view>
  132. </view>
  133. </view>
  134. </view>
  135. </scroll-view>
  136. <table-h5-summary
  137. :scrollbarSize="scrollbarSize"
  138. :data="data"
  139. :handleFooterTableScrollLeft="handleFooterTableScrollLeft"
  140. :headerFooterTableLeft="headerFooterTableLeft"
  141. v-if="showSummary"
  142. :showSummary="showSummary"
  143. :transColumns="transColumns"
  144. :border="border"
  145. :summary-method="summaryMethod"
  146. :sumText="sumText"
  147. :fixedLeftColumns="fixedLeftColumns"/>
  148. </view>
  149. <view class="zb-table-fixed-left"
  150. v-if="isFixedLeft"
  151. :style=" {height: `calc(100% - ${scrollbarSize}rpx)`}"
  152. >
  153. <template v-if="showHeader">
  154. <view class="zb-table-header" style="display: flex" :style="{background:`${headbgColor}`}">
  155. <view class="item-tr"
  156. style=""
  157. @click.stop="rowClick(item,index)"
  158. v-for="(item,index) in fixedLeftColumns" :key="index">
  159. <view
  160. :style="{
  161. width:`${item.width?item.width:'200'}rpx`,
  162. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  163. borderTop:`${border?'2rpx solid #e8e8e8':''}`,
  164. textAlign:item.align||'left'
  165. }"
  166. @click.stop="sortAction(item,index)"
  167. class="item-th"
  168. :class="border?'':'nborder'"
  169. >
  170. <template v-if="item.type==='selection'">
  171. <view class="checkbox-item">
  172. <tableCheckbox
  173. :indeterminate="indeterminate" :checked="checkedAll" @checkboxSelected="checkboxSelectedAll"></tableCheckbox>
  174. </view>
  175. </template>
  176. <template v-else>
  177. {{ item.label }}
  178. <block v-if="item.manfen">/{{item.manfen}}</block>
  179. <view class="sorter-table" v-if="item.sorter">
  180. <view :class="['sorter-table-icon',item.sorterMode==='_asc'&&`sorting${item.sorterMode||''}`]"></view>
  181. <view :class="['sorter-table-icon',item.sorterMode==='_desc'&&`sorting${item.sorterMode||''}`]"></view>
  182. </view>
  183. </template>
  184. </view>
  185. </view>
  186. </view>
  187. </template>
  188. <scroll-view
  189. scroll-y="true"
  190. id="leftTableFixed"
  191. :upper-threshold="15"
  192. @scrolltoupper="(e)=>scrollToFixedLeft(e)"
  193. @scroll="leftFixedScrollAction"
  194. :scroll-top="leftFiexScrollTop"
  195. class="zb-table-body-inner"
  196. :style=" `height: calc(100% - ${showSummary?160:80}rpx)`">
  197. <view class="zb-table-fixed">
  198. <view class="zb-table-tbody">
  199. <view
  200. :class="['item-tr',stripe?(i % 2) != 0?'odd':'even':'',highlight&&isHighlight(ite,i)?'current-row':'']"
  201. v-for="(ite,i) in transData"
  202. @click.stop="rowClick(ite,i)"
  203. :key="ite.key"
  204. style="">
  205. <view class='item-td'
  206. :class="border?'':'nborder'"
  207. :style="[{
  208. width:`${item.width?item.width:'200'}rpx`,
  209. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  210. textAlign:item.align||'left'
  211. },cellStyle&&getCellStyle(ite,item,i,index)]"
  212. :key="index"
  213. v-for="(item,index) in fixedLeftColumns">
  214. <template v-if="item.type==='selection'">
  215. <view class="checkbox-item">
  216. <tableCheckbox @checkboxSelected="(e)=>checkboxSelected(e,ite)" :cellData="ite" :checked="ite.checked"/>
  217. </view>
  218. </template>
  219. <template v-else-if="item.type==='index'">
  220. {{i+1}}
  221. </template>
  222. <template v-else>
  223. {{ite[item.name]||item.emptyString}}
  224. </template>
  225. </view>
  226. </view>
  227. </view>
  228. </view>
  229. </scroll-view>
  230. <table-side-summary
  231. :scrollbarSize="scrollbarSize"
  232. v-if="showSummary&&!(scrollbarSize>0)"
  233. :data="data"
  234. :showSummary="showSummary"
  235. :transColumns="transColumns"
  236. :border="border"
  237. :summary-method="summaryMethod"
  238. :sumText="sumText"
  239. :fixedLeftColumns="fixedLeftColumns"/>
  240. </view>
  241. </view>
  242. <zb-load-more v-if="isLoadMore&&!completeLoading"/>
  243. </view>
  244. <!-- #endif -->
  245. <!-- #ifndef H5 || APP-PLUS -->
  246. <view class="zb-table-applet">
  247. <view class="zb-table-content">
  248. <scroll-view
  249. <!-- #ifdef MP-ALIPAY -->
  250. @scroll="scrollAlipay"
  251. <!-- #endif -->
  252. @scrolltolower="scrolltolower"
  253. <!-- #ifdef MP-ALIPAY -->
  254. style=" height: 100%;overflow-x:scroll"
  255. <!-- #endif -->
  256. <!-- #ifndef MP-ALIPAY -->
  257. style=" height: 100%"
  258. <!-- #endif -->
  259. scroll-y="true"
  260. scroll-x="true">
  261. <view class="zb-table-scroll" >
  262. <template v-if="showHeader">
  263. <view class="zb-table-header top-header-uni" :style="{background:`${headbgColor}`}">
  264. <view class="zb-table-fixed" >
  265. <view class="zb-table-thead" style="position: relative;" >
  266. <view class="item-tr">
  267. <view
  268. @click.stop="sortAction(item,index)"
  269. :class="['item-th',index <fixedLeftColumns.length&&'zb-stick-side',border?'':'nborder']"
  270. :style="{
  271. left:`${item.left}rpx`,
  272. width:`${item.width?item.width:'200'}rpx`,
  273. flex:index===transColumns.length-1?1:'none',
  274. minWidth:`${item.width?item.width:'200'}rpx`,
  275. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  276. borderTop:`${border?'2rpx solid #e8e8e8':''}`,
  277. textAlign:item.align||'left'
  278. }"
  279. v-for="(item,index) in transColumns" :key="index">
  280. <template v-if="item.type==='selection'">
  281. <view class="checkbox-item">
  282. <tableCheckbox
  283. :indeterminate="indeterminate" :checked="checkedAll" @checkboxSelected="checkboxSelectedAll"></tableCheckbox>
  284. </view>
  285. </template>
  286. <template v-else>
  287. {{ item.label||'' }}
  288. <block v-if="item.manfen">/{{item.manfen}}</block>
  289. <view class="sorter-table" v-if="item.sorter">
  290. <view :class="['sorter-table-icon',item.sorterMode==='_asc'&&`sorting${item.sorterMode||''}`]"></view>
  291. <view :class="['sorter-table-icon',item.sorterMode==='_desc'&&`sorting${item.sorterMode||''}`]"></view>
  292. </view>
  293. </template>
  294. </view>
  295. </view>
  296. </view>
  297. </view>
  298. </view>
  299. </template>
  300. <template v-if="!data.length">
  301. <view class="no-data">暂无数据~~</view>
  302. </template>
  303. <view class="zb-table-fixed">
  304. <view class="zb-table-tbody">
  305. <view :class="['item-tr',highlight&&isHighlight(item,index)?'current-row':'']"
  306. @click.stop="rowClick(item,index)"
  307. v-for="(item,index) in transData" :key="item.key" >
  308. <view
  309. :style="[{
  310. left:`${ite.left}rpx`,
  311. width:`${ite.width?ite.width:'200'}rpx`,
  312. flex:i===transColumns.length-1?1:'none',
  313. minWidth:`${ite.width?ite.width:'200'}rpx`,
  314. borderRight:`${border&&borderr?'2rpx solid #e8e8e8':''}`,
  315. textAlign:ite.align||'left',
  316. },getCellStyle(item,ite,index,i)]"
  317. :class="['item-td',border?'':'nborder', i <fixedLeftColumns.length&&'zb-stick-side',stripe?(index % 2) != 0?'odd':'even':'']"
  318. v-for="(ite,i) in transColumns" :key="i">
  319. <template v-if="ite.type==='operation'">
  320. <view style="display: flex;align-items: center;height: 100%">
  321. <view
  322. v-for="ren,ind in permission(item,ite.renders,index)"
  323. :key="ind"
  324. @click.stop="$emit(ren.func,item,index)"
  325. :style="{
  326. display:'flex',
  327. alignItems: 'center',
  328. marginRight:ite.renders.length>1?'16rpx':'0'
  329. }">
  330. <template v-if="ren.type==='custom'">
  331. <view :class="ren.class||''" style="cursor: pointer">
  332. {{ren.name}}
  333. </view>
  334. </template>
  335. <template v-else>
  336. <button
  337. :class="ren.class||''"
  338. :type="ren.type||'primary'" :size="ren.size||'mini'">{{ren.name}}</button>
  339. </template>
  340. </view>
  341. </view>
  342. </template>
  343. <template v-else-if="ite.type==='selection'">
  344. <view class="checkbox-item">
  345. <tableCheckbox @checkboxSelected="(e)=>checkboxSelected(e,item)" :cellData="item" :checked="item.checked"/>
  346. </view>
  347. </template>
  348. <template v-else-if="ite.type==='img'">
  349. <image
  350. @click.stop="previewImage(item,item[ite.name],index)"
  351. v-if="item[ite.name]"
  352. :show-menu-by-longpress="false"
  353. :src="item[ite.name]" style="width: 80rpx;height:60rpx; " mode="aspectFit"></image>
  354. <text v-else>{{ite.emptyString}}</text>
  355. </template>
  356. <template v-else-if="ite.type==='index'">
  357. {{index+1}}
  358. </template>
  359. <template v-else>
  360. <!-- {{ ite.filters?itemFilter(item,ite):(item[ite.name]==null||item[ite.name]==='')?ite.emptyString:item[ite.name] }}-->
  361. {{ ite.filters?itemFilter(item,ite):formatterAction(item,ite,index,i) }}
  362. </template>
  363. </view>
  364. </view>
  365. </view>
  366. </view>
  367. <table-summary
  368. v-if="showSummary"
  369. :data="data"
  370. :showSummary="showSummary"
  371. :fixedLeftColumns="fixedLeftColumns"
  372. :transColumns="transColumns"
  373. :border="border"
  374. :summary-method="summaryMethod"
  375. :sumText="sumText"
  376. />
  377. </view>
  378. </scroll-view>
  379. </view>
  380. <zb-load-more v-if="isLoadMore&&!completeLoading"/>
  381. </view>
  382. <!-- #endif -->
  383. </template>
  384. <script>
  385. import TableCheckbox from './components/table-checkbox.vue'
  386. import TableSummary from "./components/table-summary.vue";
  387. import TableSideSummary from "./components/table-side-summary.vue";
  388. import TableH5Summary from './components/table-h5-summary'
  389. import ZbLoadMore from './components/zb-load-more'
  390. import {getScrollbarSize} from "./js/util";
  391. // fit 列的宽度是否自撑开
  392. // column 显示的列数据
  393. // stripe 是否为斑马纹 table
  394. // show-header 是否显示表头
  395. //headbgColor 头部背景色
  396. //borderr右侧的线
  397. export default {
  398. components:{
  399. TableCheckbox,
  400. TableSummary,
  401. TableSideSummary,
  402. TableH5Summary,
  403. ZbLoadMore
  404. },
  405. props:{
  406. headbgColor:{},
  407. borderr:{
  408. type:Boolean,
  409. default:true
  410. },
  411. highlight:{
  412. type:Boolean,
  413. default:false
  414. },
  415. itemDate:{
  416. type:Object,
  417. default:()=>{}
  418. },
  419. columns:{
  420. type:Array,
  421. default:()=>[]
  422. },
  423. showSummary:{
  424. type:Boolean,
  425. default:false
  426. },
  427. isShowLoadMore:{
  428. type:Boolean,
  429. default:false
  430. },
  431. data:{
  432. type:[Object,Array],
  433. default:()=>[]
  434. },
  435. sumText:{
  436. type:String,
  437. default:'合计'
  438. },
  439. showHeader:{
  440. type:Boolean,
  441. default:true
  442. },
  443. border:{
  444. type:Boolean,
  445. default:false
  446. },
  447. stripe:{
  448. type:Boolean,
  449. default:true
  450. },
  451. fit:{
  452. type:Boolean,
  453. default:false
  454. },
  455. rowKey:[String, Function],
  456. summaryMethod:Function,
  457. pullUpLoading:Function,
  458. formatter:Function,
  459. cellStyle:Function,
  460. cellHeaderStyle:Function,
  461. permissionBtn:Function,
  462. },
  463. computed:{
  464. loadMoreHeight(){
  465. return this.isLoadMore?40:0
  466. },
  467. fixedLeftColumns(){
  468. let arr = []
  469. for(let i=0;i<this.columns.length;i++){
  470. let item = this.columns[i]
  471. if(item.fixed){
  472. arr.push(item)
  473. }else {
  474. break
  475. }
  476. }
  477. return arr
  478. },
  479. itemfilters(){
  480. return(item,ite)=>{
  481. if(item[ite.name]==null){
  482. return ite.emptyString
  483. }
  484. return item[ite.name]
  485. }
  486. },
  487. scrollbarSize(){
  488. // #ifdef H5
  489. return getScrollbarSize()
  490. // #endif
  491. // #ifndef H5
  492. return 0
  493. // #endif
  494. },
  495. isFixedLeft(){
  496. if(!this.columns.length){
  497. return false
  498. }
  499. if(!this.data.length){
  500. return false
  501. }
  502. let [firstArr] = this.columns
  503. return !!firstArr.fixed;
  504. },
  505. transColumns(){
  506. if(this.fit){
  507. this.columns.forEach(column=>{
  508. if(column.type==="operation"&&column.renders){
  509. let str = ''
  510. column.renders.map((item)=>{
  511. str+=item.name
  512. })
  513. column.width = this.getTextWidth(str)+column.renders.length*40
  514. }else if(column.type==="img"){
  515. }else if(column.type==="selection"){
  516. }else{
  517. console.log(column,23)
  518. let arr = [this.getTextWidth(column.label)]
  519. this.data.forEach(data=>{
  520. let str = (data[column.name]+'')
  521. if(str==='undefined'){
  522. arr.push(60)
  523. }else{
  524. let width = this.getTextWidth(str)
  525. arr.push(width)
  526. }
  527. })
  528. column.width = Math.max(...arr)+40
  529. }
  530. })
  531. }
  532. let number = 0
  533. this.columns.forEach((item,index)=>{
  534. if(item.type==="operation"&&item.renders&&!item.width){
  535. let str = ''
  536. item.renders.map((item)=>{
  537. str+=item.name
  538. })
  539. item.width = this.getTextWidth(str)+item.renders.length*40
  540. }
  541. if(item.fixed){
  542. if(index===0){
  543. item.left = 0
  544. number+=item.width
  545. }else {
  546. item.left = number
  547. number+=item.width
  548. }
  549. }
  550. item.emptyString = item.emptyString||'--'
  551. })
  552. return this.columns
  553. },
  554. transData(){
  555. let flag = this.columns.some(item=>item.type==='selection')
  556. this.data.forEach((item,index)=>{
  557. if(flag){
  558. if(item.checked){
  559. if(!this.selectArr.length){
  560. this.selectArr.push(item)
  561. }
  562. }
  563. }
  564. if(this.rowKey){
  565. if(typeof this.rowKey==='function'){
  566. item.key = Object.freeze(this.rowKey(item))||Date.now()
  567. }else {
  568. item.key = Object.freeze(item[this.rowKey])||Date.now()
  569. }
  570. }else {
  571. item.key = index
  572. }
  573. })
  574. if(flag&&this.data.length){
  575. let le = this.data.filter(item=>item.checked).length
  576. if(le){
  577. if(le===this.data.length){
  578. this.checkedAll = true
  579. }else {
  580. this.indeterminate = true
  581. }
  582. }
  583. }
  584. return this.data
  585. },
  586. isHighlight(){
  587. return (item,index)=>{
  588. if(this.rowKey){
  589. return item.key === this.currentRow['key']
  590. }else{
  591. return index === this.currentRowIndex
  592. }
  593. }
  594. },
  595. getHeaderCellStyle() {
  596. return (column, columnIndex,childIndex)=>{
  597. const cellStyle = this.cellHeaderStyle;
  598. if(typeof cellStyle==='function'){
  599. return cellStyle({ column, columnIndex})
  600. }
  601. return {}
  602. }
  603. },
  604. getCellStyle() {
  605. return (row, column, rowIndex, columnIndex)=>{
  606. const cellStyle = this.cellStyle;
  607. if(typeof cellStyle==='function'){
  608. return cellStyle({row, column, rowIndex, columnIndex})
  609. }
  610. return {}
  611. }
  612. },
  613. },
  614. data() {
  615. return {
  616. button:[],
  617. alipayScrollTop:0,
  618. alipayScrollOldTop:0,
  619. alipayFlag:false,
  620. bodyTableLeft:0,
  621. headerTableLeft:0,
  622. lastScrollLeft:0,
  623. isLoadMore:false,
  624. headerFooterTableLeft:0,
  625. leftFiexScrollTop:0,
  626. bodyScrollTop:0,
  627. currentDriver:null,
  628. currentDriver1:null,
  629. bodyTime:null,
  630. currentRowIndex:null,
  631. currentRow: {},
  632. bodyTime1:null,
  633. headerTime:null,
  634. debounceTime:null,
  635. operation:{},
  636. completedFlag:false,
  637. selectArr:[],
  638. indeterminate:false,
  639. checkedAll:false,
  640. completeLoading:false,
  641. aliTime:null,
  642. }
  643. },
  644. created(){
  645. },
  646. mounted(){
  647. },
  648. methods: {
  649. getMove(){
  650. },
  651. formatterAction(row,column,rowIndex,columnIndex){
  652. if(column.formatter&&typeof this.formatter==='function'){
  653. return this.formatter(row,column,rowIndex,columnIndex)
  654. }
  655. return (row[column.name]==null||row[column.name]==='')?column.emptyString:row[column.name]
  656. },
  657. permission(item,renders,index){
  658. if(this.permissionBtn&&typeof this.permissionBtn==='function'){
  659. return this.permissionBtn(item,renders,index)
  660. }
  661. return renders
  662. },
  663. pullUpCompleteLoading(type){
  664. this.isLoadMore = false
  665. if(type==='ok'){
  666. this.completeLoading = true
  667. }
  668. },
  669. scrollAlipay(e){
  670. if(!this.alipayScrollOldTop){
  671. this.alipayScrollOldTop = e.detail.scrollTop
  672. }
  673. this.aliTime&&clearTimeout(this.aliTime)
  674. this.aliTime = setTimeout(()=>{
  675. if(this.alipayFlag&&e.detail.scrollTop>this.alipayScrollOldTop){
  676. this.pullLoad()
  677. }
  678. this.alipayFlag = false
  679. this.alipayScrollOldTop = null
  680. },500)
  681. },
  682. pullLoad(){
  683. if(this.isShowLoadMore){
  684. this.isLoadMore = true
  685. this.$emit('pullUpLoading')
  686. let that = this
  687. this.pullUpLoading&&this.pullUpLoading.call(this.$parent.$parent, (type)=>{
  688. that.isLoadMore = false
  689. if(type==='ok'){
  690. that.completeLoading=true
  691. }
  692. })
  693. }
  694. },
  695. scrolltolower(e){
  696. this.alipayFlag = true
  697. if(e.detail.direction==='bottom'){
  698. this.pullLoad()
  699. }
  700. // this.pullUpLoading.call(this.$parent)
  701. },
  702. previewImage(item,url,current){
  703. uni.previewImage({
  704. current,
  705. urls:[url]
  706. })
  707. },
  708. resetHighlight(){
  709. this.currentRowIndex = null
  710. this.currentRow = {}
  711. },
  712. rowClick(row,index){
  713. if(this.highlight){
  714. this.currentRowIndex = index
  715. this.currentRow = row
  716. this.$emit('currentChange',row,index)
  717. }
  718. this.$emit('rowClick',row,index)
  719. },
  720. checkboxSelectedAll(e){
  721. this.indeterminate = false
  722. if(e.checked){
  723. this.selectArr = []
  724. this.checkedAll = true
  725. this.data.forEach(item=>{
  726. // this.$set(item,'checked',true)
  727. item.checked = true
  728. this.selectArr.push(item)
  729. })
  730. }else{
  731. this.checkedAll = false
  732. this.data.forEach(item=>{
  733. this.$set(item,'checked',false)
  734. })
  735. this.selectArr = []
  736. }
  737. // #ifndef H5 || APP-PLUS
  738. this.$forceUpdate()
  739. // #endif
  740. this.$emit('toggleAllSelection',e.checked,this.selectArr)
  741. },
  742. checkboxSelected(e,item){
  743. // #ifdef H5 || APP-PLUS
  744. this.$set(item,'checked',e.checked)
  745. // #endif
  746. // #ifndef H5 || APP-PLUS
  747. this.data.forEach(item=>{
  748. if(item.key===e.data.key){
  749. item.checked = e.checked
  750. }
  751. })
  752. // #endif
  753. item.checked = e.checked
  754. e.data.checked = e.checked
  755. if(e.checked){
  756. this.selectArr.push(e.data)
  757. }else{
  758. this.selectArr = this.selectArr.filter(item=>item.key!==e.data.key)
  759. }
  760. if(this.selectArr.length===this.transData.length){
  761. this.indeterminate = false
  762. this.checkedAll = true
  763. }else{
  764. this.indeterminate = true
  765. this.checkedAll = false
  766. }
  767. if(!this.selectArr.length){
  768. this.checkedAll = false
  769. this.indeterminate = false
  770. }
  771. // #ifndef H5 || APP-PLUS
  772. this.$forceUpdate()
  773. // #endif
  774. this.$emit('toggleRowSelection',e.checked,this.selectArr)
  775. },
  776. itemFilter(item,ite){
  777. if(ite.filters&&ite.name){
  778. let key = item[ite.name]
  779. return ite.filters[key]||''
  780. }
  781. return item[ite.name]||ite.emptyString
  782. },
  783. // 默认字体为微软雅黑 Microsoft YaHei,字体大小为 14px
  784. getTextWidth(str) {
  785. if(str.length<3){
  786. return 80
  787. }
  788. let regx = /^[0-9]+.?[0-9]*$/
  789. let flexWidth = 0
  790. for (const char of str) {
  791. if ((char >= 'A' && char <= 'Z') || (char >= 'a' && char <= 'z')) {
  792. // 如果是英文字符,为字符分配8个单位宽度
  793. flexWidth += 20
  794. } else if (char >= '\u4e00' && char <= '\u9fa5') {
  795. // 如果是中文字符,为字符分配15个单位宽度
  796. flexWidth += 30
  797. } else if(regx.test(char)){
  798. flexWidth += 18
  799. }else {
  800. // 其他种类字符,为字符分配8个单位宽度
  801. flexWidth += 14
  802. }
  803. }
  804. return flexWidth
  805. },
  806. width(item){
  807. return `${item.width?item.width:'200'}rpx`
  808. },
  809. showStripe(index){
  810. if(this.currentDriver)return
  811. if(this.stripe){
  812. return (index % 2) != 0?'odd':'even'
  813. }else{
  814. return ''
  815. }
  816. },
  817. //验证字符串是否是数字
  818. checkNumber(theObj) {
  819. var reg = /^[0-9]+.?[0-9]*$/;
  820. if (reg.test(theObj)) {
  821. return true;
  822. }
  823. return false;
  824. },
  825. isDate(data){
  826. if(isNaN(data)&&!isNaN(Date.parse(data))){
  827. return true
  828. }
  829. return false
  830. },
  831. sortAction(item,index){
  832. if(!item.sorter){return false}
  833. this.$set(item,'sorterMode',item.sorterMode==='_asc'?'_desc':'_asc')
  834. if(item.sorter==='custom'){
  835. this.$emit('sort-change',item,item.sorterMode.replace('_',''),index)
  836. }else {
  837. this.sortData(item)
  838. }
  839. // #ifndef H5 || APP-PLUS
  840. this.$forceUpdate()
  841. // #endif
  842. },
  843. sortData(item){
  844. let key = item.name
  845. if(item.sorterMode==='_asc'){
  846. this.data.sort((a,b)=>{
  847. if(this.checkNumber(a[key])){
  848. return a[key]-b[key]
  849. }
  850. if(this.isDate(a[key])){
  851. let a1 = new Date(a[key]).getTime()
  852. let b1 = new Date(b[key]).getTime()
  853. return a1-b1
  854. }
  855. })
  856. }else {
  857. this.data.sort((a,b)=>{
  858. if(this.checkNumber(a[key])){
  859. return b[key]-a[key]
  860. }
  861. if(this.isDate(a[key])){
  862. let a1 = new Date(a[key]).getTime()
  863. let b1 = new Date(b[key]).getTime()
  864. return b1-a1
  865. }
  866. })
  867. }
  868. },
  869. throttle(method,delay=60){
  870. let time = null
  871. return (...args)=>{
  872. if(!time){
  873. time = setTimeout(()=>{
  874. method(...args)
  875. time = null;
  876. },delay)
  877. }
  878. }
  879. },
  880. debounce(method,delay=1000){
  881. return (...args)=>{
  882. this.debounceTime&&clearTimeout(this.debounceTime)
  883. this.debounceTime = setTimeout(()=>{
  884. method(...args)
  885. },delay)
  886. }
  887. },
  888. handleBodyScroll(e){
  889. if(this.currentDriver&&this.currentDriver!==e.currentTarget.id)return
  890. this.currentDriver = e.currentTarget.id
  891. this.headerTableLeft = e.detail.scrollLeft
  892. this.headerFooterTableLeft = e.detail.scrollLeft
  893. this.leftFiexScrollTop = e.detail.scrollTop
  894. this.bodyTime&&clearTimeout(this.bodyTime)
  895. this.bodyTime = setTimeout(()=>{
  896. this.currentDriver=null
  897. },200)
  898. },
  899. leftFixedScrollAction(e){
  900. if(this.currentDriver&&this.currentDriver!==e.currentTarget.id)return
  901. this.currentDriver = e.currentTarget.id
  902. this.bodyScrollTop = e.detail.scrollTop
  903. this.bodyTime&&clearTimeout(this.bodyTime)
  904. this.bodyTime = setTimeout(()=>{
  905. this.currentDriver=null
  906. },200)
  907. },
  908. scrollToLeft(e){
  909. if(this.currentDriver1&&this.currentDriver1!==e.currentTarget.id)return
  910. this.currentDriver1 = e.currentTarget.id
  911. if(e.detail.direction==='left'&&this.headerTableLeft<10){
  912. this.headerTableLeft = 0
  913. }else if(e.detail.direction==='top'&&this.leftFiexScrollTop<10){
  914. this.leftFiexScrollTop = 0
  915. }
  916. this.bodyTime&&clearTimeout(this.bodyTime)
  917. this.bodyTime = setTimeout(()=>{
  918. this.currentDriver1=null
  919. },200)
  920. },
  921. scrollToFixedLeft(e){
  922. if(this.currentDriver1&&this.currentDriver1!==e.currentTarget.id)return
  923. this.currentDriver1 = e.currentTarget.id
  924. if(e.detail.direction==='top'&&this.bodyScrollTop<10){
  925. this.bodyScrollTop = 0
  926. }
  927. this.bodyTime&&clearTimeout(this.bodyTime)
  928. this.bodyTime = setTimeout(()=>{
  929. this.currentDriver1=null
  930. },200)
  931. },
  932. handleTableScrollLeft(e,type){
  933. if(this.currentDriver&&this.currentDriver!==e.currentTarget.id)return
  934. this.currentDriver = e.currentTarget.id
  935. this.bodyTableLeft = e.detail.scrollLeft
  936. this.headerFooterTableLeft = e.detail.scrollLeft
  937. this.bodyTime&&clearTimeout(this.bodyTime)
  938. this.bodyTime = setTimeout(()=>{
  939. this.currentDriver=null
  940. },200)
  941. },
  942. handleFooterTableScrollLeft(e){
  943. if(this.currentDriver&&this.currentDriver!==e.currentTarget.id)return
  944. this.currentDriver = e.currentTarget.id
  945. this.bodyTableLeft = e.detail.scrollLeft
  946. this.headerTableLeft = e.detail.scrollLeft
  947. this.bodyTime&&clearTimeout(this.bodyTime)
  948. this.bodyTime = setTimeout(()=>{
  949. this.currentDriver=null
  950. },200)
  951. }
  952. }
  953. }
  954. </script>
  955. <style lang="scss">
  956. .zb-table-fixed-left{
  957. /*去除左边滚动条 */
  958. scroll-view ::-webkit-scrollbar {
  959. display: none !important;
  960. width: 0 !important;
  961. height: 0 !important;
  962. -webkit-appearance: none;
  963. background: transparent;
  964. }
  965. }
  966. .zb-table-header{
  967. ///*去除头部滚动条 */
  968. scroll-view ::-webkit-scrollbar {
  969. display: none !important;
  970. width: 0 !important;
  971. height: 0 !important;
  972. -webkit-appearance: none;
  973. background: transparent;
  974. }
  975. }
  976. </style>
  977. <style lang="scss" scoped>
  978. .sorter-table{
  979. position: absolute;
  980. right: 2rpx;
  981. top:50%;
  982. transform:translateY(-50%);
  983. .sorter-table-icon{
  984. width: 0;
  985. height: 0;
  986. color: #dcdcdc;
  987. border-right: 8rpx solid transparent;
  988. border-left: 8rpx solid transparent;
  989. }
  990. .sorter-table-icon:first-child{
  991. border-bottom: 14rpx solid currentColor;
  992. }
  993. .sorter-table-icon:last-child{
  994. margin-top: 3rpx;
  995. border-top: 14rpx solid currentColor;
  996. }
  997. .sorting_desc{
  998. color: #2979ff;
  999. }
  1000. .sorting_asc{
  1001. color: #2979ff;
  1002. }
  1003. }
  1004. .checkbox-item{
  1005. display: flex;align-items: center;justify-content: center;width: 100%;height: 100%
  1006. }
  1007. .no-data{
  1008. width: 100%;
  1009. height: 80rpx;
  1010. display: flex;
  1011. justify-content: center;
  1012. align-items: center;
  1013. // border-bottom: 1px solid #e8e8e8;
  1014. }
  1015. .item-th{
  1016. position: relative;
  1017. flex-shrink: 0;
  1018. width: 200rpx;
  1019. overflow-wrap: break-word;
  1020. color: #222327;
  1021. font-weight: bold;
  1022. border-bottom: 2rpx solid #e8e8e8;
  1023. transition: background 0.3s;
  1024. padding-right: 8rpx;
  1025. word-break:keep-all; /* 不换行 */
  1026. white-space:nowrap; /* 不换行 */
  1027. overflow:hidden; /* 内容超出宽度时隐藏超出部分的内容 */
  1028. text-overflow:ellipsis; /* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
  1029. overflow-wrap: break-word;
  1030. &.nborder{
  1031. border: none;
  1032. }
  1033. }
  1034. .zb-table{
  1035. height: 100%;
  1036. overflow: hidden;
  1037. width: 100%;
  1038. display: flex;
  1039. flex-direction: column;
  1040. font-size: 28rpx;
  1041. position: relative;
  1042. .zb-table-content{
  1043. //height: 100%;
  1044. //flex: 1;
  1045. position: relative;
  1046. overflow: hidden;
  1047. }
  1048. .zb-table-fixed{
  1049. min-width: 100%;
  1050. }
  1051. .zb-table-body{
  1052. position: relative;
  1053. background: #fff;
  1054. transition: opacity 0.3s;
  1055. }
  1056. .item-tr{
  1057. display: flex;
  1058. //height: 41px;
  1059. }
  1060. .item-td{
  1061. flex-shrink: 0;
  1062. width:200rpx;
  1063. padding-left: 8rpx;
  1064. height: 64rpx;
  1065. line-height: 64rpx;
  1066. padding-right: 8rpx;
  1067. font-weight: 500;
  1068. color: #222327;
  1069. box-sizing: border-box;
  1070. word-break:keep-all; /* 不换行 */
  1071. white-space:nowrap; /* 不换行 */
  1072. overflow:hidden; /* 内容超出宽度时隐藏超出部分的内容 */
  1073. text-overflow:ellipsis; /* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
  1074. overflow-wrap: break-word;
  1075. border-bottom: 2rpx solid #e8e8e8;
  1076. &.nborder{
  1077. border: none;
  1078. }
  1079. //transition: background 0.3s;
  1080. }
  1081. .zb-table-fixed-left .zb-table-header{
  1082. overflow-y: hidden;
  1083. }
  1084. .zb-table-header {
  1085. overflow: hidden;
  1086. // background: #fafafa;
  1087. .item-th{
  1088. padding-left: 8rpx;
  1089. line-height: 78rpx;
  1090. height: 80rpx;
  1091. //display: flex;
  1092. //align-items: center;
  1093. box-sizing: border-box;
  1094. }
  1095. }
  1096. .zb-table-fixed-left .zb-table-fixed{
  1097. background: #fff;
  1098. }
  1099. .zb-table-fixed-right .zb-table-fixed{
  1100. background: #fff;
  1101. }
  1102. .zb-table-body-inner{
  1103. height: 100%;
  1104. // overflow: scroll;
  1105. }
  1106. .zb-table-fixed-left{
  1107. position: absolute;
  1108. top: 0;
  1109. z-index: 1;
  1110. overflow: hidden;
  1111. border-radius: 0;
  1112. height: 100%;
  1113. //transition: box-shadow 0.3s ease;
  1114. }
  1115. .odd{
  1116. background-color:rgba(249,249,249,0.6);
  1117. //height: 100%;
  1118. width: 100%;
  1119. }
  1120. .even{
  1121. background-color:white ;
  1122. //height: 100%;
  1123. width: 100%;
  1124. }
  1125. }
  1126. .scroll-left-fixed{
  1127. .zb-table-fixed-left {
  1128. left: 0;
  1129. box-shadow: 12rpx 0 12rpx -8rpx #ccc;
  1130. }
  1131. }
  1132. .zb-table-applet{
  1133. height: 100%;
  1134. //overflow: hidden;
  1135. width: 100%;
  1136. position: relative;
  1137. display: flex;
  1138. flex-direction: column;
  1139. font-size: 28rpx;
  1140. .zb-table-content{
  1141. //height: 100%;
  1142. flex: 1;
  1143. overflow: hidden;
  1144. position: relative;
  1145. }
  1146. .zb-table-fixed{
  1147. min-width: 100%;
  1148. width: fit-content;
  1149. }
  1150. .zb-table-body{
  1151. position: relative;
  1152. background: #fff;
  1153. transition: opacity 0.3s;
  1154. }
  1155. .item-tr{
  1156. display: flex;
  1157. //height: 41px;
  1158. }
  1159. .item-td{
  1160. flex-shrink: 0;
  1161. width: 200rpx;
  1162. padding-left: 8rpx;
  1163. height: 80rpx;
  1164. line-height: 80rpx;
  1165. padding-right:8rpx;
  1166. box-sizing: border-box;
  1167. word-break:keep-all; /* 不换行 */
  1168. white-space:nowrap; /* 不换行 */
  1169. overflow:hidden; /* 内容超出宽度时隐藏超出部分的内容 */
  1170. text-overflow:ellipsis; /* 当对象内文本溢出时显示省略标记(...) ;需与overflow:hidden;一起使用。*/
  1171. overflow-wrap: break-word;
  1172. border-bottom: 2rpx solid #e8e8e8;
  1173. //transition: background 0.3s;
  1174. }
  1175. .zb-table-header {
  1176. //overflow: hidden;
  1177. position: sticky;
  1178. top: 0;
  1179. z-index: 2;
  1180. //width: fit-content;
  1181. .item-th{
  1182. padding-left: 8rpx;
  1183. line-height: 78rpx;
  1184. height: 80rpx;
  1185. box-sizing: border-box;
  1186. background: #fafafa;
  1187. }
  1188. .zb-stick-side{
  1189. position: sticky;
  1190. top: 0;
  1191. left: 0;
  1192. z-index: 2;
  1193. //border-right: solid 1rpx #dbdbdb;
  1194. box-sizing: border-box;
  1195. background: #fafafa;
  1196. //box-shadow: 6px 0 6px -4px #ccc;
  1197. }
  1198. }
  1199. .zb-table-fixed-left .zb-table-fixed{
  1200. background: #fff;
  1201. }
  1202. .zb-table-fixed-right .zb-table-fixed{
  1203. background: #fff;
  1204. }
  1205. .zb-table-fixed-header .zb-table-body-inner{
  1206. height: 100%;
  1207. // overflow: scroll;
  1208. }
  1209. .zb-table-fixed-left{
  1210. position: absolute;
  1211. top: 0;
  1212. z-index: 1;
  1213. overflow: hidden;
  1214. border-radius: 0;
  1215. height: 100%;
  1216. //transition: box-shadow 0.3s ease;
  1217. }
  1218. .scroll-left-fixed{
  1219. .zb-table-fixed-left {
  1220. left: 0;
  1221. box-shadow: 12rpx 0 12rpx -8rpx #ccc;
  1222. }
  1223. }
  1224. .odd{
  1225. background-color:rgba(249,249,249,0.6);
  1226. //height: 100%;
  1227. width: 100%;
  1228. }
  1229. .even{
  1230. background-color:white ;
  1231. //height: 100%;
  1232. width: 100%;
  1233. }
  1234. .zb-table-tbody {
  1235. .zb-stick-side{
  1236. position: sticky;
  1237. left: 0;
  1238. z-index: 1;
  1239. box-sizing: border-box;
  1240. background:white;
  1241. //box-shadow: 6px 0 6px -2px #ccc;
  1242. }
  1243. .odd{
  1244. background:#f9f9f9;
  1245. //height: 100%;
  1246. width: 100%;
  1247. }
  1248. .even{
  1249. background:white ;
  1250. //height: 100%;
  1251. width: 100%;
  1252. }
  1253. }
  1254. .current-row{
  1255. .item-td{
  1256. background-color: #ecf5ff;
  1257. }
  1258. }
  1259. }
  1260. .current-row{
  1261. .item-td{
  1262. background-color: #ecf5ff;
  1263. }
  1264. }
  1265. .zb-table-header{
  1266. height: 80rpx;
  1267. }
  1268. </style>