Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. /* eslint-disable no-restricted-syntax */ /* eslint-disable guard-for-in */
  2. <template>
  3. <div>
  4. <div class="row">
  5. <div align="center" class="col">
  6. <float-label
  7. class="mb-3"
  8. label="Search"
  9. style="width: 50%; float: center;"
  10. >
  11. <input
  12. v-model="searchItem"
  13. class="form-control uniInput mt-3"
  14. placeholder="Search"
  15. />
  16. </float-label>
  17. </div>
  18. </div>
  19. <div class="d-flex justify-content-between">
  20. <div class="p-2" v-if="!hideSearch"></div>
  21. <div class="p-2" v-if="title">
  22. <h2>{{ title }}</h2>
  23. </div>
  24. <div class="p-2">
  25. <div class="d-flex flex-row">
  26. <div class="p2" v-if="showColumnChooser">
  27. <div
  28. class="btn-white-border cursor-pointer"
  29. data-toggle="modal"
  30. data-target="#myModal"
  31. >
  32. Column Chooser
  33. </div>
  34. <div class="col-md-12">
  35. <div id="myModal" class="modal fade" role="dialog">
  36. <div class="modal-dialog modal-lg" style="width: 500px;">
  37. <!-- Modal content-->
  38. <div class="modal-content">
  39. <div class="modal-header">
  40. <h5>Column Chooser</h5>
  41. <button type="button" class="close" data-dismiss="modal">
  42. &times;
  43. </button>
  44. </div>
  45. <div style="margin-bottom: 50px;">
  46. <ListViewControl
  47. :items="allColumn"
  48. @checkItem="checkItem"
  49. />
  50. </div>
  51. </div>
  52. </div>
  53. </div>
  54. </div>
  55. </div>
  56. <div class="p2" v-if="selectedItems.length > 0">
  57. <div
  58. class="btn-white-border cursor-pointer"
  59. @click="onClearSelected()"
  60. >
  61. Clear Selected
  62. </div>
  63. </div>
  64. <div class="p2" v-if="showNew">
  65. <div class="btn-white-border cursor-pointer" @click="onNew()">
  66. New
  67. </div>
  68. </div>
  69. </div>
  70. </div>
  71. </div>
  72. <div style="height: 5px;"></div>
  73. <div v-if="items && items.length > 0" class="table-responsive">
  74. <table
  75. id="table"
  76. class="table table-striped"
  77. :class="{
  78. 'table table-hover': 1 === 1,
  79. 'table-sm': compact,
  80. 'table-bordered': bordered,
  81. }"
  82. >
  83. <thead>
  84. <tr class="dnd-moved">
  85. <th v-for="(column, c) in Columns" :key="c">
  86. <div
  87. @click="sortBy(column)"
  88. @mouseover="hover = c"
  89. @mouseleave="hover = -1"
  90. :class="{ active: hover === c }"
  91. >
  92. <div class="d-flex bd-highlight">
  93. <div
  94. v-if="displayHeaders.length === 0"
  95. class="p-2 w-100 bd-highlight"
  96. >
  97. {{ column | toProper }}
  98. </div>
  99. <div v-else class="p-2 w-100 bd-highlight">
  100. {{
  101. displayHeaders[c] !== ''
  102. ? displayHeaders[c]
  103. : column | toProper
  104. }}
  105. </div>
  106. <div class="p-2 flex-shrink-1 bd-highlight">
  107. <img
  108. src="../../../public/img/sort-up.png"
  109. height="8px;"
  110. v-if="sortKey === column && reverse"
  111. />
  112. <img
  113. src="../../../public/img/sort-down.png"
  114. height="8px;"
  115. v-if="sortKey === column && !reverse"
  116. />
  117. </div>
  118. </div>
  119. </div>
  120. </th>
  121. <th v-if="showCustomAction"></th>
  122. <th v-if="editable"></th>
  123. <th v-if="deleteable"></th>
  124. </tr>
  125. </thead>
  126. <tbody>
  127. <tr
  128. v-for="(item, i) in DisplayItems"
  129. :key="i"
  130. @click="onRowClick(item, i)"
  131. :class="{ selected: isSelected(i), 'cursor-pointer': allowSelect }"
  132. >
  133. <td v-for="(column, c) in Columns" :key="c">
  134. <div v-if="displayFormats.length === 0">
  135. {{
  136. isObject(item[column]) ? item[column].display : item[column]
  137. }}
  138. </div>
  139. <div
  140. v-else-if="
  141. displayFormats.length > 0 && displayFormats[c] === 'date'
  142. "
  143. >
  144. <div v-if="item[column] !== '0001-01-01T00:00:00'">
  145. {{
  146. isObject(item[column])
  147. ? item[column].display
  148. : item[column] | toDate
  149. }}
  150. </div>
  151. </div>
  152. <div
  153. style="padding-left: 10px; white-space: nowrap;"
  154. v-else-if="
  155. displayFormats.length > 0 && displayFormats[c] === 'money'
  156. "
  157. >
  158. {{
  159. isObject(item[column])
  160. ? item[column].display
  161. : item[column] | toCurrency
  162. }}
  163. </div>
  164. <div
  165. v-else-if="
  166. displayFormats.length > 0 && displayFormats[c] === 'image'
  167. "
  168. >
  169. <img
  170. :src="item[column]"
  171. style="height: 100px; width: 100px; object-fit: cover;"
  172. />
  173. </div>
  174. <div v-else>
  175. {{
  176. isObject(item[column]) ? item[column].display : item[column]
  177. }}
  178. </div>
  179. </td>
  180. <td v-if="showCustomAction" class="my-width">
  181. <button
  182. type="button"
  183. class="btn my-btn"
  184. @click="onCustomClick(item)"
  185. >
  186. <p v-if="CustomActionHeading !== 'Publish'">
  187. {{ CustomActionHeading }}
  188. </p>
  189. <img
  190. v-else
  191. src="../../../public/img/icons/Upload.png"
  192. height="25"
  193. width="25"
  194. />
  195. </button>
  196. </td>
  197. <td v-if="editable" class="my-width">
  198. <a @click="onEdit(item)" class="p-3">
  199. <img
  200. src="../../../public/img/icons/Edit.png"
  201. height="25"
  202. width="25"
  203. />
  204. </a>
  205. <!-- <button type="button" class="btn my-btn" @click="onEdit(item)">Edit</button> -->
  206. </td>
  207. <td v-if="deleteable" class="my-width">
  208. <a @click="onDelete(item)" class="p-3">
  209. <img
  210. src="../../../public/img/icons/delete.png"
  211. height="25"
  212. width="25"
  213. />
  214. </a>
  215. <!-- <button type="button" class="btn my-btn"
  216. @click="onDelete(item)">Delete</button> -->
  217. </td>
  218. </tr>
  219. </tbody>
  220. </table>
  221. <div class="d-flex justify-content-between" v-if="showPager">
  222. <div class="p-1">
  223. {{
  224. currentPage +
  225. ' / ' +
  226. PageCount +
  227. (!hideItemCount ? ' - (' + FilteredItems.length + ' items)' : '')
  228. }}
  229. </div>
  230. <div class="p-1">
  231. <BasePagination
  232. :currentPage="currentPage"
  233. :pageCount="PageCount"
  234. @nextPage="pageChangeHandle('next')"
  235. @previousPage="pageChangeHandle('previous')"
  236. @loadPage="pageChangeHandle"
  237. />
  238. </div>
  239. <div class="p-2">
  240. <div class="d-flex flex-row">
  241. <div>
  242. <select
  243. class="form-control"
  244. v-model="visibleItemsPerPageCount"
  245. @change="onChangeItemsPerPage()"
  246. >
  247. <option v-for="(item, i) in itemsPerPageList" :key="i">
  248. {{ item }}
  249. </option>
  250. </select>
  251. </div>
  252. </div>
  253. </div>
  254. </div>
  255. </div>
  256. <div v-else>
  257. <Alert :text="'No items found ^-^'" :type="'INFO'" />
  258. </div>
  259. </div>
  260. </template>
  261. <script>
  262. /* eslint-disable */
  263. import _ from 'lodash'
  264. import ItemsPerPageList from '../../assets/staticData/itemsPerPage'
  265. import BasePagination from './basePagination.vue'
  266. import Alert from './alert.vue'
  267. import ListViewControl from './listViewControl.vue'
  268. export default {
  269. components: {
  270. BasePagination,
  271. Alert,
  272. ListViewControl,
  273. },
  274. mounted() {
  275. try {
  276. // to assign initial value to itemsPerPage
  277. if (this.itemsPerPageList && this.itemsPerPageList.length > 0) {
  278. const [startItem] = this.itemsPerPageList
  279. this.visibleItemsPerPageCount = startItem
  280. }
  281. } catch (error) {
  282. throw error
  283. }
  284. this.getInitColumn()
  285. },
  286. props: {
  287. compact: {
  288. default: false,
  289. },
  290. allowSelect: {
  291. default: true,
  292. },
  293. allowMultipleSelect: {
  294. default: false,
  295. },
  296. hideSearch: {
  297. default: false,
  298. },
  299. showNew: {
  300. default: true,
  301. },
  302. items: undefined,
  303. editable: {
  304. default: false,
  305. },
  306. deleteable: {
  307. default: false,
  308. },
  309. columnCount: {
  310. default: 6,
  311. },
  312. showPager: {
  313. default: true,
  314. },
  315. title: {
  316. default: undefined,
  317. },
  318. hideItemCount: {
  319. default: false,
  320. },
  321. currentPage: {
  322. default: 1,
  323. },
  324. bordered: {
  325. default: false,
  326. },
  327. striped: {
  328. default: true,
  329. },
  330. showColumnChooser: {
  331. default: true,
  332. },
  333. displayColumns: {
  334. type: Array,
  335. default: () => [],
  336. },
  337. displayFormats: {
  338. type: Array,
  339. default: () => [],
  340. },
  341. displayHeaders: {
  342. type: Array,
  343. default: () => [],
  344. },
  345. showCustomAction: {
  346. default: false,
  347. },
  348. CustomActionHeading: {
  349. default: '',
  350. },
  351. CustomActionCondition: {
  352. default: '',
  353. },
  354. },
  355. data() {
  356. return {
  357. hover: -1,
  358. selectedItems: [],
  359. showControl: false,
  360. sortKey: 'id',
  361. reverse: false,
  362. searchItem: '',
  363. visibleItemsPerPageCount: 20,
  364. itemsPerPageList: ItemsPerPageList,
  365. visibleColumn: [],
  366. allColumn: [],
  367. }
  368. },
  369. methods: {
  370. checkItem(column, show) {
  371. const list = []
  372. for (const i in this.allColumn) {
  373. const item = this.allColumn[i]
  374. if (item && item.column === column) {
  375. item.show = show
  376. }
  377. list.push(item)
  378. }
  379. this.allColumn = list
  380. },
  381. getInitColumn() {
  382. const list = []
  383. const listAll = []
  384. if (this.items) {
  385. for (const i in Object.keys(this.items)) {
  386. const item = this.items[i]
  387. for (const o in Object.keys(item)) {
  388. if (
  389. !listAll.includes(Object.keys(item)[o]) &&
  390. !Array.isArray(Object.values(item)[o])
  391. ) {
  392. const columnName = Object.keys(item)[o]
  393. if (!listAll.some((x) => x.column === columnName)) {
  394. listAll.push({
  395. column: columnName,
  396. show:
  397. _.filter(listAll, (x) => x.show).length < this.columnCount,
  398. })
  399. }
  400. }
  401. }
  402. }
  403. }
  404. this.allColumn = listAll
  405. },
  406. onClearSelected() {
  407. this.selectedItems = []
  408. this.$emit('onClearSelected')
  409. },
  410. isSelected(i) {
  411. const ind = this.getActualIndex(i)
  412. return _.some(this.selectedItems, (x) => x === ind)
  413. },
  414. onNew() {
  415. this.$emit('onNew')
  416. },
  417. isObject(item) {
  418. return !!item && item.constructor === Object
  419. },
  420. isDate(item) {
  421. return !!item && item.constructor === Date
  422. },
  423. isDecimal(item) {
  424. if (!!item && item.constructor === Number && item.indexOf('.') > 0) {
  425. return true
  426. }
  427. return false
  428. },
  429. isImage(item) {
  430. return (
  431. !!item &&
  432. item.constructor === String &&
  433. item.length > 9 &&
  434. item.substring(0, 9) === 'data:image'
  435. )
  436. },
  437. onEdit(item) {
  438. this.$emit('onEdit', item)
  439. },
  440. onDelete(item) {
  441. this.$emit('onDelete', item)
  442. },
  443. onCustomClick(item) {
  444. this.$emit('onCustomClick', item)
  445. },
  446. onRowClick(item, i) {
  447. const ind = this.getActualIndex(i)
  448. if (_.some(this.selectedItems, (x) => x === ind)) {
  449. this.selectedItems = this.selectedItems.filter((x) => x !== ind)
  450. } else {
  451. if (!this.allowMultipleSelect) {
  452. this.selectedItems = []
  453. }
  454. this.selectedItems.push(item)
  455. }
  456. this.$emit('onRowClick', this.selectedItems)
  457. },
  458. getActualIndex(index) {
  459. return (this.currentPage - 1) * this.visibleItemsPerPageCount + index
  460. },
  461. changeColumn(title, checked) {
  462. if (checked) {
  463. this.myColumns.push(title)
  464. } else {
  465. const ind = this.myColumns.indexOf(title)
  466. if (ind > -1) {
  467. this.myColumns.splice(ind, 1)
  468. }
  469. }
  470. },
  471. onControlVisibilityChange() {
  472. this.showControl = !this.showControl
  473. },
  474. sortBy(sortKey) {
  475. this.reverse = this.sortKey === sortKey ? !this.reverse : false
  476. this.sortKey = sortKey
  477. },
  478. async pageChangeHandle(value) {
  479. console.log(value)
  480. switch (value) {
  481. case 'next':
  482. this.currentPage += 1
  483. break
  484. case 'previous':
  485. this.currentPage -= 1
  486. break
  487. default:
  488. this.currentPage = value
  489. }
  490. },
  491. onChangeItemsPerPage() {
  492. if (this.currentPage !== 1) {
  493. this.currentPage = 1
  494. }
  495. },
  496. inArray(array, value) {
  497. const lenght = array.length
  498. for (let i = 0; i < lenght; i++) {
  499. if (array[i] === value) return true
  500. }
  501. return false
  502. },
  503. },
  504. computed: {
  505. ListWidth() {
  506. if (this.showControl) {
  507. return 'col-md-9'
  508. }
  509. return 'col-md-12'
  510. },
  511. SortDirection() {
  512. return this.reverse ? 'desc' : 'asc'
  513. },
  514. PageCount() {
  515. return this.visibleItemsPerPageCount !== 0
  516. ? Math.ceil(this.FilteredItems.length / this.visibleItemsPerPageCount)
  517. : 1
  518. },
  519. Columns() {
  520. const listColumns = []
  521. if (!this.allColumn || this.allColumn.length === 0) {
  522. this.getInitColumn()
  523. }
  524. if (this.displayColumns.length > 0) {
  525. for (let i = 0; i < this.displayColumns.length; i++) {
  526. listColumns.push(this.displayColumns[i])
  527. }
  528. } else {
  529. const list = _.filter(this.allColumn, (x) => x.show)
  530. for (const i in list) {
  531. const item = list[i]
  532. if (item) {
  533. listColumns.push(item.column)
  534. }
  535. }
  536. }
  537. return listColumns
  538. },
  539. AllColumns() {
  540. const list = []
  541. if (this.items) {
  542. }
  543. return list
  544. },
  545. FilteredItems() {
  546. const list = _.filter(this.items, (item) =>
  547. Object.values(item).some(
  548. (i) =>
  549. JSON.stringify(i)
  550. .toLowerCase()
  551. .indexOf(this.searchItem.toLowerCase()) > -1,
  552. ),
  553. )
  554. return _.orderBy(list, this.sortKey, this.SortDirection)
  555. },
  556. DisplayItems() {
  557. const list = this.FilteredItems
  558. const startSlice = (this.currentPage - 1) * this.visibleItemsPerPageCount
  559. let endSlice = this.currentPage * this.visibleItemsPerPageCount
  560. if (endSlice > list.length) {
  561. endSlice = list.length
  562. }
  563. return list.slice(startSlice, endSlice)
  564. },
  565. GetAllColumn() {},
  566. },
  567. }
  568. </script>
  569. <style scoped>
  570. th[draggable] a,
  571. th[draggable] {
  572. cursor: move;
  573. }
  574. th[draggable] a:hover,
  575. th[draggable] a {
  576. display: block;
  577. text-decoration: none;
  578. color: #333333;
  579. }
  580. .table-striped > tbody > tr:nth-child(2n + 1) > td,
  581. .table-striped > tbody > tr:nth-child(2n + 1) > th {
  582. background-color: rgba(225, 225, 225, 0.8);
  583. }
  584. .active {
  585. background-color: rgba(255, 255, 255, 0.5);
  586. cursor: pointer;
  587. }
  588. .table > tbody > tr > td {
  589. vertical-align: middle;
  590. }
  591. .my-width {
  592. width: 20px;
  593. }
  594. .drag {
  595. background-color: rgba(0, 255, 0, 0.35);
  596. opacity: 0.25;
  597. }
  598. .dnd-drag {
  599. opacity: 0.25;
  600. }
  601. .over {
  602. background-color: rgba(0, 0, 255, 0.35);
  603. }
  604. .my-border {
  605. border: solid 3px silver;
  606. }
  607. .selected {
  608. background-color: rgba(96, 203, 235, 0.5);
  609. border: white 2px double;
  610. }
  611. .selected:hover {
  612. background-color: rgba(96, 203, 235, 0.85);
  613. }
  614. .btn-width {
  615. width: 125px;
  616. }
  617. .table-title {
  618. padding: 5px;
  619. border: rgba(200, 200, 200, 0.66) double 2px;
  620. border-radius: 5px;
  621. background-color: rgba(96, 203, 235, 0.25);
  622. }
  623. .table-title:hover {
  624. background-color: rgba(96, 203, 235, 0.4);
  625. }
  626. .table-header {
  627. background-color: rgba(200, 200, 200, 0.66);
  628. }
  629. .my-table {
  630. border: rgba(150, 150, 150, 0.75) 3px double;
  631. }
  632. </style>