TerrainDeVie.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <script>
  2. import { mapActions, mapState } from 'pinia'
  3. import { ConcernementsStore } from '@stores/concernements'
  4. import { UserStore } from '@/stores/user'
  5. // import { CommonStore } from '@/stores/common'
  6. import { print } from 'graphql/language/printer'
  7. import gql from 'graphql-tag'
  8. import GQL from '@api/graphql-axios'
  9. import EntiteFields from '@api/gql/entite.fragment.gql'
  10. import CartoucheLayout from '@components/layout/CartoucheLayout.vue';
  11. import Entite from '@components/contents/Entite.vue';
  12. import VueSlider from 'vue-slider-component'
  13. import 'vue-slider-component/theme/default.css'
  14. import SvgIcon from '@jamescoyle/vue-icon';
  15. import { mdiChevronRight } from '@mdi/js';
  16. import { mdiChevronDown } from '@mdi/js';
  17. import ContentEditable from '@components/editable/ContentEditable.vue';
  18. export default {
  19. props: ['cid', 'eid'],
  20. data(){
  21. return {
  22. concernement: null,
  23. entite: null,
  24. history_value: 0,
  25. history_slider_ops: null,
  26. details_value: 1,
  27. details_slider_ops: null,
  28. infos_opened: false,
  29. chevronright_path: mdiChevronRight,
  30. chevrondown_path: mdiChevronDown,
  31. headerreduced: false,
  32. }
  33. },
  34. computed: {
  35. ...mapState(ConcernementsStore,['map_mode',
  36. 'opened_concernement',
  37. 'concernementsByID',
  38. 'ct_concernement',
  39. 'ct_entite',
  40. 'detailsZoomValue']),
  41. ...mapState(UserStore,['name']),
  42. created(){
  43. let d = new Date(this.concernement.created);
  44. console.log('d', d);
  45. return d.toLocaleDateString("fr-FR");//.toISOString().split('T')[0];
  46. },
  47. changed(){
  48. let d = new Date(this.concernement.changed);
  49. console.log('d', d);
  50. return d.toLocaleDateString("fr-FR");//.toISOString().split('T')[0];
  51. },
  52. display_concernement(){
  53. return this.ct_concernement && !this.entite && this.map_mode !== 'puissancedagir' && this.map_mode !== 'doleancer';
  54. },
  55. entity_title_label(){
  56. let menacemaintien_str;
  57. if (this.concernement.entites_byid[this.eid].menacemaintien > 0) {
  58. menacemaintien_str = 'maintenu';
  59. } else {
  60. menacemaintien_str = 'menacé';
  61. }
  62. let actuelfuture_str;
  63. if (this.concernement.entites_byid[this.eid].actuelfuture > 0) {
  64. actuelfuture_str = 'sera';
  65. } else {
  66. actuelfuture_str = 'est';
  67. }
  68. return `Pouvez-vous nommer par qui ou par quoi cet élément ${actuelfuture_str} ${menacemaintien_str} ?`;
  69. }
  70. },
  71. created () {
  72. this.concernement = this.concernementsByID[this.cid];
  73. console.log(`terraindevie created, cid: ${this.cid}, eid: ${this.eid}, this.concernement:`, this.concernement);
  74. //entite
  75. if (this.eid) {
  76. this.loadEntite()
  77. }
  78. // revisions
  79. let data=[];
  80. if (this.concernement && this.concernement.revisions) {
  81. this.concernement.revisions.forEach(rev => {
  82. if (rev.entites.length > 3) {
  83. let d = new Date(rev.changed);
  84. data.push({
  85. 'id': rev.revision_id,
  86. 'changed': d.toLocaleDateString("fr-FR")
  87. })
  88. this.history_value = Math.max(this.history_value, parseInt(rev.revision_id));
  89. }
  90. });
  91. }
  92. if (data.length > 1) {
  93. this.history_slider_ops = {
  94. dotSize:10,
  95. data: data,
  96. 'data-value': 'id',
  97. 'data-label': 'changed',
  98. adsorb: true,
  99. 'hide-label': true
  100. }
  101. } else {
  102. this.history_slider_ops = null;
  103. }
  104. // details
  105. this.details_slider_ops = {
  106. min: 1,
  107. max: 4,
  108. interval: 0.05,
  109. 'hide-label': true,
  110. tooltip: 'none',
  111. dotSize:10,
  112. }
  113. },
  114. // mounted(){
  115. // console.log('terrain de vie mounted', this);
  116. // // this.$refs.cartouche_main.addEventListener('scroll', (event) => {
  117. // // console.log('main is scrolling', event);
  118. // // })
  119. // },
  120. watch: {
  121. history_value: {
  122. handler (n, o) {
  123. // console.log(`TerrainDeVie watch history_value o:${o}, n:${n}`);
  124. this.setActiveRevision(this.cid, n);
  125. },
  126. deep: true
  127. },
  128. details_value: {
  129. handler (n, o) {
  130. // console.log(`TerrainDeVie watch history_value o:${o}, n:${n}`);
  131. this.setDetailsZoomValue(n);
  132. },
  133. deep: true
  134. },
  135. detailsZoomValue: {
  136. handler (n, o) {
  137. // console.log(`TerrainDeVie watch history_value o:${o}, n:${n}`);
  138. this.details_value = n;
  139. },
  140. deep: true
  141. },
  142. cid: {
  143. handler (n,o) {
  144. console.log(`TerrainDeVie watch cid o:${o}, n:${n}`);
  145. if (n) {
  146. this.concernement = this.concernementsByID[n];
  147. }
  148. },
  149. deep: true
  150. },
  151. eid: {
  152. handler (n, o) {
  153. console.log(`TerrainDeVie watch eid o:${o}, n:${n}`);
  154. if (n) {
  155. this.loadEntite()
  156. }else{
  157. this.entite = null;
  158. }
  159. },
  160. deep: true
  161. }
  162. },
  163. methods: {
  164. ...mapActions(ConcernementsStore, ['setActiveRevision', 'setDetailsZoomValue']), // 'loadConcernementsRevisions'
  165. onClickInfos(){
  166. this.infos_opened = !this.infos_opened;
  167. },
  168. loadEntite(){
  169. const ast = gql`{
  170. entite (id: ${this.eid}) {
  171. ...EntiteFields
  172. }
  173. }
  174. ${EntiteFields}
  175. `
  176. console.log('ast', ast);
  177. GQL.post('', { query: print(ast) })
  178. .then(({data: { data: { entite }}}) => {
  179. console.log('load entite loaded', entite)
  180. this.entite = entite
  181. })
  182. .catch(error => {
  183. console.warn('Issue with load entite', error)
  184. })
  185. },
  186. onMainScrolled(scrolled){
  187. console.log('this.$refs', this.$refs);
  188. let cartouche_main = this.$refs.cartouche_layout.$refs.cartouche_main;
  189. console.log('cartouche_main', cartouche_main);
  190. if(scrolled && cartouche_main.scrollHeight > 600){
  191. this.headerreduced = true;
  192. } else {
  193. this.headerreduced = false;
  194. }
  195. },
  196. onContentEditableFocusOut(e){
  197. console.log('onContentEditableFocusOut', e);
  198. let new_field_content = e.target.innerText;
  199. console.log('onContentEditableFocusOut', new_field_content);
  200. console.log('onContentEditableFocusOut this.concernement.title', this.concernement.title);
  201. }
  202. },
  203. components: {
  204. CartoucheLayout,
  205. Entite,
  206. VueSlider,
  207. SvgIcon,
  208. ContentEditable
  209. }
  210. }
  211. </script>
  212. <template>
  213. <CartoucheLayout ref="cartouche_layout" :cid="cid" @main_scrolled="onMainScrolled">
  214. <template v-slot:header>
  215. <div class="entite">
  216. <!-- TODO update entite with revisions -->
  217. <label v-if="entite" class="menacemaintient" :class="{ hidden: headerreduced}">{{ entity_title_label }}</label>
  218. <!-- <h3 v-if="entite" class="entite-title">{{ entite.title }}</h3> -->
  219. <ContentEditable
  220. v-if="entite"
  221. tag="h3"
  222. :value="entite.title"
  223. class="entite-title"
  224. :contenteditable="entite.can_update"
  225. :data="{
  226. entitytype: 'node',
  227. bundle: 'entite',
  228. nid: this.entite.id,
  229. field: 'title'
  230. }" />
  231. </div>
  232. </template>
  233. <template v-slot:main>
  234. <!-- concernement -->
  235. <template v-if="!entite">
  236. <section v-if="concernement.description" class="description">
  237. <label v-if="ct_concernement">{{ ct_concernement.field_description.description }}</label>
  238. <ContentEditable
  239. tag="p"
  240. :value="concernement.description"
  241. :html="true"
  242. :class="{ ellipsed: headerreduced }"
  243. :contenteditable="concernement.can_update"
  244. :data="{
  245. entitytype: 'node',
  246. bundle: 'concernement',
  247. nid: this.concernement.id,
  248. field: 'field_description'
  249. }" />
  250. </section>
  251. <section v-if="concernement.caillou" class="caillou">
  252. <label v-if="ct_concernement">{{ ct_concernement.field_caillou.description }}</label>
  253. <ContentEditable
  254. tag="p"
  255. :value="concernement.caillou"
  256. :class="{ ellipsed: headerreduced }"
  257. :contenteditable="concernement.can_update"
  258. :data="{
  259. entitytype: 'node',
  260. bundle: 'concernement',
  261. nid: this.concernement.id,
  262. field: 'field_caillou'
  263. }" />
  264. </section>
  265. </template>
  266. <!-- entite -->
  267. <Entite v-if="entite" :concernement="concernement" :entite="entite" :eid="eid"/>
  268. </template>
  269. <template v-slot:footer>
  270. <section class="infos">
  271. <svg-icon
  272. type="mdi"
  273. :path="!infos_opened ? chevronright_path : chevrondown_path"
  274. class="open-btn"
  275. @click="onClickInfos"
  276. ></svg-icon>
  277. <div
  278. class="author info"
  279. @click="onClickInfos">
  280. <span>une enquête de</span> {{ concernement.author.username }}<br/>
  281. </div>
  282. <div class="wrapper" :class="{ 'opened': infos_opened }">
  283. <div class="info structure" v-if="concernement.author.structure.length"><span>avec</span> {{ concernement.author.structure[0].name }}<br/></div>
  284. <div class="info lieu" v-if="concernement.lieu.length"><span>à</span> {{ concernement.lieu[0].name }}<br/></div>
  285. <div class="info created"><span>démarrée le</span> {{ created }}<br/></div>
  286. <div class="info changed"><span>mise à jour le</span> {{ changed }}</div>
  287. <div class="info recit-colophon" v-if="concernement.recit_colophon" v-html="concernement.recit_colophon"/>
  288. </div>
  289. </section>
  290. <section class="sliders" v-if="history_slider_ops || details_slider_ops">
  291. <section class="historique" v-if="history_slider_ops">
  292. <label>Historique</label>
  293. <!-- <h3>{{ history_value }}</h3> -->
  294. <vue-slider
  295. ref="slider"
  296. v-model="history_value"
  297. v-bind="history_slider_ops"
  298. ></vue-slider>
  299. </section>
  300. <section class="details" v-if="details_slider_ops && map_mode === 'terraindevie'">
  301. <label>Détails</label>
  302. <!-- <h3>{{ details_value }}</h3> -->
  303. <vue-slider
  304. ref="details_slider"
  305. v-model="details_value"
  306. v-bind="details_slider_ops"
  307. ></vue-slider>
  308. </section>
  309. </section>
  310. </template>
  311. </CartoucheLayout>
  312. </template>
  313. <style lang="css">
  314. span.entite-point{
  315. color: #01ffe2;
  316. }
  317. </style>