AdvancedTable.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. <template>
  2. <div>
  3. <div>
  4. <button
  5. v-for="column in orderedColumns"
  6. :key="column.name"
  7. class="button"
  8. @click="toggleColumnVisibility(column)"
  9. >
  10. {{
  11. `${
  12. this.enabledColumns.indexOf(column.name) !== -1
  13. ? "Hide"
  14. : "Show"
  15. } ${column.name} column`
  16. }}
  17. </button>
  18. </div>
  19. <table class="table">
  20. <thead>
  21. <draggable
  22. item-key="name"
  23. v-model="orderedColumns"
  24. v-bind="columnDragOptions"
  25. tag="tr"
  26. >
  27. <template #item="{ element: column }">
  28. <th
  29. :class="{ sortable: column.sortable }"
  30. v-if="enabledColumns.indexOf(column.name) !== -1"
  31. @click="changeSort(column)"
  32. >
  33. {{ column.displayName }}
  34. <span
  35. v-if="
  36. column.sortable && sort[column.sortProperty]
  37. "
  38. >({{ sort[column.sortProperty] }})</span
  39. >
  40. <input
  41. v-if="column.sortable"
  42. placeholder="Filter"
  43. @click.stop
  44. @keyup.enter="changeFilter(column, $event)"
  45. />
  46. </th>
  47. </template>
  48. </draggable>
  49. </thead>
  50. <tbody>
  51. <tr v-for="item in data" :key="item._id">
  52. <td
  53. v-for="column in sortedFilteredColumns"
  54. :key="`${item._id}-${column.name}`"
  55. >
  56. <slot
  57. :name="`column-${column.name}`"
  58. :item="item"
  59. ></slot>
  60. </td>
  61. </tr>
  62. </tbody>
  63. </table>
  64. <br />
  65. <div class="control">
  66. <label class="label">Items per page</label>
  67. <p class="control select">
  68. <select v-model.number="pageSize" @change="getData()">
  69. <option value="10">10</option>
  70. <option value="25">25</option>
  71. <option value="50">50</option>
  72. <option value="100">100</option>
  73. <option value="250">250</option>
  74. <option value="500">500</option>
  75. <option value="1000">1000</option>
  76. </select>
  77. </p>
  78. </div>
  79. <br />
  80. <p>Page {{ page }} / {{ lastPage }}</p>
  81. <br />
  82. <button class="button is-primary" @click="changePage(page - 1)">
  83. Go to previous page</button
  84. >&nbsp;
  85. <button class="button is-primary" @click="changePage(page + 1)">
  86. Go to next page</button
  87. >&nbsp;
  88. <button class="button is-primary" @click="changePage(1)">
  89. Go to first page</button
  90. >&nbsp;
  91. <button class="button is-primary" @click="changePage(lastPage)">
  92. Go to last page
  93. </button>
  94. </div>
  95. </template>
  96. <script>
  97. import { mapGetters } from "vuex";
  98. import draggable from "vuedraggable";
  99. import Toast from "toasters";
  100. import ws from "@/ws";
  101. export default {
  102. components: {
  103. draggable
  104. },
  105. props: {
  106. columns: { type: Array, default: null },
  107. dataAction: { type: String, default: null }
  108. },
  109. data() {
  110. return {
  111. page: 1,
  112. pageSize: 10,
  113. data: [],
  114. count: 0, // TODO Rename
  115. sort: {},
  116. filter: {},
  117. orderedColumns: [],
  118. enabledColumns: [],
  119. columnDragOptions() {
  120. return {
  121. animation: 200,
  122. group: "columns",
  123. disabled: false,
  124. ghostClass: "draggable-list-ghost",
  125. filter: ".ignore-elements",
  126. fallbackTolerance: 50
  127. };
  128. }
  129. };
  130. },
  131. computed: {
  132. properties() {
  133. return Array.from(
  134. new Set(
  135. this.sortedFilteredColumns.flatMap(
  136. column => column.properties
  137. )
  138. )
  139. );
  140. },
  141. lastPage() {
  142. return Math.ceil(this.count / this.pageSize);
  143. },
  144. sortedFilteredColumns() {
  145. return this.orderedColumns.filter(
  146. column => this.enabledColumns.indexOf(column.name) !== -1
  147. );
  148. },
  149. ...mapGetters({
  150. socket: "websockets/getSocket"
  151. })
  152. },
  153. mounted() {
  154. this.orderedColumns = this.columns;
  155. this.enabledColumns = this.columns.map(column => column.name);
  156. ws.onConnect(this.init);
  157. },
  158. methods: {
  159. init() {
  160. this.getData();
  161. },
  162. getData() {
  163. this.socket.dispatch(
  164. this.dataAction,
  165. this.page,
  166. this.pageSize,
  167. this.properties,
  168. this.sort,
  169. this.filter,
  170. res => {
  171. console.log(111, res);
  172. new Toast(res.message);
  173. if (res.status === "success") {
  174. const { data, count } = res.data;
  175. this.data = data;
  176. this.count = count;
  177. }
  178. }
  179. );
  180. },
  181. changePage(page) {
  182. if (page < 1) return;
  183. if (page > this.lastPage) return;
  184. if (page === this.page) return;
  185. this.page = page;
  186. this.getData();
  187. },
  188. changeSort(column) {
  189. if (column.sortable) {
  190. const { sortProperty } = column;
  191. if (this.sort[sortProperty] === undefined)
  192. this.sort[sortProperty] = "ascending";
  193. else if (this.sort[sortProperty] === "ascending")
  194. this.sort[sortProperty] = "descending";
  195. else if (this.sort[sortProperty] === "descending")
  196. delete this.sort[sortProperty];
  197. this.getData();
  198. }
  199. },
  200. changeFilter(column, event) {
  201. if (column.filterable) {
  202. const { value } = event.target;
  203. const { filterProperty } = column;
  204. if (this.filter[filterProperty] !== undefined && value === "") {
  205. delete this.filter[filterProperty];
  206. } else if (this.filter[filterProperty] !== value) {
  207. this.filter[filterProperty] = value;
  208. } else return;
  209. this.getData();
  210. }
  211. },
  212. toggleColumnVisibility(column) {
  213. if (this.enabledColumns.indexOf(column.name) !== -1) {
  214. this.enabledColumns.splice(
  215. this.enabledColumns.indexOf(column.name),
  216. 1
  217. );
  218. } else {
  219. this.enabledColumns.push(column.name);
  220. }
  221. this.getData();
  222. }
  223. }
  224. };
  225. </script>
  226. <style lang="scss" scoped>
  227. .table {
  228. .sortable {
  229. cursor: pointer;
  230. }
  231. }
  232. </style>