@tekkare/romulus 0.1.250 → 0.1.252
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/runtime/components/BarChart.vue +1 -0
- package/dist/runtime/components/ChoroplethMap.vue +4 -1
- package/dist/runtime/internal/geo/fr-regions.json +1 -1
- package/dist/runtime/utils/chart.d.ts +6 -3
- package/dist/runtime/utils/chart.js +15 -2
- package/layer/app/app.config.ts +6 -0
- package/layer/app/components/OipPubmedSummary.vue +223 -0
- package/layer/app/components/OipResourceDrawer.vue +331 -0
- package/layer/app/components/OipResourceDrawerLink.vue +40 -0
- package/layer/app/components/OipResourceField.vue +41 -0
- package/layer/app/components/OipResourceGenericCard.vue +54 -0
- package/layer/app/components/OipResourceSource.vue +50 -0
- package/layer/app/components/OipResourceTags.vue +65 -0
- package/layer/app/components/OipResourceView.vue +107 -0
- package/layer/app/components/oip-drugs/fiches/AssociationFiche.vue +775 -0
- package/layer/app/components/oip-drugs/fiches/BrandFiche.vue +1111 -0
- package/layer/app/components/oip-drugs/fiches/IndicationFiche.vue +182 -0
- package/layer/app/components/oip-drugs/fiches/JoFiche.vue +101 -0
- package/layer/app/components/oip-drugs/fiches/PndsFiche.vue +279 -0
- package/layer/app/components/oip-drugs/heart/JoCard.vue +314 -0
- package/layer/app/components/oip-drugs/heart/TextHighlight.vue +326 -0
- package/layer/app/components/oip-drugs/heart/ansm/BrandCard.vue +187 -0
- package/layer/app/components/oip-drugs/heart/ansm/CisDetail.vue +363 -0
- package/layer/app/components/oip-drugs/heart/ansm/CisTable.vue +167 -0
- package/layer/app/components/oip-drugs/heart/associations/NationalAssemblyCard.vue +373 -0
- package/layer/app/components/oip-drugs/heart/associations/NationalAssemblyFiche.vue +372 -0
- package/layer/app/components/oip-drugs/heart/associations/TranscriptionCard.vue +55 -0
- package/layer/app/components/oip-drugs/heart/elastic/SourceContainerElastic.vue +103 -0
- package/layer/app/components/oip-drugs/heart/france/BrandGroupCard.vue +450 -0
- package/layer/app/components/oip-drugs/heart/mitm/Card.vue +199 -0
- package/layer/app/components/oip-drugs/heart/mitm/Source.vue +23 -0
- package/layer/app/components/oip-drugs/heart/mitm/details/Overview.vue +381 -0
- package/layer/app/components/oip-drugs/heart/put/Card.vue +212 -0
- package/layer/app/components/oip-drugs/heart/results/AccesCard.vue +696 -0
- package/layer/app/components/oip-drugs/heart/results/AlertCard.vue +342 -0
- package/layer/app/components/oip-drugs/heart/results/AsmrCursor.vue +229 -0
- package/layer/app/components/oip-drugs/heart/results/EvalCard.vue +370 -0
- package/layer/app/components/oip-drugs/heart/results/IndicCard.vue +743 -0
- package/layer/app/components/oip-drugs/heart/results/MatchExplain.vue +243 -0
- package/layer/app/components/oip-drugs/heart/results/PrefRows.vue +105 -0
- package/layer/app/components/oip-drugs/heart/results/details/HasHistory.vue +487 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalCountryCard.vue +461 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalOverview.vue +200 -0
- package/layer/app/components/oip-drugs/heart/results/details/InternationalPriceDrawer.vue +647 -0
- package/layer/app/components/oip-drugs/heart/results/details/Monograph.vue +128 -0
- package/layer/app/components/oip-drugs/heart/results/details/OpinionDrawer.vue +535 -0
- package/layer/app/components/oip-drugs/heart/results/details/PresentationDrawer.vue +738 -0
- package/layer/app/components/oip-drugs/heart/results/details/Price.vue +227 -0
- package/layer/app/components/oip-drugs/heart/results/details/PriceOverview.vue +1261 -0
- package/layer/app/components/oip-drugs/heart/results/details/RecordDrawer.vue +494 -0
- package/layer/app/components/oip-drugs/heart/results/details/RecordList.vue +426 -0
- package/layer/app/components/oip-drugs/heart/results/les/Card.vue +340 -0
- package/layer/app/components/oip-drugs/heart/results/les/Drawer.vue +67 -0
- package/layer/app/components/oip-drugs/heart/results/les/IndicationDetail.vue +149 -0
- package/layer/app/components/oip-drugs/heart/results/les/Source.vue +20 -0
- package/layer/app/components/oip-drugs/heart/results/les/SourceTag.vue +39 -0
- package/layer/app/components/oip-drugs/heart/searchPage/DynamicSource.vue +29 -0
- package/layer/app/components/oip-drugs/medicam/market/Chart.vue +121 -0
- package/layer/app/components/oip-drugs/outpatient/ProductEvolution.vue +236 -0
- package/layer/app/components/oip-drugs/resources/Ansm.vue +75 -0
- package/layer/app/components/oip-drugs/resources/Association.vue +30 -0
- package/layer/app/components/oip-drugs/resources/Brand.vue +65 -0
- package/layer/app/components/oip-drugs/resources/Contribution.vue +216 -0
- package/layer/app/components/oip-drugs/resources/Hospital.vue +151 -0
- package/layer/app/components/oip-drugs/resources/Indication.vue +54 -0
- package/layer/app/components/oip-drugs/resources/Jo.vue +57 -0
- package/layer/app/components/oip-drugs/resources/Medicam.vue +140 -0
- package/layer/app/components/oip-drugs/resources/Mitm.vue +84 -0
- package/layer/app/components/oip-drugs/resources/NationalAssembly.vue +93 -0
- package/layer/app/components/oip-drugs/resources/Outpatient.vue +97 -0
- package/layer/app/components/oip-drugs/resources/Pnds.vue +24 -0
- package/layer/app/components/oip-drugs/resources/Price.vue +106 -0
- package/layer/app/components/oip-drugs/resources/Put.vue +143 -0
- package/layer/app/components/oip-science/appel-a-projet/Cards.vue +162 -0
- package/layer/app/components/oip-science/clinical-trials/Cards.vue +382 -0
- package/layer/app/components/oip-science/clinical-trials/CardsGlobal.vue +273 -0
- package/layer/app/components/oip-science/clinical-trials/LinkedList.vue +366 -0
- package/layer/app/components/oip-science/clinical-trials/PairBadge.vue +25 -0
- package/layer/app/components/oip-science/clinical-trials/PairBody.vue +182 -0
- package/layer/app/components/oip-science/clinical-trials/SitesDrawer.vue +95 -0
- package/layer/app/components/oip-science/common/Form.vue +73 -0
- package/layer/app/components/oip-science/common/MatchAvgTag.vue +283 -0
- package/layer/app/components/oip-science/common/NoData.vue +16 -0
- package/layer/app/components/oip-science/common/ScoreBadge.vue +35 -0
- package/layer/app/components/oip-science/common/Source.vue +31 -0
- package/layer/app/components/oip-science/common/TableTags.vue +279 -0
- package/layer/app/components/oip-science/common/Timeline.vue +104 -0
- package/layer/app/components/oip-science/common/ToolTips.vue +89 -0
- package/layer/app/components/oip-science/cross/publicationPubmed.vue +484 -0
- package/layer/app/components/oip-science/crossData/CrossDataLocations.vue +71 -0
- package/layer/app/components/oip-science/ctgov/Investigators.vue +148 -0
- package/layer/app/components/oip-science/ctgov/Locations.vue +102 -0
- package/layer/app/components/oip-science/ctgov/Publications.vue +52 -0
- package/layer/app/components/oip-science/ctgov/Sponsors.vue +66 -0
- package/layer/app/components/oip-science/ctgov/StudyDescription.vue +1136 -0
- package/layer/app/components/oip-science/ctgov-centers/ClinicalTrials.vue +40 -0
- package/layer/app/components/oip-science/ctgov-centers/Publications.vue +50 -0
- package/layer/app/components/oip-science/ctgov-investigators/ClinicalTrials.vue +43 -0
- package/layer/app/components/oip-science/ctgov-investigators/Informations.vue +171 -0
- package/layer/app/components/oip-science/ctgov-investigators/Publications.vue +44 -0
- package/layer/app/components/oip-science/elastic/DateRangeFilter.vue +209 -0
- package/layer/app/components/oip-science/elastic/Filter.vue +719 -0
- package/layer/app/components/oip-science/elastic/MatchExplain.vue +152 -0
- package/layer/app/components/oip-science/establishments/Cards.vue +183 -0
- package/layer/app/components/oip-science/establishments/ClinicalTrials.vue +62 -0
- package/layer/app/components/oip-science/establishments/Hcps.vue +227 -0
- package/layer/app/components/oip-science/establishments/Informations.vue +263 -0
- package/layer/app/components/oip-science/establishments/LinkedList.vue +153 -0
- package/layer/app/components/oip-science/establishments/MatchedLabels.vue +194 -0
- package/layer/app/components/oip-science/establishments/PublicFinance.vue +62 -0
- package/layer/app/components/oip-science/euct/Investigators.vue +125 -0
- package/layer/app/components/oip-science/euct/Locations.vue +102 -0
- package/layer/app/components/oip-science/euct/Products.vue +101 -0
- package/layer/app/components/oip-science/euct/Publications.vue +89 -0
- package/layer/app/components/oip-science/euct/Sponsors.vue +86 -0
- package/layer/app/components/oip-science/euct/StudyDescription.vue +1075 -0
- package/layer/app/components/oip-science/euct-centers/ClinicalTrials.vue +40 -0
- package/layer/app/components/oip-science/euct-centers/Publications.vue +55 -0
- package/layer/app/components/oip-science/euct-investigators/ClinicalTrials.vue +41 -0
- package/layer/app/components/oip-science/euct-investigators/Informations.vue +171 -0
- package/layer/app/components/oip-science/euct-investigators/Publications.vue +51 -0
- package/layer/app/components/oip-science/hcps/AppelsAProjet.vue +62 -0
- package/layer/app/components/oip-science/hcps/Cards.vue +237 -0
- package/layer/app/components/oip-science/hcps/ClinicalTrials.vue +78 -0
- package/layer/app/components/oip-science/hcps/Informations.vue +296 -0
- package/layer/app/components/oip-science/hcps/LinkedList.vue +153 -0
- package/layer/app/components/oip-science/hcps/MatchedLabels.vue +207 -0
- package/layer/app/components/oip-science/hcps/Pubmed.vue +128 -0
- package/layer/app/components/oip-science/local/SliderTabs.vue +99 -0
- package/layer/app/components/oip-science/local/SliderTabsFull.vue +135 -0
- package/layer/app/components/oip-science/pubmed/Authors.vue +128 -0
- package/layer/app/components/oip-science/pubmed/Cards.vue +417 -0
- package/layer/app/components/oip-science/pubmed/ClinicalTrials.vue +71 -0
- package/layer/app/components/oip-science/resources/Phrc.vue +39 -0
- package/layer/app/composables/useOipChapterScroll.ts +43 -0
- package/layer/app/composables/useOipResourceHooks.ts +27 -0
- package/layer/app/composables/useOipResourceNav.ts +66 -0
- package/layer/app/composables/useOipResourceViews.ts +117 -0
- package/layer/app/composables/useOipResources.ts +83 -0
- package/layer/app/oip-drugs/PORTING.md +120 -0
- package/layer/app/oip-drugs/composables/useAssociationDetail.ts +220 -0
- package/layer/app/oip-drugs/composables/useAssociationExport.ts +63 -0
- package/layer/app/oip-drugs/composables/useAssociationLookup.ts +105 -0
- package/layer/app/oip-drugs/composables/useCardPrefOptions.ts +201 -0
- package/layer/app/oip-drugs/composables/useCurrency.ts +121 -0
- package/layer/app/oip-drugs/composables/useDirectusSources.ts +224 -0
- package/layer/app/oip-drugs/composables/useHeartBrandMatches.ts +112 -0
- package/layer/app/oip-drugs/composables/useHeartDetailSearches.ts +479 -0
- package/layer/app/oip-drugs/composables/useHeartIntlApprovals.ts +661 -0
- package/layer/app/oip-drugs/composables/useHeartLesIndication.ts +168 -0
- package/layer/app/oip-drugs/composables/useHeartMatchExplain.ts +231 -0
- package/layer/app/oip-drugs/composables/useHeartReports.ts +239 -0
- package/layer/app/oip-drugs/composables/useHeartSearchFields.ts +233 -0
- package/layer/app/oip-drugs/composables/useMergeByKey.ts +23 -0
- package/layer/app/oip-drugs/composables/useOipDrugsElastic.ts +621 -0
- package/layer/app/oip-drugs/composables/usePageEmpty.ts +58 -0
- package/layer/app/oip-drugs/composables/v-useSalesSource.ts +64 -0
- package/layer/app/oip-drugs/drugs.css +500 -0
- package/layer/app/oip-drugs/esIndices.ts +322 -0
- package/layer/app/oip-drugs/kinds.ts +264 -0
- package/layer/app/oip-drugs/locales/en.json +1571 -0
- package/layer/app/oip-drugs/locales/fr.json +1571 -0
- package/layer/app/oip-drugs/monographs/blincyto-has.vue +289 -0
- package/layer/app/oip-drugs/monographs/darzalex-has.vue +276 -0
- package/layer/app/oip-drugs/monographs/dupixent-has.vue +216 -0
- package/layer/app/oip-drugs/monographs/enhertu-has.vue +280 -0
- package/layer/app/oip-drugs/monographs/has-sein-2023.vue +1649 -0
- package/layer/app/oip-drugs/monographs/ibrance-has.vue +277 -0
- package/layer/app/oip-drugs/monographs/imfinzi-has.vue +293 -0
- package/layer/app/oip-drugs/monographs/keytruda-has.vue +334 -0
- package/layer/app/oip-drugs/monographs/kisqali-has.vue +201 -0
- package/layer/app/oip-drugs/monographs/opdivo-has.vue +231 -0
- package/layer/app/oip-drugs/monographs/ozempic-has.vue +186 -0
- package/layer/app/oip-drugs/monographs/tecentriq-has.vue +312 -0
- package/layer/app/oip-drugs/monographs/yescarta-has.vue +272 -0
- package/layer/app/oip-drugs/types/elastic.ts +113 -0
- package/layer/app/oip-drugs/types/es/agencies.ts +152 -0
- package/layer/app/oip-drugs/types/es/directory.ts +54 -0
- package/layer/app/oip-drugs/types/es/docByIndex.ts +151 -0
- package/layer/app/oip-drugs/types/es/openmedic.ts +67 -0
- package/layer/app/oip-drugs/types/es/outpatient.ts +71 -0
- package/layer/app/oip-drugs/types/es/portal.ts +130 -0
- package/layer/app/oip-drugs/types/es/retail.ts +107 -0
- package/layer/app/oip-drugs/types/es/statistics.ts +29 -0
- package/layer/app/oip-drugs/types/heart/CurrencyRate.ts +16 -0
- package/layer/app/oip-drugs/types/heart/ansm.ts +106 -0
- package/layer/app/oip-drugs/types/heart/tag.ts +29 -0
- package/layer/app/oip-drugs/utils/associationFields.ts +118 -0
- package/layer/app/oip-drugs/utils/contributions.ts +36 -0
- package/layer/app/oip-drugs/utils/countryMapping.ts +387 -0
- package/layer/app/oip-drugs/utils/esHighlight.ts +21 -0
- package/layer/app/oip-drugs/utils/exportSheets.ts +57 -0
- package/layer/app/oip-drugs/utils/heartIntlPrice.ts +228 -0
- package/layer/app/oip-drugs/utils/heartStyleAndFormat.ts +262 -0
- package/layer/app/oip-drugs/utils/heartStyleAnsm.ts +71 -0
- package/layer/app/oip-drugs/utils/latestDate.ts +31 -0
- package/layer/app/oip-drugs/utils/p-heartCardTags.ts +53 -0
- package/layer/app/oip-drugs/utils/priceExport.ts +269 -0
- package/layer/app/oip-drugs/utils/q-hasRatings.ts +43 -0
- package/layer/app/oip-drugs/utils/s-openCard.ts +20 -0
- package/layer/app/oip-drugs/utils/sourceUuids.ts +155 -0
- package/layer/app/oip-drugs/utils/styleAndFormat.ts +40 -0
- package/layer/app/oip-drugs/utils/v-salesSeries.ts +156 -0
- package/layer/app/oip-drugs/utils/v-scopeTags.ts +23 -0
- package/layer/app/oip-science/PORTING.md +93 -0
- package/layer/app/oip-science/assets/smartSelection.json +428 -0
- package/layer/app/oip-science/composables/useAuthorMatching.ts +342 -0
- package/layer/app/oip-science/composables/useCTCenter.ts +107 -0
- package/layer/app/oip-science/composables/useCTInvestigators.ts +107 -0
- package/layer/app/oip-science/composables/useEstablishmentCrossData.ts +139 -0
- package/layer/app/oip-science/composables/useEstablishmentMatching.ts +176 -0
- package/layer/app/oip-science/composables/useEuct.ts +418 -0
- package/layer/app/oip-science/composables/useEuctCenter.ts +107 -0
- package/layer/app/oip-science/composables/useEuctInvestigators.ts +107 -0
- package/layer/app/oip-science/composables/useGlobalClinicalTrials.ts +624 -0
- package/layer/app/oip-science/composables/useLinkedTrials.ts +83 -0
- package/layer/app/oip-science/composables/useOipElastic.ts +658 -0
- package/layer/app/oip-science/composables/useOipSearchExplain.ts +166 -0
- package/layer/app/oip-science/composables/usePubmed.ts +487 -0
- package/layer/app/oip-science/composables/useSearchFields.ts +153 -0
- package/layer/app/oip-science/indexConfig.json +794 -0
- package/layer/app/oip-science/locales/en.json +483 -0
- package/layer/app/oip-science/locales/fr.json +483 -0
- package/layer/app/oip-science/science.css +1182 -0
- package/layer/app/oip-science/utils/a-openCard.ts +23 -0
- package/layer/app/oip-science/utils/b-openCard.ts +35 -0
- package/layer/app/oip-science/utils/c-filterContext.ts +81 -0
- package/layer/app/oip-science/utils/f-types.ts +241 -0
- package/layer/app/oip-science/utils/frDiseaseTerms.ts +269 -0
- package/layer/app/oip-science/utils/matchMethod.ts +53 -0
- package/layer/app/oip-science/utils/sliderTabs.ts +13 -0
- package/layer/app/oip-science/utils/sources.ts +15 -0
- package/layer/app/oip-science/utils/styleAndFormat.ts +608 -0
- package/layer/app/oip-science/utils/toPresets.ts +7 -0
- package/layer/app/oip-science/utils/valueTable.ts +126 -0
- package/layer/app/plugins/oip-science-i18n.ts +17 -0
- package/layer/app/utils/oipFicheRoutes.ts +118 -0
- package/layer/app/utils/oipResources.ts +440 -0
- package/layer/nuxt.config.ts +22 -2
- package/layer/public/reports/blincyto-has.html +292 -0
- package/layer/public/reports/blincyto-has.pdf +0 -0
- package/layer/public/reports/darzalex-has.html +279 -0
- package/layer/public/reports/darzalex-has.pdf +0 -0
- package/layer/public/reports/dupixent-has.html +217 -0
- package/layer/public/reports/dupixent-has.pdf +0 -0
- package/layer/public/reports/enhertu-has.html +283 -0
- package/layer/public/reports/enhertu-has.pdf +0 -0
- package/layer/public/reports/has-sein-2023.html +1639 -0
- package/layer/public/reports/ibrance-has.html +280 -0
- package/layer/public/reports/ibrance-has.pdf +0 -0
- package/layer/public/reports/imfinzi-has.html +297 -0
- package/layer/public/reports/imfinzi-has.pdf +0 -0
- package/layer/public/reports/keytruda-has.html +337 -0
- package/layer/public/reports/keytruda-has.pdf +0 -0
- package/layer/public/reports/kisqali-has.html +202 -0
- package/layer/public/reports/kisqali-has.pdf +0 -0
- package/layer/public/reports/opdivo-has.html +232 -0
- package/layer/public/reports/opdivo-has.pdf +0 -0
- package/layer/public/reports/ozempic-has.html +188 -0
- package/layer/public/reports/ozempic-has.pdf +0 -0
- package/layer/public/reports/tecentriq-has.html +315 -0
- package/layer/public/reports/tecentriq-has.pdf +0 -0
- package/layer/public/reports/yescarta-has.html +275 -0
- package/layer/public/reports/yescarta-has.pdf +0 -0
- package/layer/server/api/oip/es.post.ts +99 -0
- package/layer/server/api/oip/pdf.get.ts +70 -0
- package/layer/server/api/oip/reports.get.ts +98 -0
- package/layer/server/api/oip/resource-types.get.ts +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Filtre a valeurs d'une liste (anciennement ElasticFilter de France Augmented
|
|
3
|
+
Science). Ses valeurs et sa clause Elasticsearch vont dans le contexte de la
|
|
4
|
+
liste parente (c-filterContext), plus dans les stores par route de FAS.
|
|
5
|
+
-->
|
|
6
|
+
<template>
|
|
7
|
+
<div @click="lauchQuery">
|
|
8
|
+
<!---->
|
|
9
|
+
|
|
10
|
+
<RmComplexSelect
|
|
11
|
+
v-if="typeSelection == 'complex'"
|
|
12
|
+
select-all-count
|
|
13
|
+
:has-more="filtersData.length === sizeTarget"
|
|
14
|
+
:loading="isLoadingQuery"
|
|
15
|
+
:label="label || filterName"
|
|
16
|
+
:label-info="haveInfo"
|
|
17
|
+
v-model="selectedItem"
|
|
18
|
+
|
|
19
|
+
:options="filtersData"
|
|
20
|
+
:show-select-all="show_select_all"
|
|
21
|
+
@search="changeAddInputValue"
|
|
22
|
+
:presets="toPresets(isSmartSelection ? getSourceSmartSelection : null)"
|
|
23
|
+
:filter-search="
|
|
24
|
+
otherResearchField.length || otherResearchNestedField.length
|
|
25
|
+
? false
|
|
26
|
+
: true
|
|
27
|
+
" :lang="$i18n.locale === 'en' ? 'en' : 'fr'" />
|
|
28
|
+
|
|
29
|
+
<RmMultipleSelect
|
|
30
|
+
|
|
31
|
+
v-if="typeSelection == 'multiple'"
|
|
32
|
+
:loading="isLoadingQuery"
|
|
33
|
+
:label="label || filterName"
|
|
34
|
+
:label-info="haveInfo"
|
|
35
|
+
:search="false"
|
|
36
|
+
v-model="selectedItem"
|
|
37
|
+
:options="filtersData"
|
|
38
|
+
@search="changeAddInputValue"
|
|
39
|
+
:filter-search="
|
|
40
|
+
otherResearchField.length || otherResearchNestedField.length
|
|
41
|
+
? false
|
|
42
|
+
: true
|
|
43
|
+
" :lang="$i18n.locale === 'en' ? 'en' : 'fr'" />
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
<script setup lang="ts">
|
|
47
|
+
import smartSelection from "../../../oip-science/assets/smartSelection.json";
|
|
48
|
+
import useOipElastic from "../../../oip-science/composables/useOipElastic";
|
|
49
|
+
import { useOipFilterContext } from "../../../oip-science/utils/c-filterContext";
|
|
50
|
+
import { toPresets } from "../../../oip-science/utils/toPresets";
|
|
51
|
+
import { caseInsensitive, frDiseaseRegex } from "../../../oip-science/utils/frDiseaseTerms";
|
|
52
|
+
|
|
53
|
+
const filterContext = useOipFilterContext();
|
|
54
|
+
|
|
55
|
+
const { queryFilter, querySearchFilter } = useOipElastic();
|
|
56
|
+
|
|
57
|
+
const emit = defineEmits(["changeElement"]);
|
|
58
|
+
|
|
59
|
+
const props = defineProps({
|
|
60
|
+
filterValues: {
|
|
61
|
+
type: [Array, String, Function],
|
|
62
|
+
required: true,
|
|
63
|
+
},
|
|
64
|
+
field: {
|
|
65
|
+
type: String,
|
|
66
|
+
required: false,
|
|
67
|
+
default: null,
|
|
68
|
+
},
|
|
69
|
+
filterName: {
|
|
70
|
+
type: String,
|
|
71
|
+
required: true,
|
|
72
|
+
},
|
|
73
|
+
label: {
|
|
74
|
+
type: String,
|
|
75
|
+
default: null,
|
|
76
|
+
},
|
|
77
|
+
sizeTarget: {
|
|
78
|
+
type: Number,
|
|
79
|
+
required: false,
|
|
80
|
+
default: 50,
|
|
81
|
+
},
|
|
82
|
+
nestedField: {
|
|
83
|
+
type: String,
|
|
84
|
+
required: false,
|
|
85
|
+
default: null,
|
|
86
|
+
},
|
|
87
|
+
indexQuery: {
|
|
88
|
+
type: String,
|
|
89
|
+
required: true,
|
|
90
|
+
},
|
|
91
|
+
isSmartSelection: {
|
|
92
|
+
type: Boolean,
|
|
93
|
+
required: false,
|
|
94
|
+
default: false,
|
|
95
|
+
},
|
|
96
|
+
typeSelection: {
|
|
97
|
+
type: String,
|
|
98
|
+
required: false,
|
|
99
|
+
default: "complex",
|
|
100
|
+
},
|
|
101
|
+
matchQuery: {
|
|
102
|
+
type: Array,
|
|
103
|
+
required: false,
|
|
104
|
+
default: [],
|
|
105
|
+
},
|
|
106
|
+
keyName: {
|
|
107
|
+
type: String,
|
|
108
|
+
required: false,
|
|
109
|
+
default: null,
|
|
110
|
+
},
|
|
111
|
+
includeFields: {
|
|
112
|
+
type: Array,
|
|
113
|
+
required: false,
|
|
114
|
+
default: [],
|
|
115
|
+
},
|
|
116
|
+
excludeFields: {
|
|
117
|
+
type: Array,
|
|
118
|
+
required: false,
|
|
119
|
+
default: [],
|
|
120
|
+
},
|
|
121
|
+
cluster: {
|
|
122
|
+
type: String,
|
|
123
|
+
required: false,
|
|
124
|
+
default: null,
|
|
125
|
+
},
|
|
126
|
+
fuziness: {
|
|
127
|
+
type: String,
|
|
128
|
+
required: false,
|
|
129
|
+
default: "AUTO",
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
otherResearchField: {
|
|
133
|
+
type: [String, Array],
|
|
134
|
+
required: false,
|
|
135
|
+
default: [],
|
|
136
|
+
},
|
|
137
|
+
otherResearchNestedField: {
|
|
138
|
+
type: [String, Array],
|
|
139
|
+
required: false,
|
|
140
|
+
default: [],
|
|
141
|
+
},
|
|
142
|
+
// Filtres maladie/oncologie : la saisie francaise cherche aussi l'anglais (cf. frDiseaseRegex)
|
|
143
|
+
frDiseaseSearch: {
|
|
144
|
+
type: Boolean,
|
|
145
|
+
default: false,
|
|
146
|
+
},
|
|
147
|
+
// props ajouté pour avoir un point info dans le titre du filtre
|
|
148
|
+
haveInfo: {
|
|
149
|
+
type: Boolean,
|
|
150
|
+
default: false,
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
sourceSmartSelection: {
|
|
154
|
+
type: String,
|
|
155
|
+
required: false,
|
|
156
|
+
default: "Countries",
|
|
157
|
+
},
|
|
158
|
+
forceList: {
|
|
159
|
+
type: Boolean,
|
|
160
|
+
required: false,
|
|
161
|
+
default: false,
|
|
162
|
+
},
|
|
163
|
+
show_select_all: {
|
|
164
|
+
type: Boolean,
|
|
165
|
+
required: false,
|
|
166
|
+
default: true,
|
|
167
|
+
},
|
|
168
|
+
mustNot: {
|
|
169
|
+
type: Array,
|
|
170
|
+
required: false,
|
|
171
|
+
default: null,
|
|
172
|
+
},
|
|
173
|
+
// Stable, locale-independent key used to read/write filterStore entries.
|
|
174
|
+
// The page's `getStore('Sponsors')` lookup uses an English hard-coded key
|
|
175
|
+
// while `filterName` is `$t('common.sponsors')` = "Promoteurs" in French.
|
|
176
|
+
// Without `storeKey`, Filter.vue would write under "Promoteurs" and the
|
|
177
|
+
// parent would read under "Sponsors" → no match → saved scopes never
|
|
178
|
+
// restore. Pages should pass `storeKey="Sponsors"` matching their
|
|
179
|
+
// getStore call. Falls back to `filterName` when omitted.
|
|
180
|
+
storeKey: {
|
|
181
|
+
type: String,
|
|
182
|
+
required: false,
|
|
183
|
+
default: null,
|
|
184
|
+
},
|
|
185
|
+
// Pass true when the field is numeric/keyword-direct (no `.keyword` sub-field).
|
|
186
|
+
// Required for `long`/`integer`/`float` ES fields like PHRC.period.
|
|
187
|
+
noKeyword: {
|
|
188
|
+
type: Boolean,
|
|
189
|
+
required: false,
|
|
190
|
+
default: false,
|
|
191
|
+
},
|
|
192
|
+
// Index EUCT (champs sans nested) ; FAS le lisait dans la route (`/euct`).
|
|
193
|
+
euct: {
|
|
194
|
+
type: Boolean,
|
|
195
|
+
required: false,
|
|
196
|
+
default: false,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Returns the field path to use in queries / aggregations.
|
|
201
|
+
// When `noKeyword` is true, the raw field is used (numeric or already-keyword
|
|
202
|
+
// fields); otherwise `.keyword` is appended (text fields with a keyword sub-field).
|
|
203
|
+
const kw = (field: string) => (props.noKeyword ? field : `${field}.keyword`);
|
|
204
|
+
|
|
205
|
+
// Use `storeKey` when provided so reads (via the parent's `getStore(key)`)
|
|
206
|
+
// and writes (here) target the same filterStore entry regardless of the
|
|
207
|
+
// current locale. Otherwise fall back to `filterName` for back-compat.
|
|
208
|
+
const effectiveStoreKey = computed(
|
|
209
|
+
() => props.storeKey || props.filterName,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const search = ref("" as string);
|
|
213
|
+
const filtersData = ref([] as any);
|
|
214
|
+
const isLoadingQuery = ref(false);
|
|
215
|
+
|
|
216
|
+
const selectedItem = ref([] as any);
|
|
217
|
+
|
|
218
|
+
const timeoutId = ref(null as any);
|
|
219
|
+
|
|
220
|
+
const dynamicFuzzyThreshold = computed(() => {
|
|
221
|
+
const cleanInput = search.value.replace(/[+\/!]/g, "").trim();
|
|
222
|
+
// Pour les codes courts (≤ 6 caractères), threshold très permissif
|
|
223
|
+
if (cleanInput.length <= 6) {
|
|
224
|
+
return 0.9;
|
|
225
|
+
}
|
|
226
|
+
// Pour les recherches moyennes (7-10 caractères), threshold moyen
|
|
227
|
+
else if (cleanInput.length <= 10) {
|
|
228
|
+
return 0.7;
|
|
229
|
+
}
|
|
230
|
+
// Pour les recherches longues, threshold strict
|
|
231
|
+
else {
|
|
232
|
+
return 0.5;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Le pays de retour de FAS (layoutConfig.returnCountry) n'existe pas hors de l'app.
|
|
237
|
+
onMounted(() => {
|
|
238
|
+
selectedItem.value =
|
|
239
|
+
props.filterValues.length > 0 ? props.filterValues : [];
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const getSourceSmartSelection = computed(() => {
|
|
243
|
+
switch (props.sourceSmartSelection) {
|
|
244
|
+
case "Pubmed Journal Name":
|
|
245
|
+
return smartSelection.orphanetPubmedJournalSelection;
|
|
246
|
+
case "country_eu":
|
|
247
|
+
return smartSelection.countries_eu;
|
|
248
|
+
default:
|
|
249
|
+
return smartSelection.countries;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// Sync selectedItem when the parent passes a new `filterValues` prop —
|
|
254
|
+
// notably when a saved scope is recalled and the parent re-renders with
|
|
255
|
+
// the restored values. Without this watch, `selectedItem` is only read
|
|
256
|
+
// from the prop once in `onMounted`, so any later prop change is invisible
|
|
257
|
+
// and the UI stays empty even though the store has the recalled entries.
|
|
258
|
+
watch(
|
|
259
|
+
() => props.filterValues,
|
|
260
|
+
(newVal) => {
|
|
261
|
+
const target = Array.isArray(newVal) ? newVal : [];
|
|
262
|
+
// Skip no-op syncs (avoids feedback loops with the watch below).
|
|
263
|
+
if (JSON.stringify(selectedItem.value) === JSON.stringify(target)) return;
|
|
264
|
+
selectedItem.value = target;
|
|
265
|
+
},
|
|
266
|
+
{ deep: true },
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
watch(
|
|
270
|
+
() => selectedItem.value,
|
|
271
|
+
async (val, oldVal) => {
|
|
272
|
+
if (val.length > 0) {
|
|
273
|
+
filterContext.setAppFilters({
|
|
274
|
+
filter: effectiveStoreKey.value,
|
|
275
|
+
keyName: props.keyName,
|
|
276
|
+
values: val,
|
|
277
|
+
});
|
|
278
|
+
} else if (oldVal && oldVal.length > 0) {
|
|
279
|
+
// Only reset when going from a real selection to empty — i.e. the
|
|
280
|
+
// user actually cleared the filter. Skip the noisy 0→0 transitions
|
|
281
|
+
// that fire on mount because `selectedItem` is initialized to `[]`
|
|
282
|
+
// and then re-assigned to (a possibly-still-empty) `props.filterValues`.
|
|
283
|
+
// Without this guard, recalled scope entries get wiped by the watch
|
|
284
|
+
// before the prop has a chance to deliver the restored values.
|
|
285
|
+
filterContext.resetSelectedFilters({
|
|
286
|
+
filter: effectiveStoreKey.value,
|
|
287
|
+
keyName: props.keyName,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
setSearch(val);
|
|
292
|
+
}
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const changeAddInputValue = (val: string) => {
|
|
296
|
+
clearTimeout(timeoutId.value);
|
|
297
|
+
search.value = val;
|
|
298
|
+
timeoutId.value = setTimeout(() => {
|
|
299
|
+
lauchQuery();
|
|
300
|
+
}, 300);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const setSearch = async (search: any) => {
|
|
304
|
+
let obj = null;
|
|
305
|
+
|
|
306
|
+
if (search.length > 0 && props.field) {
|
|
307
|
+
obj = {
|
|
308
|
+
terms: {
|
|
309
|
+
[kw(props.field)]: search,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (search.length > 0 && props.nestedField) {
|
|
315
|
+
// Pour EUCT, pas de nested
|
|
316
|
+
if (props.euct) {
|
|
317
|
+
obj = {
|
|
318
|
+
terms: {
|
|
319
|
+
[`${props.nestedField}.keyword`]: search,
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
} else {
|
|
323
|
+
obj = {
|
|
324
|
+
nested: {
|
|
325
|
+
path: props.nestedField.split(".").slice(0, -1).join("."),
|
|
326
|
+
query: {
|
|
327
|
+
terms: {
|
|
328
|
+
[`${props.nestedField}.keyword`]: search,
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (obj != null) {
|
|
337
|
+
filterContext.setQueryFilters({
|
|
338
|
+
filter: props.filterName,
|
|
339
|
+
values: obj,
|
|
340
|
+
keyName: props.keyName,
|
|
341
|
+
});
|
|
342
|
+
} else {
|
|
343
|
+
filterContext.removeQueryFilter({
|
|
344
|
+
filter: props.filterName,
|
|
345
|
+
keyName: props.keyName,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const lauchQuery = async () => {
|
|
351
|
+
isLoadingQuery.value = true;
|
|
352
|
+
if (search.value != "") {
|
|
353
|
+
await lauchQueryWithSearch();
|
|
354
|
+
} else {
|
|
355
|
+
await launchQueryWithoutSearch();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
isLoadingQuery.value = false;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const aggregationsQuery = computed(() => {
|
|
362
|
+
let obj;
|
|
363
|
+
|
|
364
|
+
if (props.field) {
|
|
365
|
+
obj = {
|
|
366
|
+
[`${props.field}`]: {
|
|
367
|
+
terms: {
|
|
368
|
+
field: kw(props.field),
|
|
369
|
+
|
|
370
|
+
size: props.sizeTarget,
|
|
371
|
+
order: {
|
|
372
|
+
_key: "asc",
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
if (props.includeFields.length > 0) {
|
|
379
|
+
obj[`${props.field}`].terms.include = props.includeFields;
|
|
380
|
+
}
|
|
381
|
+
if (props.excludeFields.length > 0) {
|
|
382
|
+
obj[`${props.field}`].terms.exclude = props.excludeFields;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (props.nestedField) {
|
|
387
|
+
// Pour EUCT, pas de nested
|
|
388
|
+
if (props.euct) {
|
|
389
|
+
obj = {
|
|
390
|
+
[`${props.nestedField}`]: {
|
|
391
|
+
terms: {
|
|
392
|
+
field: `${props.nestedField}.keyword`,
|
|
393
|
+
size: props.sizeTarget,
|
|
394
|
+
order: {
|
|
395
|
+
_key: "asc",
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
} else {
|
|
401
|
+
obj = {
|
|
402
|
+
[`${props.nestedField.split(".")[0]}`]: {
|
|
403
|
+
nested: {
|
|
404
|
+
path: props.nestedField.split(".").slice(0, -1).join("."),
|
|
405
|
+
},
|
|
406
|
+
aggs: {
|
|
407
|
+
[`${props.nestedField}`]: {
|
|
408
|
+
terms: {
|
|
409
|
+
field: `${props.nestedField}.keyword`,
|
|
410
|
+
size: props.sizeTarget,
|
|
411
|
+
order: {
|
|
412
|
+
_key: "asc",
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (props.includeFields.length > 0) {
|
|
422
|
+
if (props.euct) {
|
|
423
|
+
obj[`${props.nestedField}`].terms.include = props.includeFields;
|
|
424
|
+
} else {
|
|
425
|
+
obj[`${props.nestedField.split(".").slice(0, -1).join(".")}`].aggs[
|
|
426
|
+
`${props.nestedField}`
|
|
427
|
+
].terms.include = props.includeFields;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (props.excludeFields.length > 0) {
|
|
431
|
+
if (props.euct) {
|
|
432
|
+
obj[`${props.nestedField}`].terms.exclude = props.excludeFields;
|
|
433
|
+
} else {
|
|
434
|
+
obj[`${props.nestedField.split(".").slice(0, -1).join(".")}`].aggs[
|
|
435
|
+
`${props.nestedField}`
|
|
436
|
+
].terms.exclude = props.excludeFields;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return obj;
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const aggregationsSearchQuery = computed(() => {
|
|
445
|
+
let obj;
|
|
446
|
+
|
|
447
|
+
// Normalise les codes médicaux en majuscules pour matcher les champs keyword
|
|
448
|
+
const normalizedQuery = search.value.replace(/\b(orpha|nct|icd|atc|ema|fda)([\w:-]*)/gi, (match: string, prefix: string, suffix: string) => {
|
|
449
|
+
return prefix.toUpperCase() + suffix.toUpperCase();
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Détecte si la valeur contient des wildcards
|
|
453
|
+
const hasWildcard = search.value.includes('*') || search.value.includes('?');
|
|
454
|
+
|
|
455
|
+
// Construit un pattern case-insensitive pour chaque caractère
|
|
456
|
+
const makeCaseInsensitive = (str: string) => {
|
|
457
|
+
return str.split('').map(char => {
|
|
458
|
+
if (/[a-zA-Z]/.test(char)) {
|
|
459
|
+
return `[${char.toLowerCase()}${char.toUpperCase()}]`;
|
|
460
|
+
}
|
|
461
|
+
// Échapper les caractères spéciaux regex
|
|
462
|
+
if (/[.*+?^${}()|[\]\\]/.test(char)) {
|
|
463
|
+
return `\\${char}`;
|
|
464
|
+
}
|
|
465
|
+
return char;
|
|
466
|
+
}).join('');
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
let includePattern = '';
|
|
470
|
+
|
|
471
|
+
if (hasWildcard) {
|
|
472
|
+
// Convertir les wildcards et rendre case-insensitive
|
|
473
|
+
const withWildcards = normalizedQuery.replace(/\*/g, '.*').replace(/\?/g, '.');
|
|
474
|
+
includePattern = makeCaseInsensitive(withWildcards);
|
|
475
|
+
} else {
|
|
476
|
+
// Chercher ce qui contient le terme (case insensitive)
|
|
477
|
+
includePattern = `.*${makeCaseInsensitive(normalizedQuery)}.*`;
|
|
478
|
+
}
|
|
479
|
+
if (frRegex.value) includePattern += `|.*(${caseInsensitive(frRegex.value)}).*`;
|
|
480
|
+
|
|
481
|
+
if (props.field) {
|
|
482
|
+
obj = [props.field, props.otherResearchField]
|
|
483
|
+
.flat()
|
|
484
|
+
.map((field) => {
|
|
485
|
+
return {
|
|
486
|
+
[`${field}`]: {
|
|
487
|
+
terms: {
|
|
488
|
+
field: kw(field as string),
|
|
489
|
+
size: props.sizeTarget,
|
|
490
|
+
include: includePattern,
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
})
|
|
495
|
+
.reduce((acc, curr) => Object.assign(acc, curr), {});
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (props.nestedField) {
|
|
499
|
+
obj = [props.nestedField, props.otherResearchNestedField]
|
|
500
|
+
.flat()
|
|
501
|
+
.map((field) => {
|
|
502
|
+
return {
|
|
503
|
+
[`${field}`]: {
|
|
504
|
+
nested: {
|
|
505
|
+
// @ts-ignore
|
|
506
|
+
path: field.split(".").slice(0, -1).join("."),
|
|
507
|
+
},
|
|
508
|
+
aggs: {
|
|
509
|
+
[`${field}`]: {
|
|
510
|
+
terms: {
|
|
511
|
+
field: `${field}.keyword`,
|
|
512
|
+
// Sans size, ES retombe sur 10 buckets triés par doc count :
|
|
513
|
+
// un code exact peu représenté (ex: ORPHA:18) sort du top 10
|
|
514
|
+
// et disparaît. On récupère un superset, trié côté client.
|
|
515
|
+
size: 1000,
|
|
516
|
+
include: includePattern,
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
})
|
|
523
|
+
.reduce((acc, curr) => Object.assign(acc, curr), {});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return obj;
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// La saisie francaise traduite en anglais, null hors filtres maladie ou sans traduction.
|
|
530
|
+
const frRegex = computed(() => (props.frDiseaseSearch ? frDiseaseRegex(search.value) : null));
|
|
531
|
+
|
|
532
|
+
const searchQuery = computed(() => {
|
|
533
|
+
let query;
|
|
534
|
+
|
|
535
|
+
// Détecte si la requête contient des codes courts (ORPHA:, NCT, ICD, etc.)
|
|
536
|
+
const hasShortCodes = /\b(ORPHA|NCT|ICD|ATC|EMA|FDA)[\w:-]{1,10}\b/i.test(search.value);
|
|
537
|
+
|
|
538
|
+
// Détecte si ce sont des termes très courts (≤3 caractères)
|
|
539
|
+
const hasVeryShortTerms = search.value.split(/\s+/).some((term: string) =>
|
|
540
|
+
term.replace(/[^\w]/g, '').length <= 3 && term.replace(/[^\w]/g, '').length > 0
|
|
541
|
+
);
|
|
542
|
+
|
|
543
|
+
// Normalise les codes médicaux en majuscules pour matcher les champs keyword
|
|
544
|
+
const normalizedQuery = search.value.replace(/\b(orpha|nct|icd|atc|ema|fda)([\w:-]*)/gi, (match: string, prefix: string, suffix: string) => {
|
|
545
|
+
return prefix.toUpperCase() + suffix.toUpperCase();
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
// Ajuste la fuzzyness et phrase_slop selon le contexte
|
|
549
|
+
const adaptiveFuzziness = hasShortCodes || hasVeryShortTerms ? "0" : props.fuziness;
|
|
550
|
+
const adaptivePhraseSlop = hasShortCodes ? 0 : 2;
|
|
551
|
+
|
|
552
|
+
// Détecte si la valeur contient des wildcards
|
|
553
|
+
const hasWildcard = search.value.includes('*') || search.value.includes('?');
|
|
554
|
+
|
|
555
|
+
if (props.field) {
|
|
556
|
+
query = {
|
|
557
|
+
bool: {
|
|
558
|
+
should: [
|
|
559
|
+
...[props.field, props.otherResearchField].flat().map((field) => ({
|
|
560
|
+
bool: {
|
|
561
|
+
should: [
|
|
562
|
+
// Regexp pour recherche partielle (contient)
|
|
563
|
+
{
|
|
564
|
+
regexp: {
|
|
565
|
+
[`${field}.keyword`]: {
|
|
566
|
+
value: `.*${normalizedQuery}.*${frRegex.value ? `|.*(${frRegex.value}).*` : ''}`,
|
|
567
|
+
flags: "ALL",
|
|
568
|
+
case_insensitive: true,
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
// Wildcard pour recherche préfixe (commence par)
|
|
573
|
+
{
|
|
574
|
+
wildcard: {
|
|
575
|
+
[`${field}.keyword`]: {
|
|
576
|
+
value: hasWildcard ? normalizedQuery.toLowerCase() : `${normalizedQuery.toLowerCase()}*`,
|
|
577
|
+
case_insensitive: true,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
},
|
|
583
|
+
})),
|
|
584
|
+
],
|
|
585
|
+
},
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
if (props.nestedField) {
|
|
589
|
+
query = {
|
|
590
|
+
bool: {
|
|
591
|
+
should: [
|
|
592
|
+
...[props.nestedField, props.otherResearchNestedField]
|
|
593
|
+
.flat()
|
|
594
|
+
.map((field) => ({
|
|
595
|
+
nested: {
|
|
596
|
+
path: (field as string).split(".").slice(0, -1).join("."),
|
|
597
|
+
query: {
|
|
598
|
+
bool: {
|
|
599
|
+
should: [
|
|
600
|
+
// Regexp pour recherche partielle (contient)
|
|
601
|
+
{
|
|
602
|
+
regexp: {
|
|
603
|
+
[`${field}.keyword`]: {
|
|
604
|
+
value: `.*${normalizedQuery}.*${frRegex.value ? `|.*(${frRegex.value}).*` : ''}`,
|
|
605
|
+
flags: "ALL",
|
|
606
|
+
case_insensitive: true,
|
|
607
|
+
},
|
|
608
|
+
},
|
|
609
|
+
},
|
|
610
|
+
// Wildcard pour recherche préfixe (commence par)
|
|
611
|
+
{
|
|
612
|
+
wildcard: {
|
|
613
|
+
[`${field}.keyword`]: {
|
|
614
|
+
value: hasWildcard ? normalizedQuery.toLowerCase() : `${normalizedQuery.toLowerCase()}*`,
|
|
615
|
+
case_insensitive: true,
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
},
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
})),
|
|
624
|
+
],
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
return query;
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
const filtersWithoutSearch = computed(() => {
|
|
632
|
+
return {
|
|
633
|
+
name: props.filterName,
|
|
634
|
+
agg: aggregationsQuery.value,
|
|
635
|
+
path: props.field ? props.field : props.nestedField,
|
|
636
|
+
values: selectedItem.value,
|
|
637
|
+
isNested: props.nestedField,
|
|
638
|
+
};
|
|
639
|
+
});
|
|
640
|
+
const filtersWitSearch = computed(() => {
|
|
641
|
+
return {
|
|
642
|
+
agg: aggregationsSearchQuery.value,
|
|
643
|
+
path: props.field ? props.field : props.nestedField,
|
|
644
|
+
isNested: props.nestedField ? true : false,
|
|
645
|
+
searchQuery: searchQuery.value,
|
|
646
|
+
};
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
const launchQueryWithoutSearch = async () => {
|
|
650
|
+
await queryFilter({
|
|
651
|
+
index: props.indexQuery,
|
|
652
|
+
filters: filtersWithoutSearch.value,
|
|
653
|
+
take: props.sizeTarget,
|
|
654
|
+
customQuery: props.matchQuery,
|
|
655
|
+
cluster: props.cluster,
|
|
656
|
+
mustNot: props.mustNot,
|
|
657
|
+
}).then((data) => {
|
|
658
|
+
filtersData.value = data;
|
|
659
|
+
});
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// Trie les résultats par pertinence vis-à-vis de la recherche : ES renvoie les
|
|
663
|
+
// buckets par doc count, donc un match exact (ex: ORPHA:18) n'est jamais premier.
|
|
664
|
+
// Ordre : code orpha exact > préfixe de code > préfixe de nom > contient > reste.
|
|
665
|
+
const sortByRelevance = (results: any): string[] => {
|
|
666
|
+
const raw = search.value.trim();
|
|
667
|
+
if (!raw || !Array.isArray(results)) return results;
|
|
668
|
+
const q = raw.toLowerCase();
|
|
669
|
+
const codeQueryMatch = raw.match(/^(?:orpha:?\s*)?(\d+)$/i);
|
|
670
|
+
const qCode = codeQueryMatch ? codeQueryMatch[1] : null;
|
|
671
|
+
|
|
672
|
+
const codeOf = (item: string) => (item.match(/orpha:\s*(\d+)/i) || [])[1];
|
|
673
|
+
|
|
674
|
+
const score = (item: string) => {
|
|
675
|
+
const lower = item.toLowerCase();
|
|
676
|
+
const code = codeOf(item);
|
|
677
|
+
if (qCode && code) {
|
|
678
|
+
if (code === qCode) return 0;
|
|
679
|
+
if (code.startsWith(qCode)) return 1;
|
|
680
|
+
}
|
|
681
|
+
if (lower.startsWith(q)) return 2;
|
|
682
|
+
if (lower.includes(q)) return 3;
|
|
683
|
+
return 4;
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
return [...results].sort((a, b) => {
|
|
687
|
+
const diff = score(a) - score(b);
|
|
688
|
+
if (diff !== 0) return diff;
|
|
689
|
+
const ca = codeOf(a);
|
|
690
|
+
const cb = codeOf(b);
|
|
691
|
+
// À score égal, code le plus court d'abord (ORPHA:18 avant ORPHA:180)
|
|
692
|
+
if (ca && cb && ca.length !== cb.length) return ca.length - cb.length;
|
|
693
|
+
return a.localeCompare(b);
|
|
694
|
+
});
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
const lauchQueryWithSearch = async () => {
|
|
698
|
+
// await querySearchFilter({
|
|
699
|
+
// index: props.indexQuery,
|
|
700
|
+
// filters: filtersWitSearch.value,
|
|
701
|
+
// take: props.sizeTarget,
|
|
702
|
+
// customQuery: props.matchQuery,
|
|
703
|
+
// cluster: props.cluster,
|
|
704
|
+
// }).then((data) => {
|
|
705
|
+
// filtersData.value = data;
|
|
706
|
+
// });
|
|
707
|
+
|
|
708
|
+
await querySearchFilter({
|
|
709
|
+
index: props.indexQuery,
|
|
710
|
+
filters: filtersWitSearch.value,
|
|
711
|
+
take: props.sizeTarget,
|
|
712
|
+
customQuery: [],
|
|
713
|
+
cluster: props.cluster,
|
|
714
|
+
mustNot: props.mustNot,
|
|
715
|
+
}).then((data) => {
|
|
716
|
+
filtersData.value = sortByRelevance(data).slice(0, props.sizeTarget);
|
|
717
|
+
});
|
|
718
|
+
};
|
|
719
|
+
</script>
|