Mam napisaną aplikację w Vue.js. Zmodyfikuj kod, aby pod napisem icd-code-selector pojawił się v2-text-field, w którego wpisanie kodu rozpoznania icd ma powodować ten sam skutek, co wyszukanie co za pomocą icd-code-selector. Tym samym wpisanie prawidłowego kodu lcd po wciśnięciu enter ma spowodować dodanie do lcd-code-list odpowiedniego rozpoznania z code i wyszukanym name. Wyszukiwanie kodu icd i odpowiadającemu jemu opisu ma odbywać się analogicznie jak w icd-code-selector.

/// process-visit-core-card.vue

<template>
  <div>
    <v-row dense>
      <v-col cols="12" md="4">
        <template-based-input
          v-model="model.interview"
          :specialization-id="specializationId"
          rows="14"
          :readonly="readonly"
          type="interview"
          class="mt-2" />
      </v-col>
      <v-col cols="12" md="4">
        <examination-card
          v-model="model.examination"
          :readonly="readonly"
          :specialization-id="specializationId"
          :type="type"
          class="mt-2" />
      </v-col>
      <v-col cols="12" md="4">
        <icd-code-list
          v-if="previewMode"
          v-model="model.procedures"
          class="mt-2"
          :readonly="readonly"
          title="Zastosowane procedury"
          type="Icd9" />
        <slot v-else name="visit-history"></slot>
      </v-col>
    </v-row>
    <v-row dense>
      <v-col cols="12" md="4">
        <icd-code-list
          v-model="model.diagnoses"
          title="Rozpoznania"
          :readonly="readonly"
          use-remarks
          type="Icd10"
          class="mt-2">
          <template #actions="{ item }">
            <slot name="diagnose-actions" :item="item"></slot>
          </template>
        </icd-code-list>
      </v-col>
      <v-col cols="12" md="4">
        <text-area-with-staff-template
          v-model="model.recommendations"
          :readonly="readonly"
          label="Zalecenia dodatkowe"
          class="mt-2"
          rows="10"
          toolbar
          high
          :type="staffTemplateTypes.visitRecommendations">
          <template #actions>
            <submit-icon-button
              icon="mdi-printer"
              color="primary lighten-5"
              tooltip="Drukuj"
              :action="printRecommendations" />
          </template>
        </text-area-with-staff-template>
      </v-col>
      <v-col cols="12" md="4">
        <medical-items-card
          ref="medicalItemsRef"
          :readonly="readonly"
          class="mt-2"
          :context="context" />
      </v-col>
    </v-row>
    <v-row dense>
      <v-col cols="12" md="8">
        <slot name="patient-conditions"></slot>
      </v-col>
      <v-col v-if="!previewMode" cols="12" md="4">
        <icd-code-list
          v-model="model.procedures"
          class="mt-3"
          :readonly="readonly"
          title="Zastosowane procedury"
          type="Icd9" />
      </v-col>
    </v-row>
    <v-row dense>
      <v-col cols="12">
        <ophthalmic-care-card
          v-if="isOphthalmicCardType"
          v-model="model.ophthalmicCare.model"
          class="mt-2"
          :readonly="readonly"
          @print-ophthalmic="printOphthalmic" />
        <surgery-care-card
          v-if="isSurgeryCardType"
          v-model="model.surgeryCare.model"
          class="mt-2"
          :specialization-id="specializationId"
          :readonly="readonly" />
        <gynecology-care-card
          v-if="isGynecologyCardType"
          v-model="model.gynecologyCare.model"
          :prenatal-referral-id="prenatalReferralId"
          :readonly="readonly"
          @update:prenatal-referral-id="onPrenatalReferralIdUpdate" />
      </v-col>
    </v-row>
  </div>
</template>
<script lang="ts">
import MaskUtils from "@/components/enums/mask-utils";
import SubmitIconButton from "@/components/action-buttons/submit-icon-button.vue";
import type GovServicesBaseContext from "@/views/commerce/gov-services/gov-services-base-context";
import SpecializationCardType from "@/views/commerce/specializations/specialization-card-type";
import StaffTemplateType from "@/views/commerce/staff-templates/staff-template-type";
import TextAreaWithStaffTemplate from "@/views/commerce/staff-templates/text-templates/text-area-with-staff-template.vue";
import type CareData from "@/views/commerce/visits/process/care-data";
import ExaminationCard from "@/views/commerce/visits/process/examination/examination-card.vue";
import IcdCodeList from "@/views/commerce/visits/process/icd-codes/icd-code-list.vue";
import MedicalItemsCard from "@/views/commerce/visits/process/medical-data/medical-items-card.vue";
import OphthalmicCareCard from "@/views/commerce/visits/process/ophthalmic/ophthalmic-care-card.vue";
import SurgeryCareCard from "@/views/commerce/visits/process/surgery/surgery-care-card.vue";
import TemplateBasedInput from "@/views/commerce/visits/summary-template/template-based-input.vue";
import type {
  PropType} from "@vue/composition-api";
import {
  computed,
  defineComponent,
  inject,
  onBeforeUpdate,
  onMounted,
  ref,
  watch
} from "@vue/composition-api";
import { objectProp } from "@/compatibility-layer/model-prop";
import ModelConstants from "@/compatibility-layer/model-constants";
import { useObjectModel } from "@/compatibility-layer/object-model";
import GynecologyCareCard from "@/views/commerce/visits/process/gynecology/gynecology-care-card.vue";
import FixedData from "@/views/main-wrap/fixed-data";
import PregnancyCodes from "@/views/commerce/visits/process/pregnancy-codes";

const ProcessVisitCoreCard = defineComponent({
  components: {
    GynecologyCareCard,
    SubmitIconButton,
    SurgeryCareCard,
    OphthalmicCareCard,
    IcdCodeList,
    MedicalItemsCard,
    ExaminationCard,
    TextAreaWithStaffTemplate,
    TemplateBasedInput
  },

  props: {
    ...objectProp<CareData>(),
    type: {
      type: Number,
      required: true
    },
    specializationId: {
      type: Number,
      required: true
    },
    prenatalReferralId: {
      type: [String, null] as PropType<string | null>,
      required: false,
      default: null
    },
    previewMode: {
      type: Boolean,
      required: false,
      default: false
    },
    context: {
      type: Object as PropType<GovServicesBaseContext>,
      required: true
    }
  },

  emits: [
    ModelConstants.modelEvent,
    "print-ophthalmic",
    "print-recommendations",
    "update:prenatal-referral-id"
  ],

  setup(props, context) {
    const fixedData = inject(FixedData.Key) as FixedData;
    const model = useObjectModel<CareData>(props, context);
    const pregnancyCodes = ref(PregnancyCodes.empty());
    const inPatientConditionsEditMode = ref(false);

    const medicalItemsRef = ref(null);

    onBeforeUpdate(() => {
      medicalItemsRef.value = null;
    });
    onMounted(async () => {
      pregnancyCodes.value = await fixedData.loadPregnancyCodes();
    });

    const isSurgeryCardType = computed(() =>
      MaskUtils.hasFlag(props.type, SpecializationCardType.Surgery)
    );
    const isOphthalmicCardType = computed(() =>
      MaskUtils.hasFlag(props.type, SpecializationCardType.Ophthalmic)
    );
    const isAestheticCardType = computed(() =>
      MaskUtils.hasFlag(props.type, SpecializationCardType.Aesthetic)
    );

    const isGynecologyCardType = computed(() =>
      MaskUtils.hasFlag(props.type, SpecializationCardType.Gynecology)
    );

    const printRecommendations = (): Promise<void> =>
      new Promise<void>(resolve => context.emit("print-recommendations", resolve));

    const reload = () => {
      const entity = medicalItemsRef.value as any;
      if (entity) {
        entity.reload();
      }
    };

    const pregnancyImplied = ref(false);

    watch(
      () => model.value.diagnoses,
      (nv, _) => {
        if (pregnancyImplied.value) return;
        if (!isGynecologyCardType.value) return;
        if (nv.find(v => pregnancyCodes.value.all.has(v.code))) {
          model.value.gynecologyCare.isPregnant = true;
          pregnancyImplied.value = true;
        }
      },
      { deep: true }
    );

    return {
      model,
      isSurgeryCardType,
      isOphthalmicCardType,
      isAestheticCardType,
      isGynecologyCardType,
      inPatientConditionsEditMode,
      printOphthalmic: resolve => context.emit("print-ophthalmic", resolve),
      printRecommendations,
      medicalItemsRef,
      reload,
      staffTemplateTypes: StaffTemplateType.instance,
      onPrenatalReferralIdUpdate: v => context.emit("update:prenatal-referral-id", v)
    };
  }
});

export default ProcessVisitCoreCard;
</script>

/// v2-text-field.vue

<template>
  <v-text-field
    v-model="model"
    :clearable="!readonly && clearable"
    :dense="dense"
    :filled="readonly || filled"
    :hide-details="hideDetails || rules.length === 0"
    :label="label"
    :placeholder="placeholder"
    :prepend-icon="prependIcon"
    :readonly="readonly"
    :rules="computedRules"
    :loading="loading"
    :error-messages="errorMessages"
    :autocomplete="autocomplete"
    :outlined="outlined"
    :type="type"
    @click="onClick"
    @click:clear="onClear">
    <template v-if="customPrependInner" #prepend-inner>
      <slot name="prepend-inner"></slot>
    </template>
  </v-text-field>
</template>
<script lang="ts">
import ModelConstants from "@/compatibility-layer/model-constants";
import { optionalStringProp } from "@/compatibility-layer/model-prop";
import { useOptionalStringModel } from "@/compatibility-layer/primitive-model";
import { RulesUtils } from "@/lib/rules-utils";
import type { PropType } from "@vue/composition-api";
import { computed, defineComponent } from "@vue/composition-api";
import type { HideDetailsType } from "@/compatibility-layer/hide-details-type";

const V2TextField = defineComponent({
  props: {
    ...optionalStringProp(),
    label: {
      type: String,
      required: false,
      default: null
    },
    placeholder: {
      type: String,
      required: false,
      default: null
    },
    rules: {
      type: Array,
      required: false,
      default: () => []
    },
    prependIcon: {
      type: String,
      required: false,
      default: undefined
    },
    clearable: {
      type: Boolean,
      required: false,
      default: false
    },
    dense: {
      type: Boolean,
      required: false,
      default: true
    },
    loading: {
      type: Boolean,
      required: false,
      default: false
    },
    outlined: {
      type: Boolean,
      required: false,
      default: true
    },
    hideDetails: {
      type: [String, Boolean] as PropType<HideDetailsType>,
      required: false,
      default: true
    },
    required: {
      type: Boolean,
      required: false,
      default: false
    },
    filled: {
      type: Boolean,
      required: false,
      default: false
    },
    autocomplete: {
      type: String,
      required: false,
      default: "off"
    },
    type: {
      type: String,
      required: false,
      default: "text"
    },
    errorMessages: {
      type: Array,
      required: false,
      default: () => []
    },
    customPrependInner: {
      type: Boolean,
      required: false,
      default: false
    }
  },

  emits: [ModelConstants.modelEvent, "click", "clear"],

  setup(props, context) {
    const model = useOptionalStringModel(props, context);
    const computedRules = computed(() => {
      return props.required ? [...RulesUtils.NotEmpty, ...props.rules] : props.rules;
    });

    return {
      model,
      computedRules,
      onClick: () => context.emit("click"),
      onClear: () => context.emit("clear")
    };
  }
});

export default V2TextField;
</script>

/// icd-code-list.vue

<template>
  <titled-card toolbar :title="title" :add-button="!readonly" @add="addItem">
    <v-overlay v-if="inAddItemMode" z-index="30" :dark="false">
      <icd-code-selector
        :endpoint-suffix="type"
        @select="submitAddItem"
        @close="inAddItemMode = false" />
    </v-overlay>
    <v-overlay v-if="showDescDialog" z-index="30" :dark="false">
      <async-input-dialog
        title="Opis"
        style="min-width: min(640px, 95vw)"
        :action="setDescription"
        :rules="descriptionRules"
        :default-value="selectedItemRemarks"
        multiline
        @close="editedIndex = null" />
    </v-overlay>
    <template v-for="(item, idx) in model">
      <v-row :key="idx" dense align="center">
        <v-col cols="auto" style="flex-basis: 56px">
          <span class="text--bold text-body-2" v-text="item.code"></span>
        </v-col>
        <v-col>
          <div class="text-body-2" v-text="item.name"></div>
          <div v-if="item.remarks" class="text--darken-3 text-caption primary--text">
            {{ item.remarks }}
          </div>
        </v-col>
        <v-col cols="auto">
          <slot name="actions" :item="item"></slot>
        </v-col>
        <v-col v-if="!readonly" cols="auto">
          <edit-delete-buttons
            :edit-visible="useRemarks"
            @delete="deleteItem(item)"
            @edit="editedIndex = idx" />
        </v-col>
      </v-row>
      <v-divider v-if="idx < model.length - 1" :key="idx" class="my-1" />
    </template>
    <span v-if="!model.length" class="text-caption">Brak</span>
    <template #actions>
      <v-row dense align="center">
        <v-col cols="auto">
          <copy-from-toolbar v-if="!readonly" :action="copyFromSelection" :type="listType" />
        </v-col>
      </v-row>
    </template>
  </titled-card>
</template>
<script lang="ts">
import ModelConstants from "@/compatibility-layer/model-constants";
import { arrayProp } from "@/compatibility-layer/model-prop";
import { useArrayModel } from "@/compatibility-layer/object-model";
import AsyncInputDialog from "@/components/action-buttons/async-input-dialog.vue";
import EditDeleteButtons from "@/components/action-buttons/edit-delete-buttons.vue";
import LoadingContainer from "@/components/loading/loading-container.vue";
import TitledCard from "@/components/simple/titled-card.vue";
import CopyFromToolbar from "@/views/commerce/visits/process/copy-from-selected-visit/copy-from-toolbar.vue";
import type IcdCode from "@/views/commerce/visits/process/icd-codes/icd-code";
import IcdCodeSelector from "@/views/commerce/visits/process/icd-codes/icd-code-selector.vue";
import type RecentProcessedVisit from "@/views/commerce/visits/process/recent-processed-visit";
import type { CopyFromVisitInputType } from "@/views/commerce/visits/summary-template/copy-from-visit-input-type";
import { computed, defineComponent, ref } from "@vue/composition-api";
import { RulesUtils } from "@/lib/rules-utils";

const IcdCodeListSelector = defineComponent({
  components: {
    CopyFromToolbar,
    AsyncInputDialog,
    TitledCard,
    IcdCodeSelector,
    EditDeleteButtons,
    LoadingContainer
  },

  props: {
    ...arrayProp<IcdCode>(),

    type: {
      type: String,
      required: true
    },
    title: {
      type: String,
      required: true
    },
    useRemarks: {
      type: Boolean,
      required: false,
      default: false
    }
  },
  emits: [ModelConstants.modelEvent],

  setup(props, context) {
    const model = useArrayModel<IcdCode>(props, context, {
      itemKey: v => `${v.code}_${v.remarks}`
    });

    const editedIndex = ref(null as number | null);

    const inAddItemMode = ref(false);

    const setDescription = (val: string) => {
      const idxVal = editedIndex.value;

      if (idxVal || idxVal === 0) {
        model.value[idxVal].remarks = val;
      }
      editedIndex.value = null;
      return Promise.resolve();
    };

    const addItem = () => {
      inAddItemMode.value = true;
    };

    const deleteItem = (val: IcdCode) => {
      const idx = model.value.findIndex(v => v.code === val.code);
      if (idx !== -1) {
        model.value.splice(idx, 1);
      }
    };

    const submitAddItem = (val: IcdCode) => {
      if (model.value.findIndex(v => v.code === val.code) === -1) {
        model.value.push(val);
      }
      inAddItemMode.value = false;
    };

    const listType = computed(() => {
      if (props.type === "Icd9") {
        return "procedures" as CopyFromVisitInputType;
      }
      if (props.type === "Icd10") {
        return "diagnoses" as CopyFromVisitInputType;
      }
      return null;
    });

    const getLoadedList = (visit: RecentProcessedVisit): IcdCode[] => {
      if (props.type === "Icd9") {
        return visit.patientCare.procedures;
      }
      if (props.type === "Icd10") {
        return visit.patientCare.diagnoses;
      }
      return [];
    };

    const copyFromSelection = (visit: RecentProcessedVisit) => {
      const loadedList = getLoadedList(visit);
      if (!loadedList.length) {
        return;
      }
      model.value = loadedList;
    };

    const showDescDialog = computed(() => {
      const idxVal = editedIndex.value;
      return idxVal || idxVal === 0;
    });

    const selectedItemRemarks = computed(() => {
      const idxVal = editedIndex.value;
      return idxVal || idxVal === 0 ? model.value[idxVal].remarks : null;
    });

    return {
      model,
      deleteItem,
      addItem,
      copyFromSelection,
      submitAddItem,
      listType,
      setDescription,
      editedIndex,
      showDescDialog,
      selectedItemRemarks,
      descriptionRules: RulesUtils.ExcludedHtmlControlSequences(),
      inAddItemMode
    };
  }
});

export default IcdCodeListSelector;
</script>

/// icd-code-selector.vue

<template>
  <titled-card
    title="Wybierz pozycję"
    close-button
    toolbar
    style="width: min(1000px, 90vw)"
    @close="close">
    <template v-if="showAll">
      <v-row dense align="start" class="my-0">
        <v-col>
          <v-tabs v-if="!hideCategories" v-model="currentTab">
            <v-tab>Lista</v-tab>
            <v-tab>Kategorie</v-tab>
          </v-tabs>
        </v-col>
        <v-col v-if="currentTab === 0" cols="auto">
          <search-input v-model="searchPhrase" autofocus />
        </v-col>
      </v-row>
      <v-tabs-items v-model="currentTab">
        <v-tab-item>
          <v-container
            class="py-0"
            fluid
            style="height: calc(100vh - 250px); min-height: 60vh; overflow-y: scroll">
            <icd-code-list-selector
              :endpoint-suffix="endpointSuffix"
              :search-phrase="searchPhrase"
              @select="select" />
          </v-container>
        </v-tab-item>
        <v-tab-item>
          <v-container
            fluid
            style="max-height: calc(100vh - 250px); min-height: 60vh; overflow-y: scroll">
            <icd-code-tree-selector :endpoint-suffix="endpointSuffix" @select="select" />
          </v-container>
        </v-tab-item>
      </v-tabs-items>
    </template>

    <template v-else>
      <v-row dense justify="end" align="center">
        <v-col>
          <v-btn text small color="primary" @click="showAll = true">
            Pokaż wszystkie
          </v-btn>
        </v-col>
        <v-col cols="auto">
          <search-input v-model="searchPhrase" autofocus />
        </v-col>
      </v-row>
      <icd-code-list-selector
        :endpoint-suffix="endpointSuffix"
        :search-phrase="searchPhrase"
        :search-prefix="searchPrefix"
        @select="select" />
    </template>
  </titled-card>
</template>
<script lang="ts">
import SearchInput from "@/components/simple/search-input.vue";
import TitledCard from "@/components/simple/titled-card.vue";
import type IcdCode from "@/views/commerce/visits/process/icd-codes/icd-code";
import IcdCodeListSelector from "@/views/commerce/visits/process/icd-codes/icd-code-list-selector.vue";
import IcdCodeTreeSelector from "@/views/commerce/visits/process/icd-codes/icd-code-tree-selector.vue";
import { defineComponent, ref } from "@vue/composition-api";

const MedicalServiceGroupsView = defineComponent({
  components: { SearchInput, TitledCard, IcdCodeTreeSelector, IcdCodeListSelector },

  props: {
    endpointSuffix: {
      type: String,
      required: true
    },
    hideCategories: {
      type: Boolean,
      required: false,
      default: false
    },
    searchPrefix: {
      type: String,
      required: false,
      default: null
    }
  },

  setup(props, context) {
    const searchPhrase = ref(null as string | null);

    const showAll = ref(!props.searchPrefix);

    const currentTab = ref(0);

    const select = (item: IcdCode) => {
      context.emit("select", item);
    };

    const close = () => {
      searchPhrase.value = null;
      context.emit("close");
    };

    return {
      searchPhrase,
      select,
      close,
      showAll,
      currentTab
    };
  }
});

export default MedicalServiceGroupsView;
</script>

/// icd-code-list-selector.vue

<template>
  <v-container class="ma-0 pa-0" fluid>
    <div style="min-height: 5px">
      <v-progress-linear v-if="isSearchLoading" indeterminate color="primary" />
    </div>
    <v-data-iterator
      :footer-props="{ itemsPerPageOptions: iteratorOptions.itemsPerPageOptions }"
      :items="items"
      :items-per-page.sync="query.itemsPerPage"
      :page.sync="query.page"
      :server-items-length="totalCount"
      :loading="isSearchLoading"
      disable-filtering
      disable-sort
      class="pb-6 pt-3">
      <template #loading>
        <list-loading />
      </template>
      <template #no-data>
        <v-card><v-card-text>Brak wpisów spełniających kryteria</v-card-text></v-card>
      </template>
      <template #default="props">
        <template v-for="(item, index) in items">
          <v-card :key="index" flat tile @click="select(item)">
            <v-row :key="index" dense>
              <v-col cols="auto">
                <div class="text--bold text-body-2" style="min-width: 60px" v-text="item.code"></div>
              </v-col>
              <v-col>
                <span class="text-body-2" v-text="item.name"></span>
              </v-col>
            </v-row>
          </v-card>
          <v-divider v-if="index < items.length - 1" :key="index" class="my-1" />
        </template>
      </template>
    </v-data-iterator>
  </v-container>
</template>
<script lang="ts">
import axios from "@/lib/axios";
import { defineComponent, onMounted, ref, watch } from "@vue/composition-api";
import { debounce } from "lodash";
import LoadingContainer from "@/components/loading/loading-container.vue";
import IcdCode from "@/views/commerce/visits/process/icd-codes/icd-code";
import { IcdCodeQuery } from "@/views/commerce/visits/process/icd-codes/icd-code-query";
import ListLoading from "@/components/loading/list-loading.vue";

const IcdCodeListSelector = defineComponent({
  components: { LoadingContainer, ListLoading },

  props: {
    endpointSuffix: {
      type: String,
      required: true
    },
    searchPhrase: {
      type: String,
      required: true
    },
    searchPrefix: {
      type: String,
      required: false,
      default: null
    }
  },

  emits: ["select"],

  setup(props, context) {
    const isLoaded = ref(false);
    const isSearchLoading = ref(false);
    const query = ref(new IcdCodeQuery());
    const items = ref([] as IcdCode[]);
    const totalCount = ref(0);
    const iteratorOptions = ref({
      itemsPerPageOptions: [15, 30]
    });

    const loadData = async () => {
      isLoaded.value = false;
      await executeSearch();
      isLoaded.value = true;
    };

    onMounted(async () => {
      query.value.itemsPerPage = 30;
      query.value.prefix = props.searchPrefix;
      query.value.searchPhrase = props.searchPhrase;
      await loadData();
      isLoaded.value = true;
    });

    watch(
      () => props.searchPhrase,
      (nv, _) => (query.value.searchPhrase = nv)
    );

    watch(
      () => props.searchPrefix,
      (nv, _) => (query.value.prefix = nv)
    );

    const prevPage = ref(1);
    watch(
      query,
      async (nv, _) => {
        if (!isLoaded.value) return;
        query.value.handleUpdate(prevPage, onSearchUpdate);
      },
      {
        deep: true
      }
    );

    const executeSearch = async () => {
      const response = await axios.post(
        `/api/services/app/IcdCodes/Search${props.endpointSuffix}`,
        query.value.dto
      );
      items.value = response.data.result.items.map(IcdCode.fromDto);
      totalCount.value = response.data.result.totalCount;
    };

    const searchDebounce = debounce(async () => {
      await executeSearch();
      isSearchLoading.value = false;
    }, 500);

    const onSearchUpdate = () => {
      isSearchLoading.value = true;
      searchDebounce();
    };

    const select = (item: IcdCode) => {
      context.emit("select", item);
    };

    return {
      query,
      totalCount,
      items,
      isLoaded,
      isSearchLoading,
      iteratorOptions,
      select
    };
  }
});

export default IcdCodeListSelector;
</script>