diff --git a/packages/core/src/components/core/query/QuerySummaryDemographics.vue b/packages/core/src/components/core/query/QuerySummaryDemographics.vue new file mode 100644 index 00000000..8dcc3e84 --- /dev/null +++ b/packages/core/src/components/core/query/QuerySummaryDemographics.vue @@ -0,0 +1,56 @@ + + diff --git a/packages/core/src/components/core/query/QuerySummaryGrouped.vue b/packages/core/src/components/core/query/QuerySummaryGrouped.vue index 3e8ac9be..9faeec7c 100644 --- a/packages/core/src/components/core/query/QuerySummaryGrouped.vue +++ b/packages/core/src/components/core/query/QuerySummaryGrouped.vue @@ -7,7 +7,8 @@ import type { import { computed, defineComponent, ref, watch, } from 'vue'; -import type { QuerySummaryGrouped, QuerySummaryGroupedItem } from '../../../domains'; +import type { KeyValueRecord, KeyValueRecords } from '../../../domains'; +import { generateChartLabelsForKeyValueRecord } from '../../utility/chart/utils'; export default defineComponent({ props: { @@ -16,17 +17,17 @@ export default defineComponent({ default: 'Gruppe', }, items: { - type: Array as PropType, + type: Array as PropType, required: true, }, }, setup(props) { const id = ref(undefined) as Ref; - const item = ref(null) as Ref; + const item = ref(null) as Ref; - const options = computed(() => props.items.map((el) => ({ - id: el.key.code, - value: el.key.display || el.key.code, + const options = computed(() => props.items.map((el, id) => ({ + id, + value: generateChartLabelsForKeyValueRecord(el), }))); watch(id, (val) => { @@ -35,7 +36,7 @@ export default defineComponent({ return; } - const index = props.items.findIndex((el) => el.key.code === val); + const index = props.items.findIndex((_el, id) => id === parseInt(val, 10)); if (index !== -1) { item.value = props.items[index]; } diff --git a/packages/core/src/components/core/query/index.ts b/packages/core/src/components/core/query/index.ts index a89ab606..2e9a0f06 100644 --- a/packages/core/src/components/core/query/index.ts +++ b/packages/core/src/components/core/query/index.ts @@ -1 +1,2 @@ export { default as DQuerySummaryGrouped } from './QuerySummaryGrouped.vue'; +export { default as DQuerySummaryDemographics } from './QuerySummaryDemographics.vue'; diff --git a/packages/core/src/components/utility/chart/DChartBar.vue b/packages/core/src/components/utility/chart/DChartBar.vue index bec8a7a4..ce138135 100644 --- a/packages/core/src/components/utility/chart/DChartBar.vue +++ b/packages/core/src/components/utility/chart/DChartBar.vue @@ -5,9 +5,8 @@ import type { import { Bar } from 'vue-chartjs'; import type { PropType } from 'vue'; import { computed, defineComponent } from 'vue'; -import type { Coding, ConceptsCount, MinMaxRange } from '../../../domains'; -import { isCoding, isMinMaxRange } from '../../../domains'; -import { stringToColor } from '../../../utils'; +import type { Coding, KeyValueRecords, MinMaxRange } from '../../../domains'; +import { generateChartBackgroundColorForKeyValueRecord, generateChartLabelsForKeyValueRecord } from './utils'; export default defineComponent({ components: { @@ -16,44 +15,16 @@ export default defineComponent({ props: { items: { required: true, - type: Array as PropType>, + type: Array as PropType>, }, }, setup(props) { const data = computed>(() => ({ datasets: [{ - data: props.items.map((item) => item.count), - backgroundColor: props.items.map((item) => { - if (isCoding(item.concept)) { - return `${stringToColor(item.concept.display || item.concept.code)}`; - } - - if (isMinMaxRange(item.concept)) { - return `${stringToColor(`${(item.concept.min + item.concept.max) * 10}`)}`; - } - - if (Array.isArray(item.concept)) { - return `${stringToColor(item.concept.join('+'))}`; - } - - return undefined; - }), + data: props.items.map((item) => item.value), + backgroundColor: props.items.map((item) => generateChartBackgroundColorForKeyValueRecord(item)), }], - labels: props.items.map((item) => { - if (isCoding(item.concept)) { - return item.concept.display || item.concept.code; - } - - if (isMinMaxRange(item.concept)) { - return `${item.concept.min}-${item.concept.max}`; - } - - if (Array.isArray(item.concept)) { - return `${item.concept.join(', ')}`; - } - - return undefined; - }), + labels: props.items.map((item) => generateChartLabelsForKeyValueRecord(item)), })); const options : ChartOptions<'bar'> = { diff --git a/packages/core/src/components/utility/chart/DChartDoughnut.vue b/packages/core/src/components/utility/chart/DChartDoughnut.vue index d2ad0d8a..f9b92a9b 100644 --- a/packages/core/src/components/utility/chart/DChartDoughnut.vue +++ b/packages/core/src/components/utility/chart/DChartDoughnut.vue @@ -6,9 +6,8 @@ import type { import { Doughnut } from 'vue-chartjs'; import type { PropType } from 'vue'; import { computed, defineComponent } from 'vue'; -import { stringToColor } from '../../../utils'; -import { isCoding } from '../../../domains'; -import type { Coding, ConceptsCount, MinMaxRange } from '../../../domains'; +import type { Coding, KeyValueRecords, MinMaxRange } from '../../../domains'; +import { generateChartBackgroundColorForKeyValueRecord, generateChartLabelsForKeyValueRecord } from './utils'; export default defineComponent({ components: { @@ -17,24 +16,16 @@ export default defineComponent({ props: { items: { required: true, - type: Array as PropType>, + type: Array as PropType>, }, }, setup(props) { const data = computed>(() => ({ datasets: [{ - data: props.items.map((item) => item.count), - backgroundColor: props.items.map( - (item) => (isCoding(item.concept) ? - `${stringToColor(item.concept.display || item.concept.code)}` : - `${stringToColor(`${(item.concept.min + item.concept.max) * 10}`)}`), - ), + data: props.items.map((item) => item.value), + backgroundColor: props.items.map((item) => generateChartBackgroundColorForKeyValueRecord(item)), }], - labels: props.items.map( - (item) => (isCoding(item.concept) ? - item.concept.display || item.concept.code : - `${item.concept.min}-${item.concept.max}`), - ), + labels: props.items.map((item) => generateChartLabelsForKeyValueRecord(item)), })); const options : ChartOptions<'doughnut'> = { diff --git a/packages/core/src/components/utility/chart/utils.ts b/packages/core/src/components/utility/chart/utils.ts new file mode 100644 index 00000000..b44f41b9 --- /dev/null +++ b/packages/core/src/components/utility/chart/utils.ts @@ -0,0 +1,47 @@ +import type { KeyValueRecord } from '../../../domains'; +import { isCoding, isMinMaxRange } from '../../../domains'; +import { stringToColor } from '../../../utils'; + +export function generateChartLabelsForKeyValueRecord( + item: KeyValueRecord, +) : string | undefined { + if (isCoding(item.key)) { + return item.key.display || item.key.code; + } + + if (isMinMaxRange(item.key)) { + return `${item.key.min}-${item.key.max}`; + } + + if (Array.isArray(item.key)) { + return `${item.key.join(', ')}`; + } + + if (typeof item.key === 'string') { + return item.key; + } + + return undefined; +} + +export function generateChartBackgroundColorForKeyValueRecord( + item: KeyValueRecord, +) : string | undefined { + if (isCoding(item.key)) { + return `${stringToColor(item.key.display || item.key.code)}`; + } + + if (isMinMaxRange(item.key)) { + return `${stringToColor(`${(item.key.min + item.key.max) * 10}`)}`; + } + + if (Array.isArray(item.key)) { + return `${stringToColor(item.key.join('+'))}`; + } + + if (typeof item.key === 'string') { + return stringToColor(item.key); + } + + return undefined; +} diff --git a/packages/core/src/domains/query/types.ts b/packages/core/src/domains/query/types.ts index bb97e2b4..9098bb7c 100644 --- a/packages/core/src/domains/query/types.ts +++ b/packages/core/src/domains/query/types.ts @@ -1,15 +1,9 @@ import type { ObjectLiteral } from '../../types'; import type { Coding } from '../coding'; import type { PatientFilter } from '../patient'; +import type { KeyValueRecords } from '../types'; import type { MinMaxRange } from '../utility'; -export type ConceptCount = { - concept: CONCEPT, - count: number -}; - -export type ConceptsCount = ConceptCount[]; - export type DiagnosisFilter = { category?: Coding[], }; @@ -44,16 +38,16 @@ export type QueryBase< lastUpdate: string }; -export type QuerySummaryGroupedItem> = { +export type QuerySummaryGroupedItem> = { key: K, value: V }; -export type QuerySummaryGrouped = QuerySummaryGroupedItem[]; +export type QuerySummaryGrouped = QuerySummaryGroupedItem[]; export type QuerySummaryDemographics = { - siteDistribution: ConceptsCount, - genderDistribution: ConceptsCount, - ageDistribution: ConceptsCount, + siteDistribution: KeyValueRecords, + genderDistribution: KeyValueRecords, + ageDistribution: KeyValueRecords, }; export type QuerySummaryBase = { diff --git a/packages/core/src/domains/types.ts b/packages/core/src/domains/types.ts index 48fee1aa..c3274bd4 100644 --- a/packages/core/src/domains/types.ts +++ b/packages/core/src/domains/types.ts @@ -15,3 +15,9 @@ export type CodeRecord = { code: V, display?: string }; + +export type KeyValueRecord = { + key: KEY, + value: VALUE +}; +export type KeyValueRecords = KeyValueRecord[]; diff --git a/packages/mtb/src/runtime/components/core/MQuerySummaryMedication.vue b/packages/mtb/src/runtime/components/core/MQuerySummaryMedication.vue index 4f7de251..e0376cdb 100644 --- a/packages/mtb/src/runtime/components/core/MQuerySummaryMedication.vue +++ b/packages/mtb/src/runtime/components/core/MQuerySummaryMedication.vue @@ -1,11 +1,12 @@