AdminTicketShow.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <template>
  2. <div class="AdminTicketShow"
  3. :style="localOptions.style">
  4. <div class="title">
  5. <div class="static-title">
  6. مشاهده پیام
  7. </div>
  8. <div class="dynamic-title">
  9. <template v-if="entityLoading">
  10. <q-skeleton type="text"
  11. class="q-ml-lg"
  12. width="100px" />
  13. </template>
  14. <template v-else>
  15. {{ packageTitle }}
  16. </template>
  17. </div>
  18. <div class="back-action">
  19. <q-btn flat
  20. :to="{name: 'Admin.Invoice.Ticket'}"
  21. color="grey">
  22. بازگشت
  23. >
  24. </q-btn>
  25. </div>
  26. </div>
  27. <q-card class="form"
  28. flat>
  29. <entity-edit v-if="mounted"
  30. ref="entityEdit"
  31. v-model:value="inputs"
  32. title="اطلاعات کاربری"
  33. :api="api"
  34. :entity-id-key="entityIdKey"
  35. :entity-param-key="entityParamKey"
  36. :show-route-name="showRouteName"
  37. :show-close-button="false"
  38. :show-edit-button="false"
  39. :show-expand-button="false"
  40. :show-save-button="false"
  41. :show-reload-button="false"
  42. :default-layout="false"
  43. :redirect-after-edit="false"
  44. :before-load-input-data="beforeLoadInputData"
  45. :after-load-input-data="afterLoadInputData" />
  46. <div class="row q-mt-lg justify-end">
  47. <div class="col-md-4 col-12">
  48. <q-btn color="primary"
  49. class="full-width"
  50. :loading="entityLoading"
  51. @click="edit">
  52. ثبت تغییرات
  53. </q-btn>
  54. </div>
  55. </div>
  56. <q-card v-if="mounted"
  57. class="q-mt-md">
  58. <q-card-section>
  59. <div class="row justify-center">
  60. <div style="width: 100%;">
  61. <q-chat-message v-for="message in repliesInfo"
  62. :key="message.id"
  63. :avatar="message.creator_info.picture ? message.creator_info.picture : 'assets/images/web/sample-avatar.svg'"
  64. :name="message.creator_info.firstname + ' ' + message.creator_info.lastname"
  65. :text="[message.body]"
  66. :sent="authenticatedUser.id !== message.creator_info.id" />
  67. <!-- <div>-->
  68. <!-- <q-input v-model="replyBody"-->
  69. <!-- bottom-slots-->
  70. <!-- :loading="replyBodyLoading">-->
  71. <!-- <template v-slot:after>-->
  72. <!-- <q-btn round-->
  73. <!-- dense-->
  74. <!-- flat-->
  75. <!-- icon="send"-->
  76. <!-- :loading="replyBodyLoading"-->
  77. <!-- @click="sendReplyBody" />-->
  78. <!-- </template>-->
  79. <!-- </q-input>-->
  80. <!-- </div>-->
  81. </div>
  82. </div>
  83. </q-card-section>
  84. </q-card>
  85. <div class="action">
  86. <div class="row q-mt-lg justify-end">
  87. <div class="col-md-12 col-12">
  88. متن پیام
  89. </div>
  90. <div class="col-md-12 col-12 q-mb-md">
  91. <q-input v-model="replyText"
  92. type="textarea" />
  93. </div>
  94. <div class="col-md-4 col-12">
  95. <q-btn color="primary"
  96. class="full-width"
  97. :loading="entityLoading"
  98. @click="sendReply">
  99. ارسال پاسخ
  100. </q-btn>
  101. </div>
  102. </div>
  103. </div>
  104. </q-card>
  105. <!-- <show-source :source-type="ticket.source_type"-->
  106. <!-- :source-id="ticket.source_id"-->
  107. <!-- :source="ticket.source" />-->
  108. <admin-invoice-show v-if="ticket.source_type === 'INVOICE' && ticket.source_id"
  109. :options="{invoiceId: ticket.source_id, showBackBtn: false}"
  110. class="q-mt-lg" />
  111. <q-card v-if="ticket.source_type === 'INVOICE' && ticket.source_id"
  112. class="q-mt-lg">
  113. <q-card-section>
  114. اقساط
  115. </q-card-section>
  116. <q-separator />
  117. <q-card-section>
  118. <installment-offers :installment-offers="instalmentOffers"
  119. :loading="entityLoading"
  120. :can-accept="false"
  121. :can-reject="false"
  122. @onReject="onReject"
  123. @onAccept="onAccept" />
  124. </q-card-section>
  125. <q-separator />
  126. <q-card-section>
  127. <create-installment :invoice-id="ticket.source_id"
  128. @onCreated="onCreateInstallmentOffer" />
  129. </q-card-section>
  130. </q-card>
  131. </div>
  132. </template>
  133. <script>
  134. import { EntityEdit } from 'quasar-crud'
  135. import { User } from 'src/models/User.js'
  136. import { Ticket } from 'src/models/Ticket.js'
  137. import { mixinWidget } from 'src/mixin/Mixins.js'
  138. import { APIGateway } from 'src/api/APIGateway.js'
  139. import { FormBuilderAssist } from 'quasar-form-builder'
  140. import { TicketCategoryList } from 'src/models/TicketCategory.js'
  141. import { InstalmentOfferList } from 'src/models/InstalmentOffer.js'
  142. // import ShowSource from 'src/components/Widgets/Ticket/AdminTicketShow/ShowSource.vue'
  143. import AdminInvoiceShow from 'src/components/Widgets/Invoice/AdminInvoiceShow/AdminInvoiceShow.vue'
  144. import InstallmentOffers from 'src/components/Widgets/Ticket/AdminTicketShow/InstallmentOffers.vue'
  145. import CreateInstallment from 'src/components/Widgets/Ticket/AdminTicketShow/CreateInstallment.vue'
  146. export default {
  147. name: 'AdminTicketShow',
  148. components: {
  149. EntityEdit,
  150. // ShowSource,
  151. AdminInvoiceShow,
  152. CreateInstallment,
  153. InstallmentOffers
  154. },
  155. mixins: [mixinWidget],
  156. data: () => {
  157. return {
  158. replyText: null,
  159. mounted: false,
  160. entityLoading: true,
  161. packageTitle: '',
  162. ticket: new Ticket(),
  163. authenticatedUser: new User(),
  164. api: APIGateway.ticket.APIAdresses.base,
  165. ticketCategoryList: new TicketCategoryList(),
  166. entityIdKey: 'id',
  167. entityParamKey: 'id',
  168. showRouteName: 'Admin.Ticket.Show',
  169. indexRouteName: 'Admin.Ticket.List',
  170. inputs: [
  171. {
  172. type: 'select',
  173. name: 'category_info__type',
  174. responseKey: 'category_info.type',
  175. options: [
  176. { label: 'مالی', value: 'FINANCIAL' },
  177. { label: 'آموزش', value: 'EDUCATIONAL' },
  178. { label: 'محتوا', value: 'CONTENT' },
  179. { label: 'عمومی', value: 'GENERAL' }
  180. ],
  181. label: 'معاونت',
  182. placeholder: ' ',
  183. col: 'col-md-4 col-12'
  184. },
  185. { type: 'select', name: 'category', responseKey: 'category', placeholder: ' ', options: [], label: 'دسته', col: 'col-md-4 col-12' },
  186. { type: 'select', name: 'status', responseKey: 'status', options: (new Ticket()).statusEnums, multiple: false, label: 'وضعیت', placeholder: ' ', readonly: true, col: 'col-md-4 col-12' },
  187. { type: 'input', name: 'title', responseKey: 'title', label: 'عنوان', placeholder: ' ', readonly: true, col: 'col-md-12 col-12' },
  188. { type: 'inputEditor', name: 'body', responseKey: 'body', label: 'متن', placeholder: ' ', readonly: true, col: 'col-md-12 col-12' },
  189. { type: 'hidden', name: 'source_id', responseKey: 'source_id', value: null },
  190. { type: 'hidden', name: 'id', responseKey: 'id' },
  191. { type: 'hidden', name: 'owner', responseKey: 'owner' },
  192. { type: 'hidden', name: 'replies_info', responseKey: 'replies_info' },
  193. { type: 'hidden', name: 'source_type', value: null },
  194. { type: 'hidden', name: 'source_id', value: null }
  195. ]
  196. }
  197. },
  198. computed: {
  199. selectedCategoryInfoType () {
  200. return FormBuilderAssist.getInputsByName(this.inputs, 'category_info__type')?.value
  201. },
  202. instalmentOffers () {
  203. return new InstalmentOfferList(this.ticket.source?.instalment_offers_info)
  204. },
  205. repliesInfo () {
  206. return this.inputs.find(input => input.name === 'replies_info').value
  207. }
  208. },
  209. watch: {
  210. selectedCategoryInfoType () {
  211. FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'value', null)
  212. this.loadCategories()
  213. }
  214. },
  215. created() {
  216. this.api = this.api + '/' + this.$route.params.id
  217. },
  218. mounted() {
  219. this.loadAuthData()
  220. this.checkSource()
  221. this.loadOptions()
  222. .then(() => {
  223. this.$nextTick(() => {
  224. this.mounted = true
  225. })
  226. })
  227. .catch(() => {
  228. this.mounted = true
  229. })
  230. },
  231. methods: {
  232. onReject (offer) {
  233. this.entityLoading = true
  234. APIGateway.instalmentOffer.reject(offer.id)
  235. .then(() => {
  236. this.$refs.entityEdit.getData()
  237. })
  238. .catch(() => {
  239. this.$refs.entityEdit.getData()
  240. })
  241. },
  242. onAccept (offer) {
  243. this.entityLoading = true
  244. APIGateway.instalmentOffer.accept(offer.id)
  245. .then(() => {
  246. this.$refs.entityEdit.getData()
  247. })
  248. .catch(() => {
  249. this.$refs.entityEdit.getData()
  250. })
  251. },
  252. onCreateInstallmentOffer () {
  253. this.$refs.entityEdit.getData()
  254. },
  255. checkSource () {
  256. if (this.localOptions.defaultSourceType) {
  257. FormBuilderAssist.setAttributeByName(this.inputs, 'source_type', 'value', this.localOptions.defaultSourceType)
  258. }
  259. },
  260. loadAuthData () {
  261. this.authenticatedUser = this.$store.getters['Auth/user']
  262. },
  263. beforeLoadInputData (data) {
  264. this.entityLoading = false
  265. this.ticket = new Ticket(data)
  266. },
  267. afterLoadInputData () {
  268. this.$nextTick(() => {
  269. FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'value', this.ticket.category)
  270. })
  271. },
  272. edit() {
  273. this.entityLoading = true
  274. this.$refs.entityEdit.editEntity()
  275. .then(() => {
  276. this.$refs.entityEdit.getData()
  277. })
  278. .catch(() => {
  279. this.$refs.entityEdit.getData()
  280. })
  281. },
  282. loadOptions () {
  283. return this.loadCategories()
  284. },
  285. loadCategories () {
  286. return new Promise((resolve, reject) => {
  287. const type = this.selectedCategoryInfoType
  288. // if (!type) {
  289. // return
  290. // }
  291. this.categoriesLoading = true
  292. APIGateway.ticketCategory.index({ type })
  293. .then(({ list }) => {
  294. const ticketCategoryList = list
  295. FormBuilderAssist.setAttributeByName(this.inputs, 'category', 'options', ticketCategoryList.list.map(item => {
  296. return {
  297. value: item.id,
  298. label: item.title
  299. }
  300. }))
  301. this.categoriesLoading = false
  302. this.$nextTick(() => {
  303. resolve()
  304. })
  305. })
  306. .catch(() => {
  307. this.categoriesLoading = false
  308. this.$nextTick(() => {
  309. reject()
  310. })
  311. })
  312. })
  313. },
  314. sendReply() {
  315. this.entityLoading = true
  316. APIGateway.ticket.reply({
  317. id: this.$route.params.id,
  318. body: this.replyText
  319. })
  320. .then(() => {
  321. this.$refs.entityEdit.editEntity()
  322. .then(() => {
  323. this.$refs.entityEdit.getData()
  324. })
  325. .catch(() => {
  326. this.$refs.entityEdit.getData()
  327. })
  328. })
  329. .catch(() => {
  330. this.$refs.entityEdit.getData()
  331. })
  332. }
  333. }
  334. }
  335. </script>
  336. <style scoped lang="scss">
  337. .AdminTicketShow {
  338. .title {
  339. font-style: normal;
  340. font-weight: 700;
  341. font-size: 24px;
  342. line-height: 140%;
  343. color: #424242;
  344. margin-bottom: 27px;
  345. display: flex;
  346. flex-flow: row;
  347. position: relative;
  348. .static-title {
  349. }
  350. .dynamic-title {
  351. }
  352. .back-action {
  353. position: absolute;
  354. right: 0;
  355. top: 0;
  356. }
  357. }
  358. :deep(.form) {
  359. padding: 24px;
  360. }
  361. }
  362. </style>