OptionPanel.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. <template>
  2. <option-panel-tabs v-model:options="localOptions">
  3. <template #main-tab>
  4. <div class="option-panel-container">
  5. <div class="row items-center q-my-md">
  6. <q-btn size="md"
  7. class="q-py-lg"
  8. color="green-7"
  9. label="افزودن بنر"
  10. round
  11. dense
  12. icon="add"
  13. @click="addBanner" />
  14. </div>
  15. <q-table dir="rtl"
  16. title="جدول اسلایدها"
  17. :rows="rows"
  18. :columns="columns"
  19. row-key="name">
  20. <template v-slot:body-cell-view="props">
  21. <q-td key="view"
  22. :props="props"
  23. auto-width>
  24. <q-btn size="sm"
  25. color="secondary"
  26. round
  27. dense
  28. :icon="'edit'"
  29. @click="showFullBanner(props.row.name)" />
  30. </q-td>
  31. </template>
  32. <template v-slot:body-cell-photo="props">
  33. <q-td key="photo"
  34. class="thumbnail"
  35. :props="props"
  36. auto-width>
  37. <lazy-img :src="props.row.photo" />
  38. </q-td>
  39. </template>
  40. <template v-slot:body-cell-remove="props">
  41. <q-td key="view"
  42. :props="props"
  43. auto-width>
  44. <q-btn class="q-mr-lg"
  45. size="sm"
  46. color="red-8"
  47. round
  48. dense
  49. :icon="'delete'"
  50. @click="removeBanner(props.row.name)" />
  51. </q-td>
  52. </template>
  53. </q-table>
  54. </div>
  55. <q-dialog v-model="expandBanner"
  56. persistent>
  57. <q-card v-ripple
  58. class="column card"
  59. clickable>
  60. <div class="row col-12">
  61. <q-card-section class="row items-center q-pb-none">
  62. <q-btn v-close-popup
  63. icon="close"
  64. flat
  65. round
  66. dense
  67. @click="responsive = ''" />
  68. </q-card-section>
  69. </div>
  70. <div class="col-12 row">
  71. <q-card-section class="col-6">
  72. <q-input v-model="selectedSlide.title"
  73. label="title" />
  74. </q-card-section>
  75. <q-card-section class="col-6">
  76. <q-input v-model="selectedSlide.link"
  77. label="link" />
  78. </q-card-section>
  79. <q-card-section class="col-6">
  80. <div class="cehckBox">
  81. <q-checkbox v-model="localOptions.list[selectedBannerIndex].useAEEEvent"
  82. label="استفاده از ایونت GTM"
  83. right-label />
  84. </div>
  85. </q-card-section>
  86. <q-card-section class="col-12">
  87. <div v-if="localOptions.list[selectedBannerIndex].useAEEEvent"
  88. class="action-container q-gutter-lg-md">
  89. <div>فیلد های مورد نظر ایونت GTM :</div>
  90. <div class="col-9">
  91. <div class="outsideLabel">id</div>
  92. <q-input v-model="localOptions.list[selectedBannerIndex].AEEEventBody.id"
  93. label="id" />
  94. </div>
  95. <div class="col-6">
  96. <div class="outsideLabel">name</div>
  97. <q-input v-model="localOptions.list[selectedBannerIndex].AEEEventBody.name"
  98. label="name" />
  99. </div>
  100. <div class="col-6">
  101. <div class="outsideLabel">creative</div>
  102. <q-input v-model="localOptions.list[selectedBannerIndex].AEEEventBody.creative"
  103. label="creative" />
  104. </div>
  105. <div class="col-6">
  106. <div class="outsideLabel">position</div>
  107. <q-input v-model="localOptions.list[selectedBannerIndex].AEEEventBody.position"
  108. label="position" />
  109. </div>
  110. </div>
  111. </q-card-section>
  112. </div>
  113. <div class="row col-12">
  114. <q-toggle v-model="isResponsive"
  115. checked-icon="check"
  116. color="green"
  117. label="responsive features"
  118. unchecked-icon="clear" />
  119. </div>
  120. <q-table v-if="isResponsive"
  121. dir="rtl"
  122. title="جدول رسپانسیو"
  123. :rows="responsiveRows"
  124. :columns="responsiveColumns"
  125. row-key="name">
  126. <template v-slot:body-cell-view="props">
  127. <q-td key="view"
  128. :props="props"
  129. auto-width>
  130. <q-btn size="sm"
  131. color="secondary"
  132. round
  133. dense
  134. :icon="'edit'"
  135. @click="showFullResponsiveBanner(props.row.name)" />
  136. </q-td>
  137. </template>
  138. <template v-slot:body-cell-thumbnail="props">
  139. <q-td key="thumbnail"
  140. class="thumbnail"
  141. :props="props"
  142. auto-width>
  143. <lazy-img :src="props.row.thumbnail" />
  144. </q-td>
  145. </template>
  146. <template v-slot:body-cell-remove="props">
  147. <q-td key="view"
  148. :props="props"
  149. auto-width>
  150. <q-btn class="q-mr-lg"
  151. size="sm"
  152. color="red-8"
  153. round
  154. dense
  155. :icon="'delete'"
  156. @click="removeSizeFeatures(props.row.name)" />
  157. </q-td>
  158. </template>
  159. </q-table>
  160. <div v-else>
  161. <div class="row col-12">
  162. <q-card-section class="col-12">
  163. <banner-preview v-model:banner="selectedSlide"
  164. v-model:options="localOptions"
  165. @update:src="updateSrc" />
  166. </q-card-section>
  167. </div>
  168. </div>
  169. </q-card>
  170. </q-dialog>
  171. <q-dialog v-model="expandResponsiveBanner"
  172. persistent>
  173. <q-card v-ripple
  174. class="column"
  175. clickable>
  176. <div class="row col-12">
  177. <q-card-section class="row items-center q-pb-none">
  178. <q-btn v-close-popup
  179. icon="close"
  180. flat
  181. round
  182. dense />
  183. </q-card-section>
  184. </div>
  185. <div class="col-12 row">
  186. <q-card-section class="col-12">
  187. <banner-preview v-model:banner="selectedSlide"
  188. v-model:options="localOptions"
  189. :size="selectedResponsiveSize"
  190. @update:src="updateSrc" />
  191. </q-card-section>
  192. </div>
  193. </q-card>
  194. </q-dialog>
  195. </template>
  196. </option-panel-tabs>
  197. </template>
  198. <script>
  199. import { defineComponent } from 'vue'
  200. import { Banner } from 'src/models/Banner.js'
  201. import lazyImg from 'src/components/lazyImg.vue'
  202. import bannerPreview from 'src/components/Widgets/Slider/bannerPreview.vue'
  203. import { PageBuilderOptionPanel } from 'src/mixin/Mixins.js'
  204. import OptionPanelTabs from 'quasar-ui-q-page-builder/src/components/OptionPanelComponents/OptionPanelTabs.vue'
  205. export default defineComponent({
  206. name: 'OptionPanel',
  207. components: {
  208. OptionPanelTabs,
  209. bannerPreview,
  210. lazyImg
  211. },
  212. mixins: [PageBuilderOptionPanel],
  213. data() {
  214. return {
  215. windowWidth: 0,
  216. expandBanner: false,
  217. expandResponsiveBanner: false,
  218. file: null,
  219. responsive: '',
  220. isResponsive: false,
  221. selectedSlide: new Banner(),
  222. selectedResponsiveSize: '',
  223. selectedBannerIndex: 0,
  224. columns: [
  225. {
  226. name: 'name',
  227. required: true,
  228. label: 'ردیف',
  229. align: 'center',
  230. field: row => row.name,
  231. sortable: true
  232. },
  233. {
  234. name: 'title',
  235. align: 'center',
  236. label: 'عنوان',
  237. field: row => row.title
  238. },
  239. {
  240. name: 'photo',
  241. align: 'center',
  242. label: 'تصویر',
  243. field: row => row.photo
  244. },
  245. {
  246. name: 'view',
  247. align: 'center',
  248. label: 'مشاهده',
  249. field: row => row.view
  250. },
  251. {
  252. name: 'remove',
  253. align: 'center',
  254. label: 'حذف بنر',
  255. field: row => row.remove
  256. }
  257. ],
  258. rows: [],
  259. responsiveColumns: [
  260. {
  261. name: 'name',
  262. required: true,
  263. label: 'break point',
  264. align: 'center',
  265. field: row => row.name
  266. },
  267. {
  268. name: 'size',
  269. required: true,
  270. label: 'اندازه صفحه',
  271. align: 'center',
  272. field: row => row.size
  273. },
  274. {
  275. name: 'thumbnail',
  276. align: 'center',
  277. label: 'تصویر',
  278. field: row => row.thumbnail
  279. },
  280. {
  281. name: 'view',
  282. align: 'center',
  283. label: 'مشاهده',
  284. field: row => row.view
  285. },
  286. {
  287. name: 'remove',
  288. align: 'center',
  289. label: 'حذف',
  290. field: row => row.remove
  291. }
  292. ],
  293. responsiveRows: [
  294. {
  295. name: 'xl',
  296. size: 'size >= 1920 px',
  297. thumbnail: ''
  298. },
  299. {
  300. name: 'lg',
  301. size: 'size >= 1440 px',
  302. thumbnail: ''
  303. },
  304. {
  305. name: 'md',
  306. size: 'size >= 1024 px',
  307. thumbnail: ''
  308. },
  309. {
  310. name: 'sm',
  311. size: 'size >= 600 px',
  312. thumbnail: ''
  313. },
  314. {
  315. name: 'xs',
  316. size: 'size >= 0 px',
  317. thumbnail: ''
  318. }
  319. ],
  320. defaultOptions: {
  321. list: []
  322. }
  323. }
  324. },
  325. watch: {
  326. selectedSlide: {
  327. handler() {
  328. this.updateBanner()
  329. }
  330. }
  331. },
  332. created() {
  333. this.initTable()
  334. window.addEventListener('resize', this.onResize)
  335. },
  336. beforeUnmount() {
  337. window.removeEventListener('resize', this.onResize)
  338. },
  339. methods: {
  340. onResize() {
  341. this.windowWidth = window.innerWidth
  342. },
  343. addBanner() {
  344. const rowNumber = this.localOptions.list.length + 1
  345. this.localOptions.list.push({
  346. title: '',
  347. photo: {
  348. src: '',
  349. width: '',
  350. height: ''
  351. },
  352. features: {
  353. xl: {
  354. src: '',
  355. width: '',
  356. height: ''
  357. },
  358. lg: {
  359. src: '',
  360. width: '',
  361. height: ''
  362. },
  363. md: {
  364. src: '',
  365. width: '',
  366. height: ''
  367. },
  368. sm: {
  369. src: '',
  370. width: '',
  371. height: ''
  372. },
  373. xs: {
  374. src: '',
  375. width: '',
  376. height: ''
  377. }
  378. },
  379. link: '',
  380. useAEEEvent: false,
  381. AEEEventBody: {
  382. id: '-',
  383. name: '-',
  384. creative: null,
  385. position: null
  386. }
  387. })
  388. this.rows.push({
  389. name: rowNumber,
  390. title: '',
  391. photo: ''
  392. })
  393. },
  394. responsiveFeatures(features) {
  395. if (this.windowWidth >= 1920) {
  396. return features.xl.src !== '' ? features.xl : features.lg.src !== '' ? features.lg : features.sm.src !== '' ? features.md : features.sm.src !== '' ? features.sm : features.xs
  397. } else if (this.windowWidth <= 1919 && this.windowWidth > 1440) {
  398. return features.lg.src !== '' ? features.lg : features.md.src !== '' ? features.md : features.sm.src !== '' ? features.sm : features.xs.src !== '' ? features.xs : features.xl
  399. } else if (this.windowWidth <= 1439 && this.windowWidth > 1024) {
  400. return features.md.src !== '' ? features.md : features.sm.src !== '' ? features.sm : features.xs.src !== '' ? features.xs : features.lg.src !== '' ? features.lg : features.xl
  401. } else if (this.windowWidth <= 1023 && this.windowWidth > 600) {
  402. return features.sm.src !== '' ? features.sm : features.xs.src !== '' ? features.xs : features.md.src !== '' ? features.md : features.lg.src !== '' ? features.lg : features.xl
  403. } else if (this.windowWidth <= 599) {
  404. return features.xs.src !== '' ? features.xs : features.sm.src !== '' ? features.sm : features.md.src !== '' ? features.md : features.lg.src !== '' ? features.lg : features.xl
  405. }
  406. },
  407. removeBanner(name) {
  408. const index = this.rows.findIndex(row => row.name === name)
  409. this.localOptions.list.splice(index, 1)
  410. this.rows.splice(index, 1)
  411. },
  412. removeSizeFeatures(size) {
  413. this.localOptions.list[this.selectedBannerIndex].features[size].src = ''
  414. this.updateResponsiveRows()
  415. },
  416. initTable() {
  417. for (let i = 0; i < this.localOptions.list.length; i++) {
  418. this.rows.push({
  419. name: i + 1,
  420. title: this.localOptions.list[i].title,
  421. photo: this.localOptions.list[i].photo.src ? this.localOptions.list[i].photo.src : this.responsiveFeatures(this.localOptions.list[i].features).src
  422. })
  423. }
  424. },
  425. updateTable() {
  426. for (let i = 0; i < this.localOptions.list.length; i++) {
  427. this.rows[i] = {
  428. name: i + 1,
  429. title: this.localOptions.list[i].title,
  430. photo: this.localOptions.list[i].photo.src ? this.localOptions.list[i].photo.src : this.responsiveFeatures(this.localOptions.list[i].features).src
  431. }
  432. }
  433. },
  434. updateBanner() {
  435. this.localOptions.list[this.selectedBannerIndex] = this.selectedSlide
  436. this.updateTable()
  437. },
  438. showFullBanner(index) {
  439. this.expandBanner = true
  440. this.selectedSlide = new Banner(this.localOptions.list[index - 1])
  441. this.selectedBannerIndex = index - 1
  442. this.updateResponsiveRows()
  443. },
  444. showFullResponsiveBanner(name) {
  445. this.expandResponsiveBanner = true
  446. this.selectedSlide.features[name].src = this.localOptions.list[this.selectedBannerIndex].features[name].src
  447. this.selectedResponsiveSize = name
  448. },
  449. updateResponsiveRows() {
  450. this.responsiveRows.forEach(row => {
  451. Object.keys(this.localOptions.list[this.selectedBannerIndex].features).forEach(key => {
  452. if (key === row.name) {
  453. row.thumbnail = this.localOptions.list[this.selectedBannerIndex].features[key].src
  454. }
  455. })
  456. })
  457. },
  458. updateSrc(data) {
  459. if (data.size) {
  460. this.localOptions.list[this.selectedBannerIndex].features[data.size].src = data.src
  461. const index = this.responsiveRows.findIndex(row => row.name === data.size)
  462. this.responsiveRows[index].thumbnail = data.src
  463. } else {
  464. this.localOptions.list[this.selectedBannerIndex].photo.src = data.src
  465. }
  466. }
  467. }
  468. })
  469. </script>
  470. <style scoped>
  471. .thumbnail {
  472. padding: 0;
  473. }
  474. .card {
  475. width: 50%;
  476. }
  477. </style>