Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.71 KB | None | 0 0
  1. <template>
  2. <div class="seats-group">
  3. <b-jumbotron
  4. :header="sectorName"
  5. >
  6. <div class="row">
  7. <div class="col-12 col-xl-6">
  8. <b-button
  9. v-if="!isNameChanging"
  10. variant="primary"
  11. size="sm"
  12. @click="showNameChanging"
  13. >
  14. Изменить название сектора
  15. </b-button>
  16.  
  17. <template
  18. v-else
  19. class="mb-3"
  20. >
  21. <b-form-group>
  22. <b-form-input
  23. v-model="sectorNameNew"
  24. type="text"
  25. />
  26. </b-form-group>
  27.  
  28. <b-button
  29. variant="success"
  30. size="sm"
  31. @click="renameSector"
  32. >
  33. Сохранить
  34. </b-button>
  35.  
  36. <b-button
  37. variant="danger"
  38. size="sm"
  39. class="ml-2"
  40. @click="isNameChanging = !isNameChanging"
  41. >
  42. Отмена
  43. </b-button>
  44. </template>
  45. </div>
  46. </div>
  47.  
  48. <div class="row">
  49. <div class="col-12">
  50. <div class="h4 my-3">
  51. Сгенерировать сетку
  52. </div>
  53. </div>
  54. <div class="col-12 col-xl-6">
  55. <b-form-group
  56. label-cols-sm="6"
  57. label="Количество рядов в секторе"
  58. label-for="rows"
  59. >
  60. <b-form-input
  61. v-model="rows"
  62. id="rows"
  63. type="number"
  64. :disabled="showGrid"
  65. />
  66. </b-form-group>
  67. <b-form-group
  68. label-cols-sm="6"
  69. label="Количество мест в ряду"
  70. label-for="columns"
  71. >
  72. <b-form-input
  73. v-model="columns"
  74. id="columns"
  75. type="number"
  76. :disabled="showGrid"
  77. />
  78. </b-form-group>
  79.  
  80. <div class="mt-2">
  81. <b-button
  82. variant="primary"
  83. :disabled="showGrid"
  84. @click="generateGrid"
  85. >
  86. Сгенерировать
  87. </b-button>
  88.  
  89. <b-button
  90. variant="success"
  91. class="ml-2"
  92. @click="saveGrid"
  93. >
  94. Сохранить
  95. </b-button>
  96. </div>
  97.  
  98. <div class="mt-4" v-if="showGrid">
  99. <b-button
  100. variant="success"
  101. size="sm"
  102. class="mr-2"
  103. @click="addRow"
  104. >
  105. Добавить ряд
  106. </b-button>
  107.  
  108. <b-button
  109. variant="warning"
  110. size="sm"
  111. class="mr-2"
  112. :disabled="disableDivideButton"
  113. @click="addTypes"
  114. >
  115. Разделить на типы
  116. </b-button>
  117.  
  118. <b-button
  119. variant="primary"
  120. size="sm"
  121. class="mr-2"
  122. @click="rotateSector"
  123. >
  124. Вращать
  125. </b-button>
  126.  
  127. <div class="mt-2">
  128. <b-button
  129. variant=""
  130. size="sm"
  131. @click="$emit('close')"
  132. class="mr-2"
  133. >
  134. К списку секторов
  135. </b-button>
  136.  
  137. <b-button
  138. variant="info"
  139. size="sm"
  140. class="mr-2"
  141. @click="goToSector('next')"
  142. >
  143. Следующий сектор
  144. </b-button>
  145.  
  146. <b-button
  147. variant="info"
  148. size="sm"
  149. @click="goToSector('prev')"
  150. >
  151. Предыдущий сектор
  152. </b-button>
  153. </div>
  154. </div>
  155. </div>
  156.  
  157. <div class="col-12 col-xl-6">
  158. <div
  159. v-if="showGrid"
  160. class="grid"
  161. >
  162. <div class="row">
  163. <div
  164. v-if="Object.keys(grid).length"
  165. class="col-12 d-flex flex-column-reverse"
  166. >
  167. <div
  168. v-for="row in Object.keys(grid)"
  169. :key="row"
  170. class="grid__row d-flex align-items-center"
  171. >
  172. <p
  173. v-if="columns"
  174. class="text-bold mb-0 mr-2"
  175. >
  176. Ряд {{ Number(row) }}
  177. </p>
  178. <div
  179. v-for="col in grid[row]"
  180. :key="Math.random() * (col + 1)"
  181. :data-row="Number(row)"
  182. :data-seat="Number(col)"
  183. :data-hidden="!col"
  184. class="grid__seat"
  185. >
  186. {{ col }}
  187. </div>
  188. </div>
  189. </div>
  190. </div>
  191. </div>
  192. </div>
  193. </div>
  194.  
  195. <component
  196. :is="'ExtendedMenu'"
  197. :isVisible="showDropDown"
  198. :name="sectorName"
  199. :posX="dropDownX"
  200. :posY="dropDownY"
  201. >
  202. <ul class="my-dropdown__list">
  203. <li
  204. v-if="Object.keys(groups).length"
  205. class="no-hover"
  206. >
  207. Добавить в группу
  208.  
  209. <b-form-select
  210. v-model="selectedGroup"
  211. size="sm"
  212. class="mt-3"
  213. :options="Object.keys(groups)"
  214. @change="addSeatToGroup"
  215. />
  216. </li>
  217. <li @click="removeSeatFromGrid">
  218. Удалить
  219. </li>
  220. <li @click="showDropDown = false">
  221. Закрыть
  222. </li>
  223. </ul>
  224. </component>
  225. </b-jumbotron>
  226.  
  227. <b-modal
  228. ref="not-saved-warning-modal"
  229. hide-footer
  230. content-class="shadow"
  231. title="Изменения не сохранены"
  232. >
  233. <div class="d-block text-center">
  234. <p>
  235. Вы изменили данные сектора, но не сохранили изменения.
  236. <br>
  237. Сохранить?
  238. </p>
  239. </div>
  240. <div class="d-flex justify-content-center">
  241. <b-button
  242. class="mt-3"
  243. variant="success"
  244. @click="saveGridFromModal"
  245. >
  246. Сохранить
  247. </b-button>
  248. <b-button
  249. class="mt-3 ml-3"
  250. variant="outline-danger"
  251. size="sm"
  252. @click="cancelSaveFromModal"
  253. >
  254. Отмена
  255. </b-button>
  256. </div>
  257. </b-modal>
  258.  
  259. <b-modal
  260. ref="one-sector-warning-modal"
  261. hide-footer
  262. content-class="shadow"
  263. title="Другие сектора отсутствуют"
  264. >
  265. <div class="d-block text-center">
  266. <p>
  267. Отредактируйте другие сектора для перехода к ним.
  268. </p>
  269. </div>
  270. <div class="d-flex justify-content-center">
  271. <b-button
  272. class="mt-3"
  273. variant="outline-danger"
  274. size="sm"
  275. @click="$refs['one-sector-warning-modal'].hide()"
  276. >
  277. Закрыть
  278. </b-button>
  279. </div>
  280. </b-modal>
  281. </div>
  282. </template>
  283.  
  284. <script lang="ts">
  285. import {Component, Prop, Watch, Vue} from 'vue-property-decorator';
  286. import {Getter, Action} from 'vuex-class';
  287. import ExtendedMenu from '@/components/Dropdown/ExtendedMenu.vue';
  288. import {IScheme, ISector} from '@/interfaces/scheme';
  289.  
  290. interface VueWithModals extends Vue {
  291. show: () => void;
  292. hide: () => void;
  293. }
  294.  
  295. interface IGrid {
  296. [k: string]: number[];
  297. }
  298.  
  299. const namespace = 'scheme';
  300.  
  301. @Component({
  302. components: {
  303. ExtendedMenu
  304. }
  305. })
  306. export default class SeatsGroup extends Vue {
  307. @Prop({required: true}) sector!: ISector;
  308.  
  309. @Getter('schemeData', {namespace}) schemeData!: IScheme;
  310. @Action('changeSectorGrid', {namespace}) changeSectorGrid!:
  311. (payload: ISector) => Promise<void>;
  312.  
  313. sectorToShow: ISector | null = null;
  314. rows: string = '';
  315. columns: string = '';
  316. count: number = 0;
  317. selectedRow: number = 0;
  318. selectedSeat: number = 0;
  319. grid: IGrid = {};
  320. showGrid: boolean = false;
  321. rotate: number = 0;
  322. sectorNameNew: string = '';
  323. isNameChanging: boolean = false;
  324. isDivided: boolean = false;
  325. selectedGroup: string | null = null;
  326. isSaved: boolean = false;
  327. direction: null | string = null;
  328. groups: any = {};
  329. showDropDown: boolean = false;
  330. dropDownX: number = 0;
  331. dropDownY: number = 0;
  332.  
  333. @Watch('sectorToShow', {deep: true})
  334. onSectorToShowChanged(newVal: ISector): void {
  335. if (newVal) {
  336. this.init();
  337. }
  338. }
  339.  
  340. mounted() {
  341. this.sectorToShow = this.sector;
  342. this.init();
  343.  
  344. document.addEventListener(
  345. 'click',
  346. (e: MouseEvent) => this.handleClick(e)
  347. );
  348. }
  349.  
  350. /**
  351. * @description Установить свойства сектора
  352. */
  353. init(): void {
  354. if (this.sector) {
  355. this.resetGrid();
  356. const {grid, columns, rows, count, rotate} = this.sector;
  357. this.grid = grid as IGrid;
  358.  
  359. if (rows) {
  360. this.rows = String(rows);
  361. }
  362.  
  363. if (columns) {
  364. this.columns = String(columns);
  365. }
  366.  
  367. if (count) {
  368. this.count = count;
  369. }
  370.  
  371. if (rotate) {
  372. this.rotate = rotate;
  373. }
  374. }
  375.  
  376. if (this.isNameChanging) {
  377. this.isNameChanging = false;
  378. }
  379.  
  380. if (this.sectorNameNew) {
  381. this.sectorNameNew = '';
  382. }
  383.  
  384. if (this.rows && this.columns) {
  385. this.generateGrid();
  386. } else {
  387. this.resetGrid();
  388. }
  389. }
  390.  
  391. /**
  392. * @description Сгенерировать сетку мест
  393. */
  394. generateGrid(): void {
  395. const rows = Number(this.rows);
  396. const columns = Number(this.columns);
  397.  
  398. if (rows > 0 && columns > 0) {
  399. if (Object.keys(this.grid).length) {
  400. this.grid = {};
  401. }
  402.  
  403. for (let row = 1; row <= rows; row++) {
  404. this.grid[row] = [];
  405.  
  406. for (let col = 1; col <= columns; col++) {
  407. this.grid[row].push(col);
  408. }
  409. }
  410.  
  411. this.count = rows * columns;
  412. this.showGrid = true;
  413. }
  414. }
  415.  
  416. /**
  417. * @description Сохранить изменения в объект данных схемы
  418. */
  419. async saveGrid(): Promise<void> {
  420. this.isSaved = true;
  421.  
  422. const payload = {
  423. ...this.sector,
  424. rows: Number(this.rows),
  425. columns: Number(this.columns),
  426. count: this.count,
  427. grid: this.grid,
  428. rotate: this.rotate
  429. };
  430.  
  431. if (Object.keys(this.groups).length) {
  432. payload.groups = this.groups;
  433. }
  434.  
  435. await this.changeSectorGrid(payload);
  436. }
  437.  
  438. /**
  439. * @description Сбросить данные сетки мест в секторе
  440. */
  441. resetGrid(): void {
  442. this.showGrid = false;
  443. this.isSaved = false;
  444. this.grid = {};
  445. this.rows = '';
  446. this.columns = '';
  447. this.rotate = 0;
  448. }
  449.  
  450. /**
  451. * @description Добавить ряд
  452. */
  453. addRow(): void {
  454. const length = Object.keys(this.grid).length;
  455. const rows = Number(this.rows);
  456. const columns = Number(this.columns);
  457.  
  458. this.grid[length + 1] = [];
  459. for (let col = 1; col <= columns; col++) {
  460. this.grid[length + 1].push(col);
  461. }
  462.  
  463. this.rows = String(rows + 1);
  464. this.count = this.count + columns;
  465. }
  466.  
  467. /**
  468. * @description Добавить вращение сектора
  469. * (в случае, если он должен быть расположен под углом)
  470. */
  471. rotateSector(): void {
  472. if ((this.rotate + 45) < 360) {
  473. this.rotate += 45;
  474. } else if (this.rotate === 360) {
  475. this.rotate = 0;
  476. } else {
  477. this.rotate = (this.rotate + 45) - 360;
  478. }
  479.  
  480. this.changeSectorGrid({
  481. name: this.sectorName,
  482. rotate: this.rotate
  483. });
  484. }
  485.  
  486. /**
  487. * @description Перейти к предыдущему/следующему сектору в схеме
  488. */
  489. goToSector(direction: string): void {
  490. if (this.isSaved || this.grid === {}) {
  491. const keys: string[] = Object.keys(this.schemeData);
  492. let index: number = keys.findIndex(
  493. (k: string) => k === this.sectorName
  494. );
  495. let newSector: string | undefined;
  496.  
  497. if (keys.length > 1) {
  498. switch (direction) {
  499. case 'prev':
  500. if (index === 0) {
  501. index = keys.length;
  502. }
  503. newSector = keys[index - 1];
  504. break;
  505. case 'next':
  506. if (index === keys.length - 1) {
  507. index = -1;
  508. }
  509. newSector = keys[index + 1];
  510. break;
  511. }
  512.  
  513. this.sectorToShow = this.schemeData[newSector as string];
  514. this.$emit('changeSector', newSector);
  515. } else {
  516. (this.$refs['one-sector-warning-modal'] as VueWithModals).show();
  517. }
  518. } else {
  519. this.direction = direction;
  520. this.showModal();
  521. }
  522. }
  523.  
  524. /**
  525. * @description Удалить место
  526. */
  527. removeSeatFromGrid(): void {
  528. const target: HTMLElement | null = document.querySelector(
  529. `[data-row="${this.selectedRow}"][data-seat="${this.selectedSeat}"]`
  530. );
  531. target && target.setAttribute('data-hidden', 'true');
  532. this.grid[this.selectedRow][this.selectedSeat - 1] = 0;
  533. this.count--;
  534. this.showDropDown = false;
  535. }
  536.  
  537. /**
  538. * @description Показать поле для изменения имени сектора
  539. */
  540. showNameChanging(): void {
  541. if (this.sectorName) {
  542. this.sectorNameNew = this.sectorName === 'Название отсутствует' ? '' : this.sectorName;
  543. }
  544.  
  545. this.isNameChanging = !this.isNameChanging;
  546. }
  547.  
  548. /**
  549. * @description Изменить название сектора
  550. */
  551. renameSector(): void {
  552. this.sectorToShow = {
  553. ...this.sectorToShow,
  554. name: this.sectorNameNew
  555. };
  556. }
  557.  
  558. /**
  559. * @description Разделить места в секторе по группам
  560. */
  561. addTypes(): void {
  562. this.isDivided = true;
  563. const counter = Object.keys(this.groups).length;
  564. let last;
  565.  
  566. if (!counter) {
  567. this.groups[counter + 1] = {};
  568. return;
  569. }
  570.  
  571. if (counter > 0) {
  572. last = this.groups[counter];
  573.  
  574. if (last && Object.keys(last).length) {
  575. this.groups[counter + 1] = {};
  576. }
  577. }
  578. }
  579.  
  580. /**
  581. * @description Определить категорию для места в секторе
  582. * @param group {string}
  583. */
  584. addSeatToGroup(group: string): void {
  585. const seats = this.groups[group][this.selectedRow] || [];
  586. seats.push(this.selectedSeat);
  587.  
  588. this.groups[group] = {
  589. ...this.groups[group],
  590. [this.selectedRow]: seats
  591. };
  592.  
  593. this.selectedGroup = '';
  594. }
  595.  
  596. /**
  597. * @description Показать модальное окно
  598. * с предупреждением о несохраненных данных
  599. */
  600. showModal(): void {
  601. (this.$refs['not-saved-warning-modal'] as VueWithModals).show();
  602. }
  603.  
  604. /**
  605. * @description Вызов сохранения
  606. * измененного состояния схемы из модального окна
  607. */
  608. saveGridFromModal(): void {
  609. this.saveGrid();
  610. this.goToSector(this.direction as string);
  611. (this.$refs['not-saved-warning-modal'] as VueWithModals).hide();
  612. }
  613.  
  614. /**
  615. * @description Отмена сохранения
  616. * измененного состояния схемы
  617. * и переход к следующему/предыдущему сектору
  618. */
  619. cancelSaveFromModal(): void {
  620. this.isSaved = true;
  621. this.goToSector(this.direction as string);
  622. (this.$refs['not-saved-warning-modal'] as VueWithModals).hide();
  623. }
  624.  
  625. /**
  626. * @description Обработчик клика
  627. * для компонента расширенного меню
  628. * @param e {MouseEvent}
  629. */
  630. handleClick(e: MouseEvent): void {
  631. const element = e.target as HTMLElement;
  632. const {row, seat} = element.dataset || {};
  633. if (row && seat) {
  634. this.showDropDown = true;
  635. this.dropDownX = e.clientX;
  636. this.dropDownY = e.clientY;
  637. this.selectedRow = Number(row);
  638. this.selectedSeat = Number(seat);
  639. } else {
  640. this.showDropDown = false;
  641. }
  642. }
  643.  
  644. get sectorName(): string | undefined {
  645. if (this.sector ) {
  646. return this.sector.name;
  647. }
  648. }
  649.  
  650. get disableDivideButton(): boolean {
  651. let disabled = false;
  652. const groups = Object.values(this.groups);
  653. if (groups.length) {
  654. groups.forEach(
  655. (group) => disabled = Boolean(!Object.keys(group as {}).length)
  656. );
  657. }
  658.  
  659. return disabled;
  660. }
  661. }
  662. </script>
  663.  
  664. <style lang="scss" scoped>
  665. .grid {
  666. &__seat {
  667. margin: 5px;
  668. background: #acf;
  669. cursor: pointer;
  670. display: flex;
  671. justify-content: center;
  672. align-items: center;
  673. width: 30px;
  674. height: 30px;
  675. border-radius: 50%;
  676.  
  677. &[data-hidden="true"] {
  678. opacity: 0;
  679. pointer-events: none;
  680. visibility: hidden;
  681. }
  682. }
  683.  
  684. &__row {
  685. p {
  686. font-weight: bold;
  687. text-align: center;
  688. width: 70px;
  689. }
  690.  
  691. &.active {
  692. .grid__seat {
  693. background: darken(plum, 35%);
  694. color: white;
  695. }
  696. }
  697. }
  698. }
  699.  
  700. .btn {
  701. min-width: 160px;
  702. }
  703.  
  704. /deep/ .dropdown-toggle {
  705. &:after {
  706. display: none;
  707. }
  708. }
  709.  
  710. /deep/ .dropdown-menu.show {
  711. min-width: 300px;
  712. }
  713. </style>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement