@tekkare/romulus 0.1.251 → 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/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,461 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Un pays du regard international : ses prix publies, puis ses decisions.
|
|
3
|
+
|
|
4
|
+
La carte reprend la lecture de l'onglet Prix France : le prix d'abord, en
|
|
5
|
+
cartes de presentation, puis la liste des decisions en tableau. Elle ne
|
|
6
|
+
calcule rien : la page lui donne des lignes de prix deja converties et des
|
|
7
|
+
decisions deja normalisees, elle les met en page et signale ce qu'on ouvre.
|
|
8
|
+
-->
|
|
9
|
+
<script setup lang="ts">
|
|
10
|
+
import type { HeartIntlPriceRow } from "../../../../../oip-drugs/utils/heartIntlPrice";
|
|
11
|
+
import type { HeartIntlRecord } from "../../../../../oip-drugs/composables/useHeartIntlApprovals";
|
|
12
|
+
|
|
13
|
+
const props = defineProps<{
|
|
14
|
+
/** Code ISO du pays (ou « EU » pour l'Union europeenne). */
|
|
15
|
+
iso: string;
|
|
16
|
+
/** Nom du pays, dans la langue lue. */
|
|
17
|
+
label: string;
|
|
18
|
+
/** L'agence dont viennent les decisions : EMA, G-BA, AIFA... */
|
|
19
|
+
agency: string;
|
|
20
|
+
/** Les presentations tarifees du pays. Vide pour l'Union europeenne. */
|
|
21
|
+
prices: HeartIntlPriceRow[];
|
|
22
|
+
/** Les decisions du registre, deja normalisees. */
|
|
23
|
+
records: HeartIntlRecord[];
|
|
24
|
+
/** Fiche Directus du referentiel de prix du pays. */
|
|
25
|
+
priceSource?: string | null;
|
|
26
|
+
/** Fiche Directus du registre d'autorisation du pays. */
|
|
27
|
+
approvalSource?: string | null;
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
}>();
|
|
30
|
+
|
|
31
|
+
const emit = defineEmits<{
|
|
32
|
+
(event: "select-price", row: HeartIntlPriceRow): void;
|
|
33
|
+
(event: "select-record", record: HeartIntlRecord): void;
|
|
34
|
+
}>();
|
|
35
|
+
|
|
36
|
+
const { locale } = useI18n();
|
|
37
|
+
const en = computed(() => locale.value === "en");
|
|
38
|
+
|
|
39
|
+
const money = (value: number | null | undefined, currency = "EUR") =>
|
|
40
|
+
typeof value === "number"
|
|
41
|
+
? `${Math.round(value).toLocaleString("fr-FR")} ${currency === "EUR" ? "€" : currency}`
|
|
42
|
+
: "-";
|
|
43
|
+
|
|
44
|
+
const percent = (value: number | null | undefined) =>
|
|
45
|
+
typeof value === "number"
|
|
46
|
+
? `${value > 0 ? "+" : ""}${value.toLocaleString("fr-FR", { maximumFractionDigits: 1 })} %`
|
|
47
|
+
: "";
|
|
48
|
+
|
|
49
|
+
/** La derniere date connue du pays, prix et decisions confondus. */
|
|
50
|
+
const lastUpdate = computed(() => {
|
|
51
|
+
const dates = [
|
|
52
|
+
...props.prices.map((row) => row.date),
|
|
53
|
+
...props.records.map((record) => record.date),
|
|
54
|
+
]
|
|
55
|
+
.filter(Boolean)
|
|
56
|
+
.sort((a: any, b: any) => new Date(b).getTime() - new Date(a).getTime());
|
|
57
|
+
return dates[0] ?? null;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/** Tous les registres ne rendent pas un verdict : l'AIFA classe, le G-BA juge. */
|
|
61
|
+
const hasOutcome = computed(() => props.records.some((record) => record.status));
|
|
62
|
+
|
|
63
|
+
/** La date du dernier tarif du pays, citee par sa source. */
|
|
64
|
+
const lastPriceDates = computed(() => props.prices.map((row) => row.date));
|
|
65
|
+
|
|
66
|
+
const columns = computed(() => [
|
|
67
|
+
{ key: "date", label: "Date", minWidth: "110px", rowHeader: true },
|
|
68
|
+
{ key: "typeLabel", label: en.value ? "Type" : "Nature", minWidth: "150px" },
|
|
69
|
+
{ key: "title", label: en.value ? "Subject" : "Objet", minWidth: "260px" },
|
|
70
|
+
...(hasOutcome.value
|
|
71
|
+
? [{ key: "status", label: en.value ? "Outcome" : "Résultat", minWidth: "130px" }]
|
|
72
|
+
: []),
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
/** La teinte de l'etiquette de resultat. Romulus n'a pas de rouge : rose. */
|
|
76
|
+
const tone = (record: HeartIntlRecord) =>
|
|
77
|
+
record.statusTone === "good" ? "green" : record.statusTone === "bad" ? "rose" : "gray";
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<template>
|
|
81
|
+
<article class="ic">
|
|
82
|
+
<header class="ic_head">
|
|
83
|
+
<RmFlag :code="iso" :height="18" :title="label" />
|
|
84
|
+
<h3 class="ic_country">{{ label }}</h3>
|
|
85
|
+
<RmTag variant="gray">{{ agency }}</RmTag>
|
|
86
|
+
<span class="ic_counts">
|
|
87
|
+
<template v-if="prices.length">
|
|
88
|
+
{{ prices.length }}
|
|
89
|
+
{{ en ? (prices.length > 1 ? "presentations" : "presentation") : "présentation" + (prices.length > 1 ? "s" : "") }}
|
|
90
|
+
</template>
|
|
91
|
+
<template v-if="prices.length && records.length"> · </template>
|
|
92
|
+
<template v-if="records.length">
|
|
93
|
+
{{ records.length }}
|
|
94
|
+
{{ en ? (records.length > 1 ? "decisions" : "decision") : "décision" + (records.length > 1 ? "s" : "") }}
|
|
95
|
+
</template>
|
|
96
|
+
</span>
|
|
97
|
+
<span v-if="lastUpdate" class="ic_last">
|
|
98
|
+
<RmIcon name="Calendar" :size="14" />
|
|
99
|
+
<RmDate :date="lastUpdate" :lang="en ? 'en' : 'fr'" compact />
|
|
100
|
+
</span>
|
|
101
|
+
</header>
|
|
102
|
+
|
|
103
|
+
<!-- Bandeau prix : une carte par presentation tarifee, le prix en grand. -->
|
|
104
|
+
<section v-if="prices.length" class="ic_band">
|
|
105
|
+
<p class="ic_band_title">
|
|
106
|
+
{{ en ? "Published prices" : "Prix publiés" }}
|
|
107
|
+
<span class="ic_band_sub">
|
|
108
|
+
{{
|
|
109
|
+
en
|
|
110
|
+
? "latest applicable price, converted to euros"
|
|
111
|
+
: "dernier prix applicable, converti en euros"
|
|
112
|
+
}}
|
|
113
|
+
</span>
|
|
114
|
+
</p>
|
|
115
|
+
|
|
116
|
+
<!-- Une marque peut porter vingt presentations dans un pays : le bandeau
|
|
117
|
+
defile horizontalement plutot que d'empiler des rangees ou de cacher
|
|
118
|
+
le reste derriere un bouton. -->
|
|
119
|
+
<div
|
|
120
|
+
class="ic_scroller"
|
|
121
|
+
tabindex="0"
|
|
122
|
+
role="group"
|
|
123
|
+
:aria-label="en ? `Published prices in ${label}` : `Prix publiés en ${label}`"
|
|
124
|
+
>
|
|
125
|
+
<button
|
|
126
|
+
v-for="row in prices"
|
|
127
|
+
:key="row.key"
|
|
128
|
+
type="button"
|
|
129
|
+
class="ic_price_card"
|
|
130
|
+
@click="emit('select-price', row)"
|
|
131
|
+
>
|
|
132
|
+
<span class="ic_price_head">
|
|
133
|
+
<span class="ic_price_name">{{ row.product }}</span>
|
|
134
|
+
<RmTag v-if="row.category" variant="gray">{{ row.category }}</RmTag>
|
|
135
|
+
</span>
|
|
136
|
+
|
|
137
|
+
<span v-if="row.date" class="ic_price_date">
|
|
138
|
+
<RmIcon name="Calendar" :size="13" />
|
|
139
|
+
{{ en ? "Price of" : "Tarif au" }}
|
|
140
|
+
<RmDate :date="row.date" :lang="en ? 'en' : 'fr'" compact />
|
|
141
|
+
</span>
|
|
142
|
+
|
|
143
|
+
<span class="ic_price_value">
|
|
144
|
+
{{ money(row.priceEur) }}
|
|
145
|
+
<span class="ic_price_type">{{ row.typeLabel }}</span>
|
|
146
|
+
</span>
|
|
147
|
+
|
|
148
|
+
<span class="ic_price_fields">
|
|
149
|
+
<span class="ic_field">
|
|
150
|
+
<span class="ic_field_label">{{ en ? "Local price" : "Prix local" }}</span>
|
|
151
|
+
<span class="ic_field_value">{{ money(row.priceLocal, row.currency) }}</span>
|
|
152
|
+
</span>
|
|
153
|
+
<span v-if="row.variation" class="ic_field">
|
|
154
|
+
<span class="ic_field_label">{{ en ? "Last change" : "Dernière variation" }}</span>
|
|
155
|
+
<span class="ic_field_value" :class="row.variation < 0 ? 'is_down' : 'is_up'">
|
|
156
|
+
<RmIcon :name="row.variation < 0 ? 'TrendDown' : 'TrendUp'" :size="13" />
|
|
157
|
+
{{ money(row.variation, row.currency) }}
|
|
158
|
+
<template v-if="row.variationPct !== null">({{ percent(row.variationPct) }})</template>
|
|
159
|
+
</span>
|
|
160
|
+
</span>
|
|
161
|
+
<span v-if="row.manufacturer" class="ic_field">
|
|
162
|
+
<span class="ic_field_label">{{ en ? "Manufacturer" : "Fabricant" }}</span>
|
|
163
|
+
<span class="ic_field_value">{{ row.manufacturer }}</span>
|
|
164
|
+
</span>
|
|
165
|
+
<span v-if="row.localId" class="ic_field">
|
|
166
|
+
<span class="ic_field_label">{{ en ? "Local code" : "Code local" }}</span>
|
|
167
|
+
<span class="ic_field_value ic_mono">{{ row.localId }}</span>
|
|
168
|
+
</span>
|
|
169
|
+
</span>
|
|
170
|
+
</button>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
</section>
|
|
174
|
+
|
|
175
|
+
<!-- Decisions du registre : indications, avis, autorisations. -->
|
|
176
|
+
<section class="ic_records">
|
|
177
|
+
<p class="ic_band_title">
|
|
178
|
+
{{ en ? "Indications and decisions" : "Indications et décisions" }}
|
|
179
|
+
<span class="ic_band_sub">{{ agency }}</span>
|
|
180
|
+
</p>
|
|
181
|
+
|
|
182
|
+
<RmTable
|
|
183
|
+
v-if="records.length"
|
|
184
|
+
:columns="columns"
|
|
185
|
+
:rows="records"
|
|
186
|
+
row-key="key"
|
|
187
|
+
compact
|
|
188
|
+
flat
|
|
189
|
+
:page-size="5"
|
|
190
|
+
max-height="auto"
|
|
191
|
+
:caption="`${label} · ${agency}`"
|
|
192
|
+
:empty-text="en ? 'No decision' : 'Aucune décision'"
|
|
193
|
+
@row-click="(row: any) => emit('select-record', row as HeartIntlRecord)"
|
|
194
|
+
>
|
|
195
|
+
<template #date="{ row }">
|
|
196
|
+
<RmDate v-if="row.date" :date="row.date" :lang="en ? 'en' : 'fr'" compact />
|
|
197
|
+
<span v-else>-</span>
|
|
198
|
+
</template>
|
|
199
|
+
|
|
200
|
+
<template #typeLabel="{ row }">
|
|
201
|
+
<span class="ic_type">
|
|
202
|
+
<RmIcon :name="row.icon" :size="14" />
|
|
203
|
+
{{ row.typeLabel }}
|
|
204
|
+
</span>
|
|
205
|
+
<span v-if="row.badge" class="ic_ref">{{ row.badge }}</span>
|
|
206
|
+
</template>
|
|
207
|
+
|
|
208
|
+
<template #title="{ row }">
|
|
209
|
+
<span class="ic_record_title">{{ row.title }}</span>
|
|
210
|
+
<span v-if="row.excerpt" class="ic_record_excerpt">{{ row.excerpt }}</span>
|
|
211
|
+
</template>
|
|
212
|
+
|
|
213
|
+
<template #status="{ row }">
|
|
214
|
+
<RmTag v-if="row.status" :variant="tone(row as HeartIntlRecord)">{{ row.status }}</RmTag>
|
|
215
|
+
<span v-else>-</span>
|
|
216
|
+
</template>
|
|
217
|
+
</RmTable>
|
|
218
|
+
|
|
219
|
+
<p v-else-if="loading" class="ic_empty">
|
|
220
|
+
{{ en ? "Loading decisions…" : "Chargement des décisions…" }}
|
|
221
|
+
</p>
|
|
222
|
+
<p v-else class="ic_empty">
|
|
223
|
+
{{ en ? `No decision published by ${agency}.` : `Aucune décision publiée par ${agency}.` }}
|
|
224
|
+
</p>
|
|
225
|
+
</section>
|
|
226
|
+
|
|
227
|
+
<!-- Sources du pays, en pied de carte comme sur les autres pages. -->
|
|
228
|
+
<footer v-if="priceSource || approvalSource" class="ic_sources">
|
|
229
|
+
<oip-drugs-heart-elastic-source-container-elastic
|
|
230
|
+
v-if="priceSource"
|
|
231
|
+
:uuid="priceSource"
|
|
232
|
+
prefer-nickname
|
|
233
|
+
:kind="approvalSource ? (en ? 'Price source' : 'Source prix') : undefined"
|
|
234
|
+
:last-label="$t('oipDrugs.heart.sources.lastPrice')"
|
|
235
|
+
:last-date="lastPriceDates"
|
|
236
|
+
/>
|
|
237
|
+
<oip-drugs-heart-elastic-source-container-elastic
|
|
238
|
+
v-if="approvalSource"
|
|
239
|
+
:uuid="approvalSource"
|
|
240
|
+
prefer-nickname
|
|
241
|
+
:kind="en ? 'Approvals source' : 'Source décisions'"
|
|
242
|
+
/>
|
|
243
|
+
</footer>
|
|
244
|
+
</article>
|
|
245
|
+
</template>
|
|
246
|
+
|
|
247
|
+
<style scoped>
|
|
248
|
+
.ic {
|
|
249
|
+
display: flex;
|
|
250
|
+
flex-direction: column;
|
|
251
|
+
gap: 16px;
|
|
252
|
+
width: 100%;
|
|
253
|
+
background: var(--white);
|
|
254
|
+
border: 1px solid var(--light, #ececf2);
|
|
255
|
+
border-radius: 14px;
|
|
256
|
+
padding: 20px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ic_head {
|
|
260
|
+
display: flex;
|
|
261
|
+
align-items: center;
|
|
262
|
+
flex-wrap: wrap;
|
|
263
|
+
gap: 10px;
|
|
264
|
+
padding-bottom: 12px;
|
|
265
|
+
border-bottom: 1px solid var(--light, #ececf2);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.ic_country {
|
|
269
|
+
font-size: 16px;
|
|
270
|
+
font-weight: 700;
|
|
271
|
+
color: var(--darkest);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.ic_counts,
|
|
275
|
+
.ic_last {
|
|
276
|
+
font-size: 12px;
|
|
277
|
+
color: var(--medium);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.ic_last {
|
|
281
|
+
display: inline-flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
gap: 4px;
|
|
284
|
+
margin-left: auto;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.ic_band_title {
|
|
288
|
+
display: flex;
|
|
289
|
+
align-items: baseline;
|
|
290
|
+
gap: 8px;
|
|
291
|
+
font-size: 13px;
|
|
292
|
+
font-weight: 700;
|
|
293
|
+
color: var(--darkest);
|
|
294
|
+
margin-bottom: 10px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.ic_band_sub {
|
|
298
|
+
font-size: 11px;
|
|
299
|
+
font-weight: 500;
|
|
300
|
+
color: var(--medium);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.ic_scroller {
|
|
304
|
+
display: flex;
|
|
305
|
+
gap: 12px;
|
|
306
|
+
overflow-x: auto;
|
|
307
|
+
padding-bottom: 6px;
|
|
308
|
+
scroll-snap-type: x proximity;
|
|
309
|
+
scrollbar-width: thin;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.ic_scroller:focus-visible {
|
|
313
|
+
outline: 2px solid var(--primary);
|
|
314
|
+
outline-offset: 2px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.ic_price_card {
|
|
318
|
+
flex: 0 0 260px;
|
|
319
|
+
scroll-snap-align: start;
|
|
320
|
+
display: flex;
|
|
321
|
+
flex-direction: column;
|
|
322
|
+
gap: 8px;
|
|
323
|
+
text-align: left;
|
|
324
|
+
font-family: inherit;
|
|
325
|
+
background: var(--lightest, #f7f7fb);
|
|
326
|
+
border: 1px solid var(--light, #ececf2);
|
|
327
|
+
border-radius: 12px;
|
|
328
|
+
padding: 14px;
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
transition: border-color 0.15s, box-shadow 0.15s;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.ic_price_card:hover {
|
|
334
|
+
border-color: var(--primary);
|
|
335
|
+
box-shadow: 0 2px 10px rgb(0 0 0 / 6%);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.ic_price_head {
|
|
339
|
+
display: flex;
|
|
340
|
+
align-items: flex-start;
|
|
341
|
+
justify-content: space-between;
|
|
342
|
+
gap: 8px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.ic_price_name {
|
|
346
|
+
font-size: 12px;
|
|
347
|
+
font-weight: 700;
|
|
348
|
+
color: var(--darkest);
|
|
349
|
+
line-height: 1.3;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.ic_price_date {
|
|
353
|
+
display: inline-flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
gap: 4px;
|
|
356
|
+
font-size: 11px;
|
|
357
|
+
color: var(--medium);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.ic_price_value {
|
|
361
|
+
display: flex;
|
|
362
|
+
align-items: baseline;
|
|
363
|
+
gap: 8px;
|
|
364
|
+
font-family: var(--font-serif, inherit);
|
|
365
|
+
font-size: 24px;
|
|
366
|
+
font-weight: 700;
|
|
367
|
+
color: var(--primary);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.ic_price_type {
|
|
371
|
+
font-family: inherit;
|
|
372
|
+
font-size: 11px;
|
|
373
|
+
font-weight: 600;
|
|
374
|
+
color: var(--medium);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.ic_price_fields {
|
|
378
|
+
display: grid;
|
|
379
|
+
grid-template-columns: 1fr 1fr;
|
|
380
|
+
gap: 8px 12px;
|
|
381
|
+
padding-top: 8px;
|
|
382
|
+
border-top: 1px solid var(--light, #ececf2);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.ic_field {
|
|
386
|
+
display: flex;
|
|
387
|
+
flex-direction: column;
|
|
388
|
+
gap: 2px;
|
|
389
|
+
min-width: 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.ic_field_label {
|
|
393
|
+
font-size: 10px;
|
|
394
|
+
font-weight: 600;
|
|
395
|
+
letter-spacing: 0.02em;
|
|
396
|
+
text-transform: uppercase;
|
|
397
|
+
color: var(--medium);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.ic_field_value {
|
|
401
|
+
display: inline-flex;
|
|
402
|
+
align-items: center;
|
|
403
|
+
gap: 4px;
|
|
404
|
+
font-size: 12px;
|
|
405
|
+
font-weight: 600;
|
|
406
|
+
color: var(--darkest);
|
|
407
|
+
overflow-wrap: anywhere;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.ic_field_value.is_down {
|
|
411
|
+
color: var(--success, #1a7f5a);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.ic_field_value.is_up {
|
|
415
|
+
color: var(--danger, #c0392b);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.ic_mono {
|
|
419
|
+
font-variant-numeric: tabular-nums;
|
|
420
|
+
font-weight: 500;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.ic_type {
|
|
424
|
+
display: inline-flex;
|
|
425
|
+
align-items: center;
|
|
426
|
+
gap: 6px;
|
|
427
|
+
white-space: nowrap;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.ic_ref {
|
|
431
|
+
display: block;
|
|
432
|
+
font-size: 10px;
|
|
433
|
+
color: var(--medium);
|
|
434
|
+
white-space: nowrap;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.ic_record_title {
|
|
438
|
+
display: block;
|
|
439
|
+
font-weight: 600;
|
|
440
|
+
color: var(--darkest);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.ic_record_excerpt {
|
|
444
|
+
display: block;
|
|
445
|
+
font-size: 11px;
|
|
446
|
+
color: var(--medium);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.ic_empty {
|
|
450
|
+
font-size: 12px;
|
|
451
|
+
color: var(--medium);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.ic_sources {
|
|
455
|
+
display: flex;
|
|
456
|
+
flex-direction: column;
|
|
457
|
+
gap: 4px;
|
|
458
|
+
padding-top: 12px;
|
|
459
|
+
border-top: 1px solid var(--light, #ececf2);
|
|
460
|
+
}
|
|
461
|
+
</style>
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Regard international sur une marque : une carte par pays.
|
|
3
|
+
|
|
4
|
+
Chaque carte porte ce que le pays publie sur le produit : ses prix d'abord
|
|
5
|
+
(suivi mondial `ope__ww_price_tracker__tekkare`, converti en euros), puis ses
|
|
6
|
+
decisions (AIFA, AEMPS, G-BA, MHRA, EMA, FDA). Ouvrir une presentation ou une
|
|
7
|
+
decision ouvre le meme tiroir que les autres onglets de la fiche.
|
|
8
|
+
|
|
9
|
+
Deux precautions valent pour toute la lecture :
|
|
10
|
+
|
|
11
|
+
- Les conditionnements ne sont pas harmonises d'un pays a l'autre (un flacon
|
|
12
|
+
ici, deux la, 50 mg ailleurs) : on compare des presentations, jamais des
|
|
13
|
+
pays entre eux.
|
|
14
|
+
- Chaque pays publie ses propres types de prix. Le prix montre suit un ordre
|
|
15
|
+
fixe (fabricant, grossiste, public...) pour porter la meme notion partout
|
|
16
|
+
ou elle existe.
|
|
17
|
+
-->
|
|
18
|
+
<script setup lang="ts">
|
|
19
|
+
import * as currencyModule from "../../../../../oip-drugs/composables/useCurrency";
|
|
20
|
+
import { HEART_INTL_PRICE_CURRENCY, heartIntlPriceRows } from "../../../../../oip-drugs/utils/heartIntlPrice";
|
|
21
|
+
import type { HeartIntlPriceRow } from "../../../../../oip-drugs/utils/heartIntlPrice";
|
|
22
|
+
import type { HeartIntlRecord } from "../../../../../oip-drugs/composables/useHeartIntlApprovals";
|
|
23
|
+
import { HEART_INTL_COUNTRIES } from "../../../../../oip-drugs/composables/useHeartIntlApprovals";
|
|
24
|
+
import { heartFormatDate } from "../../../../../oip-drugs/utils/heartStyleAndFormat";
|
|
25
|
+
|
|
26
|
+
const props = defineProps<{
|
|
27
|
+
/** Les documents du suivi mondial des prix pour la marque. */
|
|
28
|
+
docs: any[];
|
|
29
|
+
/** Les decisions des registres etrangers, par code pays. */
|
|
30
|
+
records: Record<string, HeartIntlRecord[]>;
|
|
31
|
+
/** Nom de la marque, pour la ligne de portee. */
|
|
32
|
+
brand?: string;
|
|
33
|
+
/** Les registres sont encore en vol. */
|
|
34
|
+
loading?: boolean;
|
|
35
|
+
}>();
|
|
36
|
+
|
|
37
|
+
const { locale } = useI18n();
|
|
38
|
+
const en = computed(() => locale.value === "en");
|
|
39
|
+
|
|
40
|
+
// Ex-CurrencyStore (lot P) : le composable charge lui-meme les taux, avec
|
|
41
|
+
// la meme API (`getCurrency(code)`). Export nomme ou par defaut, selon le
|
|
42
|
+
// portage du socle.
|
|
43
|
+
const useCurrency = ((currencyModule as any).useCurrency ?? (currencyModule as any).default) as () => any;
|
|
44
|
+
const currencyStore = useCurrency();
|
|
45
|
+
|
|
46
|
+
/** Taux de la devise locale vers l'euro, charge par useCurrency. */
|
|
47
|
+
function eurRate(iso: string) {
|
|
48
|
+
const code = HEART_INTL_PRICE_CURRENCY[iso];
|
|
49
|
+
if (!code || code === "EUR") return 1;
|
|
50
|
+
return currencyStore.getCurrency(code)?.eur_rate ?? null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const priceRows = computed(() => heartIntlPriceRows(props.docs ?? [], eurRate));
|
|
54
|
+
|
|
55
|
+
const pricesByCountry = computed(() => {
|
|
56
|
+
const groups: Record<string, HeartIntlPriceRow[]> = {};
|
|
57
|
+
for (const row of priceRows.value) {
|
|
58
|
+
(groups[row.iso] ??= []).push(row);
|
|
59
|
+
}
|
|
60
|
+
return groups;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/** Une carte par pays qui a quelque chose a dire. */
|
|
64
|
+
const countries = computed(() =>
|
|
65
|
+
HEART_INTL_COUNTRIES.map((country) => ({
|
|
66
|
+
iso: country.iso,
|
|
67
|
+
key: country.key,
|
|
68
|
+
agency: country.agency,
|
|
69
|
+
label: en.value ? country.en : country.fr,
|
|
70
|
+
prices: pricesByCountry.value[country.key] ?? [],
|
|
71
|
+
records: props.records?.[country.key] ?? [],
|
|
72
|
+
priceSource: country.priceSource,
|
|
73
|
+
approvalSource: country.approvalSource,
|
|
74
|
+
})).filter((country) => country.prices.length > 0 || country.records.length > 0),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const decisionCount = computed(() =>
|
|
78
|
+
countries.value.reduce((sum, country) => sum + country.records.length, 0),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const lastUpdate = computed(() => {
|
|
82
|
+
const dates = [
|
|
83
|
+
...priceRows.value.map((row) => row.date),
|
|
84
|
+
...countries.value.flatMap((country) => country.records.map((record) => record.date)),
|
|
85
|
+
]
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
.sort((a: any, b: any) => new Date(b).getTime() - new Date(a).getTime());
|
|
88
|
+
return dates[0] ?? null;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const kpis = computed(() => [
|
|
92
|
+
{
|
|
93
|
+
icon: "GlobeHemisphereWest",
|
|
94
|
+
value: countries.value.length,
|
|
95
|
+
legend: en.value ? "Countries covered" : "Pays couverts",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
icon: "Package",
|
|
99
|
+
value: priceRows.value.length,
|
|
100
|
+
legend: en.value ? "Priced presentations" : "Présentations tarifées",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
icon: "Stamp",
|
|
104
|
+
value: decisionCount.value,
|
|
105
|
+
legend: en.value ? "Decisions" : "Décisions",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
icon: "Calendar",
|
|
109
|
+
value: lastUpdate.value ? heartFormatDate(lastUpdate.value) : "-",
|
|
110
|
+
legend: en.value ? "Latest update" : "Dernière mise à jour",
|
|
111
|
+
},
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
/** La decision ouverte dans le tiroir des enregistrements. */
|
|
115
|
+
const drawerRecord = ref<HeartIntlRecord | null>(null);
|
|
116
|
+
|
|
117
|
+
function openRecord(record: HeartIntlRecord) {
|
|
118
|
+
drawerRecord.value = record;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** La presentation ouverte dans le tiroir des prix. */
|
|
122
|
+
const drawerPrice = ref<HeartIntlPriceRow | null>(null);
|
|
123
|
+
|
|
124
|
+
/** Son pays, nomme comme la carte le nomme. */
|
|
125
|
+
const drawerPriceCountry = computed(
|
|
126
|
+
() => countries.value.find((country) => country.key === drawerPrice.value?.iso)?.label,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
</script>
|
|
130
|
+
|
|
131
|
+
<template>
|
|
132
|
+
<section class="io">
|
|
133
|
+
<RmKpiBar :kpis="kpis" :loading="loading && countries.length === 0" />
|
|
134
|
+
|
|
135
|
+
<oip-drugs-heart-results-details-international-country-card
|
|
136
|
+
v-for="country in countries"
|
|
137
|
+
:key="country.key"
|
|
138
|
+
:iso="country.iso"
|
|
139
|
+
:label="country.label"
|
|
140
|
+
:agency="country.agency"
|
|
141
|
+
:prices="country.prices"
|
|
142
|
+
:records="country.records"
|
|
143
|
+
:price-source="country.priceSource"
|
|
144
|
+
:approval-source="country.approvalSource"
|
|
145
|
+
:loading="loading"
|
|
146
|
+
@select-price="drawerPrice = $event"
|
|
147
|
+
@select-record="openRecord"
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
<p v-if="!countries.length && !loading" class="io_none">
|
|
151
|
+
<RmIcon name="Info" :size="16" />
|
|
152
|
+
{{
|
|
153
|
+
en
|
|
154
|
+
? `Nothing published abroad for ${brand ?? ""} in the countries covered.`
|
|
155
|
+
: `Rien de publié à l'étranger pour ${brand ?? ""} dans les pays couverts.`
|
|
156
|
+
}}
|
|
157
|
+
</p>
|
|
158
|
+
|
|
159
|
+
<!-- Une decision s'ouvre dans le tiroir commun aux autres onglets. -->
|
|
160
|
+
<oip-drugs-heart-results-details-record-drawer
|
|
161
|
+
:record="drawerRecord"
|
|
162
|
+
:source-label="drawerRecord?.sourceLabel"
|
|
163
|
+
@close="drawerRecord = null"
|
|
164
|
+
/>
|
|
165
|
+
|
|
166
|
+
<!-- Une presentation a son propre tiroir : elle porte un historique de
|
|
167
|
+
prix, que les rubriques de texte du tiroir commun ne rendaient pas. -->
|
|
168
|
+
<oip-drugs-heart-results-details-international-price-drawer
|
|
169
|
+
:row="drawerPrice"
|
|
170
|
+
:country-label="drawerPriceCountry"
|
|
171
|
+
@close="drawerPrice = null"
|
|
172
|
+
/>
|
|
173
|
+
</section>
|
|
174
|
+
</template>
|
|
175
|
+
|
|
176
|
+
<style scoped>
|
|
177
|
+
.io {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 16px;
|
|
181
|
+
width: 100%;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.io_none {
|
|
185
|
+
display: flex;
|
|
186
|
+
align-items: center;
|
|
187
|
+
gap: 8px;
|
|
188
|
+
font-size: 13px;
|
|
189
|
+
color: var(--dark);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.io_none {
|
|
193
|
+
padding: 24px 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
</style>
|