_id.vue 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. <template>
  2. <v-container class="spacing-playground" fluid>
  3. <modal
  4. adaptive
  5. height="auto"
  6. name="is-edited-modal"
  7. :clickToClose="false"
  8. v-if="is_edited"
  9. >
  10. <v-alert outlined type="info"
  11. >Статья уже редактируется пользователем {{ is_edited.user }}</v-alert
  12. >
  13. <v-btn @click="$router.push('/admin/publications')"
  14. >Перейти к публикациям</v-btn
  15. >
  16. <v-btn @click="interception()"
  17. >Перехватить редактирование</v-btn
  18. >
  19. </modal>
  20. <modal adaptive height="auto" name="is-interception-modal" :clickToClose="false">
  21. <v-alert outlined type="info">Редактирование статьи было перехвачено другим пользователем</v-alert>
  22. <v-btn @click="$router.push('/admin/publications')">Перейти к публикациям</v-btn>
  23. <v-btn @click="interception()">Перехватить редактирование</v-btn>
  24. </modal>
  25. <v-tabs v-model="tab">
  26. <v-tabs-slider color="blue"></v-tabs-slider>
  27. <v-tab v-for="item in items_tab" :key="item">
  28. {{ item }}
  29. </v-tab>
  30. </v-tabs>
  31. <v-tabs-items v-model="tab">
  32. <v-tab-item>
  33. <v-card>
  34. <v-row no-gutters>
  35. <v-col cols="8" class="col detail__main pa-6">
  36. <treeselect
  37. placeholder="Категория"
  38. value="id"
  39. noChildrenText="Нет подкатегорий"
  40. valueFormat="object"
  41. v-model="category"
  42. :options="treeCategories"
  43. class="tree-select"
  44. />
  45. <div class="error" v-if="$v.$dirty && !$v.category.required">
  46. Обязательное поле
  47. </div>
  48. <v-text-field v-model="title" label="Заголовок">
  49. </v-text-field>
  50. <div class="error" v-if="$v.$dirty && !$v.title.required">
  51. Обязательное поле
  52. </div>
  53. <v-text-field disabled v-model="generatedAlias" label="Алиас">
  54. </v-text-field>
  55. <v-text-field v-model="sliderId" label="Слайдер"> </v-text-field>
  56. <v-text-field v-model="sorting" label="Позиция"> </v-text-field>
  57. <v-textarea
  58. name="input-7-1"
  59. label="Описание"
  60. hint=""
  61. v-model="description"
  62. ></v-textarea>
  63. <v-textarea
  64. label="Видео"
  65. v-model="video"
  66. rows="3"
  67. auto-grow
  68. ></v-textarea>
  69. <v-text-field v-model="externalLink" label="Внешняя ссылка">
  70. </v-text-field>
  71. <v-text-field v-model="token" label="Токен (для рекламы)">
  72. </v-text-field>
  73. <v-file-input
  74. prepend-icon=""
  75. append-icon="$file"
  76. label="Прикрепить файлы (PDF, ZIP, DOC, DOCX)"
  77. chips
  78. multiple
  79. small-chips
  80. v-model="filesModel"
  81. @change="loadFiles"
  82. accept=".pdf, .zip, .doc, .docx"
  83. ></v-file-input>
  84. <v-chip-group v-if="files.length">
  85. <v-chip
  86. @click:close="deleteFile(file, index)"
  87. v-for="(file, index) in files"
  88. :key="file.id"
  89. close
  90. >
  91. {{ file.original_file_name }}
  92. </v-chip>
  93. </v-chip-group>
  94. <AdminEditor
  95. v-if="content"
  96. :value="content"
  97. @input="content = $event"
  98. ></AdminEditor>
  99. <v-btn class="ml-auto mr-0 pa-6 my-6" @click="createNews('save')">Сохранить публикацию</v-btn>
  100. <v-btn class="ml-auto mr-0 pa-6 my-6" @click="createNews('update')">Обновить публикацию</v-btn>
  101. <v-btn class="ml-auto mr-0 pa-6 my-6" @click="previewNews">Предпросмотр</v-btn>
  102. <v-btn class="ml-auto mr-0 pa-6 my-6" @click="shareNews">Поделиться</v-btn>
  103. <v-btn class="mx-6" tile color="warning" @click="deleteNews(id)">
  104. <v-icon left> mdi-delete </v-icon>
  105. удалить
  106. </v-btn>
  107. </v-col>
  108. <v-col cols="3" class="col detail__sidebar pa-6">
  109. <div v-if="!img.relative_path">
  110. <v-img
  111. v-if="img.url"
  112. :lazy-src="img.url ? img.url : 'без картинки'"
  113. :src="img.url ? img.url : 'без картинки'"
  114. :max-width="400"
  115. >
  116. </v-img>
  117. </div>
  118. <v-img
  119. v-else
  120. :lazy-src="url(img ? img.relative_path : '')"
  121. :src="url(img ? img.relative_path : '')"
  122. :max-width="400"
  123. >
  124. </v-img>
  125. <v-row align="center">
  126. <v-col cols="10" class="col pa-6">
  127. <v-file-input
  128. v-model="file"
  129. @change="fileHandler('main-img', 814, 458)"
  130. @click:clear="
  131. img = {};
  132. img.id = 'remove';
  133. img.image_id = '';
  134. "
  135. label="Картинка:"
  136. type="file"
  137. accept="image/*"
  138. ref="input1"
  139. >
  140. </v-file-input>
  141. </v-col>
  142. <v-col cols="2" class="col pa-6">
  143. <v-btn
  144. v-if="detail_img_id != ''"
  145. icon
  146. color="error"
  147. elevation="2"
  148. @click="
  149. img = {};
  150. img.id = 'remove';
  151. detail_img_id = '';
  152. "
  153. >
  154. <v-icon>mdi-delete</v-icon>
  155. </v-btn>
  156. </v-col>
  157. </v-row>
  158. <div v-if="!previewImg.relative_path">
  159. <v-img
  160. v-if="previewImg.url"
  161. :lazy-src="previewImg.url ? previewImg.url : 'без картинки'"
  162. :src="previewImg.url ? previewImg.url : 'без картинки'"
  163. :max-width="400"
  164. >
  165. </v-img>
  166. </div>
  167. <v-img
  168. v-else
  169. :lazy-src="url(previewImg ? previewImg.relative_path : '')"
  170. :src="url(previewImg ? previewImg.relative_path : '')"
  171. :max-width="400"
  172. >
  173. </v-img>
  174. <v-row align="center">
  175. <v-col cols="10" class="col pa-6">
  176. <v-file-input
  177. v-model="previewFile"
  178. @change="fileHandler('preview-img', 850, 420)"
  179. @click:clear="
  180. previewImg = {};
  181. previewImg.id = 'remove';
  182. previewImg.image_id = '';
  183. "
  184. label="Превью:"
  185. type="file"
  186. accept="image/*"
  187. ref="inputPreview"
  188. >
  189. </v-file-input>
  190. </v-col>
  191. <v-col cols="2" class="col pa-6">
  192. <v-btn
  193. v-if="preview_img_id != ''"
  194. icon
  195. color="error"
  196. elevation="2"
  197. @click="
  198. previewImg = {};
  199. previewImg.id = 'remove';
  200. preview_img_id = '';
  201. "
  202. >
  203. <v-icon>mdi-delete</v-icon>
  204. </v-btn>
  205. </v-col>
  206. </v-row>
  207. <v-select
  208. class="tree-select"
  209. :items="authorsList"
  210. item-text="name"
  211. item-value="value"
  212. v-model="author"
  213. label="Автор"
  214. ></v-select>
  215. <v-checkbox label="Показывать автора" v-model="showAuthor">
  216. </v-checkbox>
  217. <v-checkbox label="Не отдавать в Яндекс" v-model="dont_send_to_rss">
  218. </v-checkbox>
  219. <v-checkbox label="МОЛНИЯ" v-model="lightning"> </v-checkbox>
  220. <v-checkbox label="Включить комментарии" v-model="allowComments">
  221. </v-checkbox>
  222. <v-checkbox
  223. label="На правах рекламы"
  224. v-model="advertisement"
  225. ></v-checkbox>
  226. <v-checkbox
  227. label="Метка Реклама (не видна читателю)"
  228. v-model="advertisement_mark"
  229. ></v-checkbox>
  230. <v-checkbox label="Партнерский материал" v-model="partner">
  231. </v-checkbox>
  232. <v-checkbox
  233. label="Имеются противопоказания"
  234. v-model="contraindications"
  235. >
  236. </v-checkbox>
  237. <v-checkbox v-model="activity" label="Активность"> </v-checkbox>
  238. <v-checkbox v-model="showInStories" label="Показывать в сторис">
  239. </v-checkbox>
  240. <v-checkbox v-model="verified" label="Проверено"> </v-checkbox>
  241. <div v-if="!storieImg">
  242. <v-img
  243. v-if="storieImg"
  244. :lazy-src="storieImg.url ? storieImg.url : 'без картинки'"
  245. :src="storieImg.url ? storieImg.url : 'без картинки'"
  246. :max-width="400"
  247. >
  248. </v-img>
  249. </div>
  250. <v-img
  251. v-else
  252. :lazy-src="url(storieImg ? storieImg.relative_path : '')"
  253. :src="url(storieImg ? storieImg.relative_path : '')"
  254. :max-width="400"
  255. >
  256. </v-img>
  257. <!--<v-file-input
  258. v-if="showInStories"
  259. v-model="storieFile"
  260. @change="fileHandler('storie-img', 500, 1200)"
  261. label="Картинка для истории:"
  262. type="file"
  263. accept="image/*"
  264. ref="inputStorie"
  265. ></v-file-input>-->
  266. <v-menu
  267. ref="menu"
  268. v-model="menu"
  269. :close-on-content-click="false"
  270. :return-value.sync="startActivity.date"
  271. transition="scale-transition"
  272. offset-y
  273. min-width="auto"
  274. >
  275. <template v-slot:activator="{ on, attrs }">
  276. <v-text-field
  277. v-model="startActivity.date"
  278. label="Выберите дату"
  279. prepend-icon="mdi-calendar"
  280. readonly
  281. v-bind="attrs"
  282. v-on="on"
  283. ></v-text-field>
  284. </template>
  285. <v-date-picker v-model="startActivity.date" no-title scrollable>
  286. <v-spacer></v-spacer>
  287. <v-btn text color="primary" @click="menu = false"> Cancel </v-btn>
  288. <v-btn
  289. text
  290. color="primary"
  291. @click="$refs.menu.save(startActivity.date)"
  292. >
  293. OK
  294. </v-btn>
  295. </v-date-picker>
  296. </v-menu>
  297. <vue-timepicker
  298. v-model="startActivity.time"
  299. format="HH:mm:ss"
  300. ></vue-timepicker>
  301. <v-text-field v-model="source" label="Источник" @blur="getAlias">
  302. </v-text-field>
  303. <v-text-field v-model="hash_tags" label="Хэш-тэги"> </v-text-field>
  304. <v-text-field v-model="metaDescription" label="SEO-description">
  305. </v-text-field>
  306. <v-text-field v-model="metaKeys" label="SEO-keywords"> </v-text-field>
  307. </v-col>
  308. <div v-if="message.length" class="message-box">
  309. <v-alert
  310. v-model="message"
  311. :key="i"
  312. class="message"
  313. :type="messageClass ? messageClass : 'primary'"
  314. dismissible
  315. >
  316. {{ message }}
  317. </v-alert>
  318. </div>
  319. </v-row>
  320. </v-card>
  321. </v-tab-item>
  322. <v-tab-item>
  323. <v-card>
  324. <v-list two-line>
  325. <v-list-item v-for="comment in comments" :key="comment.id">
  326. <v-list-item-content>
  327. <v-row>
  328. <v-col>
  329. {{ comment.user_create_for_admin ? comment.user_create_for_admin.first_name : 'Гость' }}
  330. </v-col>
  331. <v-col cols="2">
  332. {{ convertDate(comment.created_at) }}
  333. </v-col>
  334. <v-col cols="6">
  335. {{ comment.message ? comment.message : '' }}
  336. </v-col>
  337. </v-row>
  338. </v-list-item-content>
  339. <v-list-item-action class="is-flex">
  340. <v-btn icon v-if="comment.need_moderation" @click="approveComment(comment.id)">
  341. <v-icon color="green lighten-1">mdi-check-circle</v-icon>
  342. </v-btn>
  343. <v-btn icon @click="removeComment(comment.id)">
  344. <v-icon color="red darker-1">mdi-delete</v-icon>
  345. <!--удалить-->
  346. </v-btn>
  347. <v-btn icon :to="{name: 'admin-comments-id', params: { id: comment.id, message: comment.message}}" target="_blank">
  348. <v-icon color="green darker-1"> mdi-pencil </v-icon>
  349. <!--изменить-->
  350. </v-btn>
  351. </v-list-item-action>
  352. </v-list-item>
  353. </v-list>
  354. </v-card>
  355. </v-tab-item>
  356. </v-tabs-items>
  357. </v-container>
  358. </template>
  359. <script>
  360. import VueTimepicker from "vue2-timepicker";
  361. import "vue2-timepicker/dist/VueTimepicker.css";
  362. import Treeselect from "@riophae/vue-treeselect";
  363. import "@riophae/vue-treeselect/dist/vue-treeselect.css";
  364. import global from "@/mixins/global";
  365. const nest = (items, id = null, link = "parent_id") => {
  366. return items
  367. .filter((item) => item[link] === id)
  368. .map((item) => ({
  369. ...item,
  370. label: item.title,
  371. children: nest(items, item.id),
  372. }));
  373. };
  374. export default {
  375. components: {
  376. VueTimepicker,
  377. Treeselect,
  378. },
  379. mixins: [global],
  380. async beforeRouteLeave(to, from, next) {
  381. if (this.confirm) {
  382. const out = window.confirm("Вы уверены, что хотите покинуть страницу?");
  383. if (!out) return;
  384. }
  385. if (this.editedInterval !== null) {
  386. clearInterval(this.editedInterval);
  387. await this.disableEdit();
  388. }
  389. next();
  390. },
  391. methods: {
  392. async enableEdit() {
  393. await this.$axios.get("/admin/news/edited_status/" + this.id + "/on").then((res) => {
  394. if(res.data.data.interception){
  395. this.$modal.show("is-interception-modal");
  396. clearInterval(this.editedInterval);
  397. }
  398. });
  399. },
  400. async disableEdit() {
  401. await this.$axios.get("/admin/news/edited_status/" + this.id + "/off")
  402. },
  403. interception(){
  404. this.$axios.get("/admin/news/edited_status/" + this.id + "/interception");
  405. this.$modal.hide("is-edited-modal");
  406. this.$modal.hide("is-interception-modal");
  407. this.editedInterval = setInterval(this.enableEdit, 60000);
  408. window.addEventListener("beforeunload", this.disableEdit);
  409. },
  410. getContainer(str) {
  411. this.$axios.get("admin/containers/type_" + str).then((res) => {
  412. if (str == "module") {
  413. this.modules = res.data.data;
  414. return res.data;
  415. } else if (str == "section") {
  416. this.sections = res.data.data;
  417. return res.data;
  418. } else if (str == "slider") {
  419. this.sliders = res.data.data;
  420. return res.data;
  421. }
  422. });
  423. },
  424. async getCategory() {
  425. await this.$axios.$get("/admin/categories").then((res) => {
  426. this.categories = res.data;
  427. return res.data;
  428. });
  429. },
  430. async getAuthors() {
  431. await this.$axios
  432. .$post("authorized/admin/user/profiles/list/by_group", {
  433. groups: [3],
  434. })
  435. .then((res) => {
  436. if (!res.data.users) return [];
  437. this.authors = {
  438. value: "",
  439. name: "",
  440. };
  441. this.authors = res.data.users.map((item) => ({
  442. value: item.user_id,
  443. name: item.first_name,
  444. }));
  445. return this.authors;
  446. });
  447. },
  448. url(relative_path) {
  449. let url = "https://api.amic.ru/" + relative_path;
  450. return url;
  451. },
  452. getFile(type) {
  453. if (type == "main-img") {
  454. return this.file;
  455. } else if (type == "preview-img") {
  456. return this.previewFile;
  457. } else if (type == "storie-img") {
  458. return this.storieFile;
  459. }
  460. },
  461. notificationHandler(message, error) {
  462. this.messageClass = false;
  463. this.message = message;
  464. if (error) {
  465. this.messageClass = "error";
  466. }
  467. const interva = setTimeout(() => {
  468. this.message = "";
  469. }, 2000);
  470. },
  471. fileHandler(type, width, height) {
  472. const fileData = new FormData();
  473. fileData.append("file", this.getFile(type));
  474. if (type == "main-img" && this.category.alias == "articles") {
  475. fileData.append("destination_width", 1900);
  476. fileData.append("destination_height", 800);
  477. }
  478. else if (
  479. type == "preview-img" &&
  480. this.category.parent_for_admin &&
  481. this.category.parent_for_admin.alias == 'video'
  482. ) {
  483. fileData.append("destination_width", 1400);
  484. fileData.append("destination_height", 650);
  485. }
  486. else {
  487. fileData.append("destination_width", width);
  488. fileData.append("destination_height", height);
  489. }
  490. fileData.append("title", "example");
  491. // TODO - добавить поле для названия фотографии. Создать метод - либо добавлять после создания, либо во время, либо до
  492. this.$axios
  493. .$post("authorized/admin/files/upload/image/news/raw", fileData, {
  494. headers: {
  495. "Content-Type": `multipart/form-data;`,
  496. },
  497. })
  498. .then((res) => {
  499. if (type == "main-img") {
  500. this.img = res.data;
  501. } else if (type == "preview-img") {
  502. this.previewImg = res.data;
  503. } else if (type == "storie-img") {
  504. this.storieImg = res.data;
  505. }
  506. if (res.success) {
  507. this.notificationHandler("Картинка удачно загрузилась!", false);
  508. } else {
  509. this.notificationHandler(res.errors.join("* "), true);
  510. }
  511. return res;
  512. })
  513. .catch((err) => {
  514. this.notificationHandler(err.errors.join("* "), true);
  515. return err;
  516. });
  517. },
  518. createNews(state) {
  519. this.confirm = false;
  520. this.$axios.post("admin/news/update", this.newsItem).then((res) => {
  521. console.log(res);
  522. if (res.status == 202) {
  523. this.notificationHandler("Публикация обновлена!", false);
  524. }
  525. });
  526. if (state == "save") {
  527. this.$router.push("/admin/publications");
  528. }
  529. },
  530. previewNews() {
  531. const path = this.isVideo ? '/preview/video' : '/preview';
  532. let { href } = this.$router.resolve({ path });
  533. this.$axios
  534. .post("admin/news/preview", this.newsItem)
  535. .then((res) => {
  536. let newsPreview = JSON.stringify(res.data.data);
  537. window.localStorage.setItem("preview", newsPreview);
  538. window.open(href, "_blank");
  539. })
  540. .catch((err) => this.notificationHandler(err.message, true));
  541. },
  542. shareNews() {
  543. const path = this.isVideo ?
  544. `/preview/video?uuid=${this.newsItem.id}` :
  545. `/preview?uuid=${this.newsItem.id}`;
  546. let { href } = this.$router.resolve({ path });
  547. window.open(href, "_blank");
  548. },
  549. deleteNews(id) {
  550. this.$swal
  551. .fire({
  552. title: "Вы уверены, что хотите удалить новость?",
  553. showCancelButton: true,
  554. confirmButtonText: "Удалить",
  555. icon: "error",
  556. cancelButtonText: `Не удалять`,
  557. confirmButtonColor: `#ab003c`,
  558. denyButtonColor: `#2196f3`,
  559. })
  560. .then((result) => {
  561. /* Read more about isConfirmed, isDenied below */
  562. if (result.isConfirmed) {
  563. this.$axios.post("/admin/news/remove", { id: id }).then((res) => {
  564. console.log(res.data);
  565. this.$axios
  566. .$get("/admin/news/list?page=1")
  567. .then((res) => {
  568. console.log(res.data);
  569. this.newsList = res.data;
  570. return res.data;
  571. })
  572. .catch((err) => {
  573. console.log(err);
  574. });
  575. return res;
  576. });
  577. this.$swal.fire("Удалено!", "", "error");
  578. this.$router.go(-1);
  579. } else if (result.isDenied) {
  580. this.$swal.fire("Отмена удаления", "", "info");
  581. }
  582. });
  583. },
  584. getAlias() {
  585. this.$axios
  586. .post("admin/alias/generation", { text: this.title })
  587. .then((res) => {
  588. if (res.status == 200) {
  589. this.generatedAlias = res.data.data.text;
  590. this.$axios
  591. .get(
  592. "admin/alias/check/news/" +
  593. this.generatedAlias +
  594. "/" +
  595. this.category.id
  596. )
  597. .then((res) => {
  598. if (res.success) {
  599. this.alias = this.generatedAlias;
  600. return generatedAlias;
  601. }
  602. });
  603. }
  604. return res;
  605. });
  606. },
  607. async loadFile(File) {
  608. const fileData = new FormData();
  609. fileData.append("file", File);
  610. fileData.append("title", File.name);
  611. const file = await this.$axios
  612. .post("authorized/admin/files/upload/document/news", fileData)
  613. .then((res) => res.data.data)
  614. .catch((e) => console.log(e));
  615. await this.$axios
  616. .post("admin/news/file/add", {
  617. file_id: file.id,
  618. news_id: this.id,
  619. })
  620. .catch((e) => console.log(e));
  621. return file;
  622. },
  623. async deleteFile(file, index) {
  624. this.files.splice(index, 1);
  625. await this.$axios
  626. .post("admin/news/file/remove", {
  627. file_id: file.id,
  628. news_id: this.id,
  629. })
  630. .catch((e) => console.log(e));
  631. },
  632. async loadFiles(files) {
  633. if (!files) return;
  634. const promises = files.map((file) => this.loadFile(file));
  635. const newFiles = await Promise.all(promises);
  636. this.files = [...this.files, ...newFiles];
  637. this.filesModel = null;
  638. },
  639. convertDate(dateTampstamp) {
  640. const date = new Date(dateTampstamp);
  641. const dateString =
  642. date.toLocaleString("ru", {
  643. day: "numeric",
  644. month: "long",
  645. }) +
  646. " " +
  647. date.getFullYear() +
  648. ", " +
  649. ("0" + date.getHours()).slice(-2) +
  650. ":" +
  651. ("0" + date.getMinutes()).slice(-2);
  652. return dateString;
  653. },
  654. async approveComment(commentId) {
  655. await this.$axios
  656. .$get(
  657. "https://api.amic.ru/api/v1/admin/comments/approve/" +
  658. commentId
  659. )
  660. .then((res) => {
  661. if(res.success){
  662. alert('Комментарий одобрен');
  663. }else{
  664. alert('Ошибка одобрения комментария');
  665. }
  666. })
  667. .catch((error) => {
  668. alert('Ошибка одобрения комментария');
  669. console.log(error);
  670. });
  671. },
  672. async removeComment(commentId) {
  673. await this.$axios
  674. .$get(
  675. "https://api.amic.ru/api/v1/admin/comments/remove/" +
  676. commentId
  677. )
  678. .then((res) => {
  679. if(res.success){
  680. alert('Комментарий удалён');
  681. }else{
  682. alert('Ошибка удаления комментария');
  683. }
  684. })
  685. .catch((error) => {
  686. alert('Ошибка удаления комментария');
  687. });
  688. },
  689. },
  690. data() {
  691. return {
  692. confirm: true,
  693. sliderId: "",
  694. messageClass: "",
  695. menu: "",
  696. message: "",
  697. author: "",
  698. authors: [],
  699. storieImg: null,
  700. dont_send_to_rss: null,
  701. hash_tags: "",
  702. sorting: null,
  703. is_edited: false,
  704. editedInterval: null,
  705. showAuthor: true,
  706. allowComments: true,
  707. advertisement: false,
  708. advertisement_mark: false,
  709. partner: false,
  710. contraindications: false,
  711. modules: [],
  712. sliders: [],
  713. sections: [],
  714. metaDescription: "",
  715. editor: null,
  716. content: "",
  717. title: "",
  718. description: "",
  719. category: null,
  720. metaKeys: " ",
  721. img: {},
  722. detail_img_id: "",
  723. source: "",
  724. previewImg: {},
  725. preview_img_id: "",
  726. previewFile: null,
  727. storieFile: null,
  728. file: null,
  729. lightning: false,
  730. activity: true,
  731. alias: "",
  732. showInStories: false,
  733. generatedAlias: "",
  734. startActivity: {
  735. date: "",
  736. time: "",
  737. },
  738. id: "",
  739. categories: [],
  740. propertiesForAdmin: [],
  741. propertiesList: [],
  742. video: "",
  743. externalLink: "",
  744. token: "",
  745. files: [],
  746. filesModel: null,
  747. verified: false,
  748. tab: null,
  749. items_tab: [
  750. 'Новость', 'Комментарии',
  751. ],
  752. comments: []
  753. };
  754. },
  755. validations: {},
  756. layout: "admin",
  757. // Компьютед
  758. computed: {
  759. isVideo() {
  760. if(!this.category) return false;
  761. const parentCategory = this.category.parent_for_admin;
  762. return parentCategory && parentCategory.alias == 'video';
  763. },
  764. start_activity() {
  765. return this.startActivity.date + " " + this.startActivity.time;
  766. },
  767. properties() {
  768. const entries = this.propertiesList.map((p) => [p.id, this[p.code]]);
  769. return Object.fromEntries(entries);
  770. },
  771. newsItem() {
  772. return {
  773. author: this.author,
  774. title: this.title,
  775. text: this.content,
  776. alias: this.generatedAlias,
  777. description: this.description,
  778. activity: this.activity,
  779. news_category_id: this.category.id,
  780. start_activity: this.start_activity,
  781. detail_image_id: this.img.id ? this.img.id : this.img.image_id,
  782. preview_image_id: this.previewImg.id
  783. ? this.previewImg.id
  784. : this.previewImg.image_id,
  785. source: this.source,
  786. slider_id: this.sliderId ? this.sliderId : "",
  787. section_id: this.sectionId ? this.sectionId : "",
  788. meta_description: this.metaDescription,
  789. module_id: this.moduleId ? this.moduleId : "",
  790. meta_key: this.metaKeys,
  791. allow_comments: this.allowComments,
  792. show_author: this.showAuthor,
  793. sorting: Number(this.sorting),
  794. lightning: this.lightning,
  795. show_in_stories: this.showInStories,
  796. id: this.id,
  797. hash_tags: this.hash_tags,
  798. dont_send_to_rss: this.dont_send_to_rss,
  799. properties: this.properties,
  800. video: this.video,
  801. link: this.externalLink,
  802. verified: this.verified,
  803. token: this.token,
  804. advertisement_mark: this.advertisement_mark,
  805. };
  806. },
  807. treeCategories() {
  808. if (!this.categories) return [];
  809. return nest(this.categories);
  810. },
  811. authorsList() {
  812. return this.authors;
  813. },
  814. },
  815. // Компьютед конец
  816. async mounted() {
  817. window.addEventListener("beforeunload", (event) => {
  818. event.preventDefault();
  819. event.returnValue = "";
  820. });
  821. await this.getCategory();
  822. await this.getAuthors();
  823. console.log("/admin/news/item/" + this.$route.params.id)
  824. await this.$axios
  825. .$get("/admin/news/item/" + this.$route.params.id)
  826. .then((res) => {
  827. this.author =
  828. res.data.author_for_admin && res.data.author_for_admin.id.length
  829. ? res.data.author_for_admin.id
  830. : "";
  831. this.is_edited = res.data.editor;
  832. this.title = res.data.title;
  833. this.generatedAlias = res.data.alias;
  834. this.description = res.data.description;
  835. this.startActivity.date = res.data.start_activity.split(" ")[0]
  836. ? res.data.start_activity.split(" ")[0]
  837. : "";
  838. this.startActivity.time = res.data.start_activity.split(" ")[1]
  839. ? res.data.start_activity.split(" ")[1]
  840. : "";
  841. this.img = res.data.detail_image_for_admin
  842. ? res.data.detail_image_for_admin
  843. : "";
  844. this.detail_img_id = res.data.detail_image_id
  845. ? res.data.detail_image_id
  846. : "";
  847. this.previewImg = res.data.preview_image_for_admin
  848. ? res.data.preview_image_for_admin
  849. : "";
  850. this.preview_img_id = res.data.preview_image_id
  851. ? res.data.preview_image_id
  852. : "";
  853. this.source = res.data.source;
  854. this.activity = res.data.activity;
  855. this.metaDescription = res.data.meta_description;
  856. this.showInStories = res.data.show_in_stories;
  857. this.metaKeys = res.data.meta_key;
  858. this.allowComments = res.data.pull_for_admin.is_show_comments;
  859. this.showAuthor = res.data.show_author;
  860. this.sorting = res.data.sorting;
  861. this.lightning = res.data.lightning;
  862. this.showInStories = res.data.show_in_stories;
  863. this.id = res.data.id;
  864. this.hash_tags = res.data.hash_tags;
  865. this.dont_send_to_rss = res.data.dont_send_to_rss;
  866. this.content = res.data.text;
  867. this.sliderId = res.data.slider_id;
  868. this.video = res.data.video ? res.data.video : "";
  869. this.category = res.data.category_for_admin;
  870. this.externalLink = res.data.link;
  871. this.advertisement_mark = res.data.advertisement_mark;
  872. this.token = res.data.token;
  873. this.verified = res.data.verified;
  874. this.files = res.data.files_for_admin.map((e) => e.file_for_admin);
  875. this.comments = res.data.comments_for_admin;
  876. this.propertiesForAdmin = res.data.properties_for_admin.map(
  877. (element) => ({ ...element.property, value: element.value })
  878. );
  879. this.propertiesForAdmin.forEach((property) => {
  880. this[property.code] = Number(property.value);
  881. });
  882. return res;
  883. });
  884. if (this.is_edited) {
  885. this.$modal.show("is-edited-modal");
  886. } else {
  887. await this.enableEdit();
  888. this.editedInterval = setInterval(this.enableEdit, 60000);
  889. window.addEventListener("beforeunload", this.disableEdit);
  890. }
  891. await this.$axios
  892. .get("admin/properties")
  893. .then((res) => (this.propertiesList = res.data.data));
  894. },
  895. };
  896. </script>
  897. <style lang="less" scoped>
  898. img {
  899. max-width: 250px;
  900. }
  901. .tree-select {
  902. margin-bottom: 15px;
  903. }
  904. .message {
  905. width: 400px;
  906. height: 100px;
  907. text-align: center;
  908. display: flex;
  909. align-items: center;
  910. justify-content: center;
  911. box-shadow: 1px 1px 1px 1px;
  912. background: white;
  913. &-box {
  914. display: flex;
  915. flex-direction: column;
  916. align-items: flex-end;
  917. right: 20px;
  918. bottom: 20px;
  919. position: fixed;
  920. justify-content: flex-end;
  921. }
  922. }
  923. </style>