Connecting search apis

This commit is contained in:
mustafa-rezae 2025-03-15 13:41:29 +03:30
parent 953d98f3be
commit 832f5dbf52
9 changed files with 954 additions and 404 deletions

View File

@ -1,73 +0,0 @@
export default {
items: {
get: "monir/search/get/byid/",
},
Farhanghestan: {
search_normal: "monir/search/0/10",
search_And: "monir/search/and/0/10",
search_Phrase: "monir/search/phrase/0/10",
search_Code: "monir/search/code/all/0/10",
},
subject: {
add: "sanad/subject/add",
// edit: "sanad/subject/edit",
delete: "sanad/subject/delete",
order: "monir/sanad/subject/order",
},
index: {
Index_one: "safheh212/one",
index_multi: "safheh212/multi",
},
nesha: {
search_normal: "monir/search/nesha/0/10",
},
wordSWeight: {
list: "ngrams/elastic/{{index_key}}/1to3",
},
rezome: {
add: "rezumeh",
get: "rezumeh/get",
},
navigation: {
list: "navigate/list/@entity",
report:
"navigate/report/{{index_key}}/{{offset}}/{{limit}}/{{aggs}}/{{filter}}",
reportItem: "navigate/report/items",
reportSubjectItem: "navigate/report/subject={{subject_title}}/items",
},
bnavigation: {
list: "repo/navigate/list",
report: "repo/navigate/report",
reportItem: "repo/navigate/report/items",
reportSubjectItem: "repo/navigate/report/subject={{subject_title}}/items",
},
schema: {
list: "schema",
},
search: {
autoComplate:
"{{appname}}/complation/{{index_key}}/{{filter}}",
logAutoComplate:
"searchlog/complation/{{filter}}",
default:
"{{appname}}/data/{{index_key}}/{{sortKey}}/{{offset}}/{{limit}}/{{filter}}",
queryNormal:
"{{appname}}/search/{{index_key}}/{{search_type}}/{{sortKey}}/{{field_collapse}}/{{offset}}/{{limit}}/{{filter}}",
textSearch:
"{{appname}}/search/text/{{index_key}}/{{field}}/{{offset}}/{{limit}}/{{filter}}",
},
chart: {
timeline: "{{appname}}/data/timeline/{{index_key}}",
xy: "{{appname}}/data/xy/{{index_key}}/{{field_key}}",
items:
"navigate/report/items/search/{{index_key}}/{{offset}}/{{limit}}/{{filter}}",
chartTreeMap: "list/project/treemap/{{chart_key}}/{{filter}}",
treeItems:"navigate/report/items/search/{{index_key}}/{{offset}}/{{limit}}/{{filter}}",
tree: "list/subject/list",
graph:"repo/majles/{{to_key}}/relation"
},
synonym:{
getSynonyms:"synonym/get/words",
synonymSearch:"search/qasection/synonym/@listkey/@offset/@limit/@q",
}
};

4
apis/hadithaApi.js Normal file
View File

@ -0,0 +1,4 @@
export default {
search:
"repo/monir/search/@index_key/@search_type/@type_key/@listkey/@field_collapsed/@offset/@limit/@q=none",
};

View File

@ -1,4 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { InputMenuItem } from "@nuxt/ui";
import hadithaApi from "../../apis/hadithaApi";
import type { HadithResponseModel } from "../../types/hadithType";
import { useStorage } from "@vueuse/core";
import type { MaybeArrayOfArray } from "@nuxt/ui/runtime/types/utils.js";
// #region props
const props = defineProps({ const props = defineProps({
showFilter: { showFilter: {
default: false, default: false,
@ -7,43 +14,34 @@ const props = defineProps({
default: false, default: false,
}, },
}); });
// #endregion props
// #region emits
const emit = defineEmits(["response-ready"]); const emit = defineEmits(["response-ready"]);
const router = useRouter(); // #endregion emits
export type Sample = { // #region refs
fromPerson: string; const userSearchHistory = useStorage(
arabicText: string; "userSearchHistory",
persianText: string; new Set() // Initial value
reference: string; );
};
const searchTerm = ref("");
const open = ref(false);
const loading = ref(false);
// If you want to share state across multiple components,
// you can use the same key in useState. Nuxt will ensure
// that the state is shared and reactive across your application.
// const typingTimer = useState<number>("typingTimer", () => 0);
// const doneTypingInterval = useState<number>("doneTypingInterval", () => 1000);
const typingTimer = ref<number | any>(0);
const doneTypingInterval = ref<number>(1000);
// #endregion refs
// #region reactive
const state = reactive({ const state = reactive({
list: [ list: [],
{
fromPerson: "امام علی علیه‌السلام",
arabicText:
" وَمَا يَذۡكُرُونَ إِلَّآ أَن يَشَآءَ ٱللَّهُ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ",
persianText:
" خداوند متعال ما (اهل بیت) را آفرید و ما را خازنان علم خود در آسمان و زمین قرار داد. و نماز در مسیحیت برای ما قرار که پیش",
reference: "الکافی، جلد ۱، صفحه ۱۰۳",
},
{
fromPerson: "امام علی علیه‌السلام",
arabicText:
" وَمَا يَذۡكُرُونَ إِلَّآ أَن يَشَآءَ ٱللَّهُ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ",
persianText:
" خداوند متعال ما (اهل بیت) را آفرید و ما را خازنان علم خود در آسمان و زمین قرار داد. و نماز در مسیحیت برای ما قرار که پیش",
reference: "الکافی، جلد ۱، صفحه ۱۰۳",
},
{
fromPerson: "امام علی علیه‌السلام",
arabicText:
" وَمَا يَذۡكُرُونَ إِلَّآ أَن يَشَآءَ ٱللَّهُ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ",
persianText:
" خداوند متعال ما (اهل بیت) را آفرید و ما را خازنان علم خود در آسمان و زمین قرار داد. و نماز در مسیحیت برای ما قرار که پیش",
reference: "الکافی، جلد ۱، صفحه ۱۰۳",
},
],
filters: [ filters: [
{ {
label: "معنایی", label: "معنایی",
@ -106,59 +104,75 @@ const state = reactive({
}, },
], ],
}); });
const searchTerm = ref<string>(""); // #endregion reactive
const open = ref(false);
const loading = ref(false);
// fetch history list from backend(ssr) // #region methods
// const { data: users, status } = await useFetch(
// "https://jsonplaceholder.typicode.com/users",
// {
// transform: (data: { id: number; name: string }[]) => {
// return (
// data?.map((user) => ({
// label: user.name,
// value: String(user.id),
// avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` },
// })) || []
// );
// },
// lazy: true,
// }
// );
const clearSimilar = () => { const clearSimilar = () => {
console.info("clearSimilar"); console.info("clearSimilar");
}; };
const onBlur = () => { const onBlur = () => {
// console.info("onBlue"); console.info("onBlur");
}; };
const onChange = () => { const onChange = () => {
// console.info("onChange"); console.info("onChange");
sendQuery();
}; };
const onUpdateModel = (newVal: string) => { const onUpdateModel = (newVal: boolean | InputMenuItem | any) => {
console.info("onUpdateModel", newVal); console.info("onUpdateModel", newVal);
}; };
const onSearch = () => {
console.info("onSearch");
router.push({
name: "hadithaSearch",
});
};
const onKeyDown = () => { const onKeyDown = () => {
// console.info("onKeyDown"); clearTimeout(typingTimer.value);
}; };
const onKeyUp = () => { const onKeyUp = () => {
// console.info("onKeyUp"); clearTimeout(typingTimer.value);
typingTimer.value = setTimeout(() => {
sendQuery();
}, doneTypingInterval.value);
}; };
const onSend = () => {
console.info("onSend");
const sendQuery = async () => {
if (loading.value) return;
loading.value = true;
let url = hadithaApi.search;
url = url.replace("@index_key", "dhparag");
url = url.replace("@search_type", "normal");
url = url.replace("@type_key", "hadith");
url = url.replace("@offset", "0");
url = url.replace("@limit", "10");
url = url.replace("@listkey", "normal");
url = url.replace("@field_collapsed", "normal");
url = url.replace(
"@q=none",
searchTerm.value.length ? `q=${searchTerm.value}` : "q=none"
);
// fetch search list from backend(ssr)
const { data, status, error, refresh, clear } =
await useHadithaSearchComposable<HadithResponseModel>(url, {
method: "post",
});
if (status.value == "success") {
loading.value = false;
}
// pass res and search query to the parent.
emit("response-ready", { emit("response-ready", {
searchList: state.list, res: data.value,
searchQuery: searchTerm.value, searchQuery: searchTerm.value,
}); });
// check if search term is not empty
if (searchTerm.value) userSearchHistory.value.add(searchTerm.value); // Add the value to the Set
// close the history dropdown menu
open.value = false;
}; };
// #endregion methods
</script> </script>
<template> <template>
@ -180,13 +194,13 @@ const onSend = () => {
<div class="search-input"> <div class="search-input">
<UInputMenu <UInputMenu
class="w-full focus:placeholder-gray-800" class="w-full focus:placeholder-gray-800"
:items="[]" :items="<any>Array.from(userSearchHistory)"
v-model="searchTerm" v-model="searchTerm"
v-model:open="open" v-model:open="open"
v-model:search-term="searchTerm" v-model:search-term="searchTerm"
placeholder="هوشمند جستجو کنید..." placeholder="هوشمند جستجو کنید..."
:ui="{ :ui="{
base: ['haditha-search-input'], base: 'haditha-search-input',
}" }"
:content="{ :content="{
align: 'start', align: 'start',
@ -203,11 +217,15 @@ const onSend = () => {
@update:searchTerm="onUpdateModel" @update:searchTerm="onUpdateModel"
@keydown="onKeyDown" @keydown="onKeyDown"
@keyup="onKeyUp" @keyup="onKeyUp"
@keydown.enter="onSend" @keydown.enter="sendQuery"
> >
</UInputMenu> </UInputMenu>
</div> </div>
<UButton class="my-trailing-button" @click.prevent="onSearch" icon="i-haditha-search"> <UButton
class="my-trailing-button"
@click.prevent="sendQuery"
icon="i-haditha-search"
>
<!-- <UIcon name="i-lucide-search" /> --> <!-- <UIcon name="i-lucide-search" /> -->
</UButton> </UButton>
</div> </div>

View File

@ -5,6 +5,9 @@ const props = defineProps({
return []; return [];
}, },
}, },
total: {
default: 0,
},
noDataText: { noDataText: {
default: "نتیجه‌ای یافت نشد!", default: "نتیجه‌ای یافت نشد!",
}, },
@ -40,28 +43,29 @@ const SearchShow = defineAsyncComponent(() =>
<template> <template>
<div class="search-list-contianer"> <div class="search-list-contianer">
<div class="total"> <div class="total">
<span>48</span> <span>{{ total }}</span>
نتیجه نتیجه
</div> </div>
<div class="search-list firefox-scrollbar" :class="route.name"> <div class="search-list firefox-scrollbar">
<div <div
v-if="props.list.length" v-if="props.list.length"
class="search-list-item" class="search-list-item"
v-for="(item, index) in props.list" v-for="(item, index) in props.list"
:key="index" :key="index"
> >
<p @click="openModal(item)" class="from-person">امام علی علیهالسلام</p> <p @click="openModal(item)" class="from-person">
<p @click="openModal(item)" class="arabic-text"> {{ item._source.meta.hadith_masoum ?? "بدون عنوان" }}
وَمَا يَذۡكُرُونَ إِلَّآ أَن يَشَآءَ ٱللَّهُ هُوَ أَهلُ ٱلتَّقوَىٰ
وَأَهلُ ٱلمَغفِرَةِ هُوَ أَهلُ ٱلتَّقوَىٰ وَأَهلُ ٱلمَغفِرَةِ
</p>
<p class="persian-text">
خداوند متعال ما (اهل بیت) را آفرید و ما را خازنان علم خود در آسمان و
زمین قرار داد. و نماز در مسیحیت برای ما قرار که پیش
</p> </p>
<p @click="openModal(item)" class="arabic-text">بدون متن عربی</p>
<p
class="persian-text"
v-html="item.highlight['content.fa'] ?? item._source.content"
></p>
<div class="flex justify-end"> <div class="flex justify-end">
<p class="reference">الکافی، جلد ۱، صفحه ۱۰۳</p> <p class="reference">
{{ item._source.address.vol_title }}، صفحه {{ item._source.address.page_num }}
</p>
</div> </div>
</div> </div>
@ -118,7 +122,7 @@ const SearchShow = defineAsyncComponent(() =>
} }
.search-list { .search-list {
padding: 1em 1.3em; padding: 1em 1.3em;
height: calc(100dvh - 15.2em); height: calc(100dvh - 16em);
overflow-y: auto; overflow-y: auto;
&.hadithaFavorites { &.hadithaFavorites {
@ -214,6 +218,10 @@ const SearchShow = defineAsyncComponent(() =>
</style> </style>
<style> <style>
.text__orange {
color: orange;
}
.modal-content { .modal-content {
border: 0.3px solid #e0e0e0; border: 0.3px solid #e0e0e0;
box-shadow: 0px 8px 20px 0px #0000001a; box-shadow: 0px 8px 20px 0px #0000001a;

View File

@ -18,3 +18,9 @@ onUnmounted(() => {
<slot></slot> <slot></slot>
</main> </main>
</template> </template>
<style>
#__nuxt.isolate {
height: 100%;
}
</style>

View File

@ -0,0 +1,497 @@
<script setup>
definePageMeta({
layout: false,
name: "hadithaSearchShow",
});
useHead({
name: "hadithaSearchShow",
title: `${import.meta.env.VITE_HADITH_PAGE_TITLE} | ${
props.selectedItem._source.meta.hadith_masoum ?? "بدون عنوان"
}`,
meta: [
{ name: "description", content: "کاوش با هوش مصنوعی در احادیث اسلامی" },
],
bodyAttrs: {
class: import.meta.env.VITE_HADITH_SYSTEM,
},
});
const props = defineProps({
selectedItem: {
type: Object,
default() {
return {};
},
},
});
const emit = defineEmits(["close"]);
// const open = ref(false);
const closeModal = () => {
emit("close");
};
const goToTheSearch = () => {
router.push({
name: "hadithaSearch",
});
};
const goToTheChatbot = () => {
router.push({
name: "hadithaChatbot",
});
};
</script>
<template>
<div class="search-show-modal">
<div class="body-header">
<span class="top-left-bgi z-0"></span>
<div class="modal-title flex justify-between">
<NuxtImg
fit="auto"
quality="80"
placeholder
src="/img/haditha/haditha-title.svg"
/>
<UButton
icon="i-haditha-close"
color="neutral"
variant="ghost"
class="close-btn"
@click="closeModal"
/>
</div>
</div>
<div class="body-content">
<div class="h-full flex flex-col justify-center z-2">
<div class="bg-container h-full">
<div class="header flex">
<UButton variant="ghost" class="bookmark-btn" icon="i-haditha-tag">
</UButton>
<div class="referene">
<span> نشانی: </span>
{{ props.selectedItem._source.address.vol_title }}، صفحه
{{ props.selectedItem._source.address.page_num }}
</div>
</div>
<div class="content">
<div class="search-item">
<div class="text-arabic-section">
<div class="section-header">
<span class="section-title">
{{ props.selectedItem._source.meta.hadith_masoum ?? "بدون عنوان" }}
</span>
<UButton variant="ghost" class="copy-btn" label="کپی" />
</div>
<div class="arabic-text">
<p>بدون متن عربی</p>
</div>
</div>
<div class="separator"></div>
<div class="text-persian-section">
<div class="section-header">
<span class="section-title"> ترجمه </span>
<UButton variant="ghost" class="copy-btn" label="کپی" />
</div>
<p class="from">
{{ props.selectedItem._source.meta.hadith_masoum ?? "بدون عنوان" }}:
</p>
<p
class="persian-text"
v-html="props.selectedItem.highlight['content.fa'] ?? props.selectedItem._source.content"
></p>
</div>
<div class="separator"></div>
<div class="text-description-section">
<div class="section-header">
<span class="section-title"> شرح </span>
<UButton variant="ghost" class="copy-btn" label="کپی" />
</div>
<p
class="description-item"
v-html="props.selectedItem.highlight['content.fa'] ?? props.selectedItem._source.content"
></p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="body-footer">
<div class="mt-5 z-2">
<div class="flex justify-between actions">
<UButton
class="similar-btn"
icon="i-haditha-search-3"
label="مشابه"
color="neutral"
variant="outline"
@click.prevent="goToTheSearch"
/>
<UButton
class="explore-btn"
trailing-icon="i-haditha-explore"
label="کاوش"
variant="solid"
@click.prevent="goToTheChatbot"
/>
</div>
<div class="flex justify-between pagination">
<UButton
class="prev-haditha"
label="حدیث قبل"
color=""
variant="soft"
icon="i-haditha-chevron-right"
/>
<UButton
class="next-haditha"
label="حدیث بعد"
color=""
variant="soft"
trailing-icon="i-haditha-chevron-left"
/>
</div>
</div>
</div>
</div>
</template>
<!-- because of the buttons, using without scoped. -->
<style>
.search-show-modal {
.body-header {
.modal-title {
padding: 0 0.5em 1.5em;
margin-bottom: 2.5em;
.close-btn {
color: var(--ui-color-two);
/* width: 24px; */
/* height: 24px; */
padding: 0.2em;
background-color: transparent;
}
}
}
.body-content {
.header {
.bookmark-btn {
width: 49px;
height: 32px;
gap: 4px;
border-radius: 6px;
border-width: 0.5px;
padding-top: 4px;
padding-right: 12px;
padding-bottom: 4px;
padding-left: 12px;
border: 0.5px solid #d9d9d9;
background: #ffffff;
display: flex;
justify-content: center;
align-items: center;
/* span { */
/* width: 19; */
/* height: 21; */
/* background: #29d985; */
/* } */
}
.referene {
margin-right: 0.5em;
width: 182;
height: 32;
gap: 4px;
border-radius: 6px;
border-width: 0.5px;
padding-top: 4px;
padding-right: 12px;
padding-bottom: 4px;
padding-left: 12px;
background: #ffffff;
border: 0.5px solid #d9d9d9;
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 18px;
letter-spacing: 0%;
text-align: right;
color: #8a92a8;
display: flex;
align-items: center;
span {
margin-left: 0.1em;
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 18px;
letter-spacing: 0%;
text-align: right;
color: #4d00ff;
}
}
}
.content {
height: calc(100dvh - 29em);
overflow-y: auto;
.search-item {
padding: 1em 0 1em 0.1em;
.section-header {
display: flex;
justify-content: space-between;
text-align: right;
margin-bottom: 0.5em;
.section-title {
font-family: IRANSansX;
font-weight: 400;
font-size: 14px;
line-height: 21px;
letter-spacing: 0%;
text-align: right;
/* Fallback color */
color: #4be8ae;
/* Gradient background */
background-image: linear-gradient(
102.02deg,
#4be8ae 7.38%,
#00a762 91.78%
);
/* Clip the background to the text */
background-clip: text;
-webkit-background-clip: text; /* For Safari */
/* Make the text transparent */
color: transparent;
-webkit-text-fill-color: transparent; /* For Safari */
}
.copy-btn {
padding: 0.2em 1em;
/* width: 44px; */
/* height: 24px; */
gap: 4px;
border-radius: 6px;
border-width: 0.5px;
padding-top: 4px;
padding-right: 12px;
padding-bottom: 4px;
padding-left: 12px;
background: #ffffff;
border: 0.5px solid #d9d9d9;
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 18px;
letter-spacing: 0%;
text-align: right;
color: #8a92a8;
}
}
.text-arabic-section {
padding: 2em 0;
.arabic-text {
font-family: Takrim;
font-weight: 400;
font-size: 18px;
line-height: 32px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
margin-bottom: 0.5em;
}
}
.text-persian-section {
padding: 2em 0;
.section-header {
}
.from,
.persian-text {
font-family: Takrim;
font-weight: 400;
font-size: 18px;
line-height: 30px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
}
/* .persian-text {
font-family: Takrim;
font-weight: 400;
font-size: 16px;
line-height: 22px;
letter-spacing: 0%;
text-align: right;
color: #626b84;
margin-bottom: 0.5em;
} */
}
.text-description-section {
padding: 2em 0;
.description-item {
font-family: Takrim;
font-weight: 400;
font-size: 18px;
line-height: 30px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
/*
height: 24px;
gap: 4px;
padding-top: 4px;
padding-right: 8px;
padding-bottom: 4px;
padding-left: 8px;
border-radius: 6px;
border-width: 0.5px;
border: 0.5px solid #d9d9d9;
font-family: IRANSansX;
font-weight: 300;
font-size: 10px;
line-height: 15px;
letter-spacing: 0%;
text-align: right;
color: #8a92a8; */
}
}
.separator {
/* border: 0.5px solid #eee; */
height: 1px;
background-position: center center;
background-size: contain;
background-image: linear-gradient(
90deg,
#ffffff 0%,
#a0f5ff 30.4%,
#3fc9fa 71.47%,
#a7ffe7 100%
);
}
}
}
}
.body-footer {
.actions {
margin-bottom: 1em;
.similar-btn {
width: 114;
height: 56;
gap: 8px;
border-radius: 12px;
border-width: 0.5px;
padding-top: 8px;
padding-right: 20px;
padding-bottom: 8px;
padding-left: 24px;
background: #ffffff;
border: 0.5px solid;
border-image-source: linear-gradient(
102.02deg,
#4be8ae 7.38%,
#00a762 91.78%
);
box-shadow: 0px 8px 20px 0px #0000001a;
font-family: IRANSansX;
font-weight: 400;
font-size: 15px;
line-height: 22.5px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
}
.explore-btn {
width: 118;
height: 56;
gap: 4px;
border-radius: 12px;
padding-top: 8px;
padding-right: 24px;
padding-bottom: 8px;
padding-left: 20px;
background: linear-gradient(268.94deg, #d284ff -0.65%, #4d00ff 104.59%);
box-shadow: 0px 8px 20px 0px #0000001a;
font-family: IRANSansX;
font-weight: 400;
font-size: 16px;
line-height: 24px;
letter-spacing: 0%;
text-align: right;
color: #fff;
}
}
.pagination {
padding: 0.7em 0px;
/* width: 672; */
/* height: 56; */
justify-content: space-between;
border-radius: 16px;
border-width: 0.3px;
padding-right: 32px;
padding-left: 32px;
background: #ffffff;
border: 0.3px solid #e0e0e0;
box-shadow: 0px 8px 20px 0px #0000001a;
.prev-haditha {
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 20px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
}
.next-haditha {
font-family: IRANSansX;
font-weight: 300;
font-size: 12px;
line-height: 20px;
letter-spacing: 0%;
text-align: right;
color: var(--ui-color-two);
}
}
}
}
</style>

View File

@ -1,4 +1,5 @@
<script setup> <script setup>
definePageMeta({ definePageMeta({
layout: false, layout: false,
name: "hadithaSearch", name: "hadithaSearch",
@ -14,9 +15,10 @@ useHead({
}, },
}); });
const img = useImage();
const img = useImage();
const searchQuery = ref(""); const searchQuery = ref("");
const total = ref(0);
const state = reactive({ const state = reactive({
searchList: [], searchList: [],
}); });
@ -45,8 +47,11 @@ const backgroundImageStyle = computed(() => {
const renderContent = (payload) => { const renderContent = (payload) => {
console.info(payload); console.info(payload);
state.searchList = payload.searchList; total.value = payload.res.hits.total.value;
state.searchList = payload.res.hits.hits;
searchQuery.value = payload.searchQuery; searchQuery.value = payload.searchQuery;
}; };
// components declaration // components declaration
@ -85,7 +90,12 @@ const SearchList = defineAsyncComponent(() =>
v-if="searchQuery?.length == 0" v-if="searchQuery?.length == 0"
class="flex justify-center flex-col items-center" class="flex justify-center flex-col items-center"
> >
<NuxtImg fit="auto" quality="80" placeholder src="/img/haditha/logo.png" /> <NuxtImg
fit="auto"
quality="80"
placeholder
src="/img/haditha/logo.png"
/>
<div class="title"> <div class="title">
کاوش با کاوش با
<span class="badge-style"> هوش مصنوعی </span> <span class="badge-style"> هوش مصنوعی </span>
@ -112,6 +122,7 @@ const SearchList = defineAsyncComponent(() =>
<search-list <search-list
no-data-text="نتیجه‌ای یافت نشد!" no-data-text="نتیجه‌ای یافت نشد!"
no-data-icon="/img/haditha/no-data.png" no-data-icon="/img/haditha/no-data.png"
:total="total"
:list="state.searchList" :list="state.searchList"
></search-list> ></search-list>
</div> </div>

View File

@ -1,260 +1,339 @@
export type SummaryOption = { key: string; label: string; type: string }; export interface HadithResponseModel {
export type Filter = { status: number
title: string; message: string
filter_key: string; postion: number
source_key: string; meta: any
by_more: number; took: number
}; timed_out: boolean
export type Summary = { _shards: Shards
title: string; hits: Hits
key: string; aggregations: Aggregations
options: SummaryOption[]; params: Params
}; }
export type Tag = {
قانون: string;
عنوان: string;
متن: string;
ماده: string;
نوع: string;
سال: string;
دسته: string;
مصوب: string;
تاریخ: string;
};
export type Domain = {
label: string;
tag: string;
key: string;
field_collapse: string;
table_actions: TableActions[];
table_columns: TableColumns;
};
export type DomainItem = { export interface Shards {
label: string; total: number
tag: string; successful: number
key: string; skipped: number
field_collapse: string; failed: number
table_actions: TableActions[]; }
table_columns: TableColumns[];
};
export type baseTableAction = { export interface Hits {
title: string; total: Total
key: string; max_score: number
"v-can": string; hits: Hit[]
icon: string; }
type: string;
link_route?: {
id: string;
name: string;
key: string;
};
toggle_icons?: { icon1: string; icon2: string };
};
export type TableActions = [
baseTableAction & {
api_items: {
data_type: string;
ref_key: string;
id: string;
title: string;
};
}
];
export type TableColumnItem = {
key: string;
title: string;
width: string;
textAlign?: string;
isLink?: true;
link_route?: { id: string; name: string; key: string };
trancate_word?: number;
colors?: {
منسوخه: string;
معتبر: string;
موقت: string;
"بااجرامنتفي مي شود": string;
تمديد: string;
آزمايشي: string;
تنفيذ: string;
};
};
export type TableColumns = TableColumnItem[]; export interface Total {
value: number
relation: string
}
export type Advance = { export interface Hit {
key: string; _index: string
label: string; _id: string
tag: string; _score: number
type: string; _source: Source
placeholder: string; highlight: Highlight
labelClass: string; }
inputClass: string;
multi_select: string;
options?: [{ value: string; title: string }];
};
export type SearchType = {
key: string;
description?: string;
label: string;
item?: {
label: string;
type: string;
component: string;
};
};
export type SearchContentActions = {
icon?: "";
title: string;
key: string;
type: string;
"v-can": string;
api_items?: { export interface Source {
data_type: string; id: string
ref_key: string; address: Address
id: string; content: string
title: string; meta: Meta
}; parag_order: number
toggle_icons?: { icon1: string; icon2: string }; style_tag: string
}; heading_level: number
sub_ayehs: any[]
sub_hadithes: any[]
type_key: string
type_title: string
lang: string
tocs: string[]
xml: string
ai_embeddings: number[]
ai_classes: AiClass[]
}
export type Item = { export interface Address {
key: string; book_title: string
source_key: string; page_end: number
label: string; page_num: number
style: string; vol_id: string
process?: string; vol_num: string
vol_title: string
}
link_route?: { export interface Meta {
id: string; hadith_description: string
name: string; hadith_sanad: string
key: string; hadith_references: any[]
}; }
};
export type Items = {
key: string;
items: Item[];
array_key: string;
};
export type SearchContentCollapseItems = { export interface AiClass {
key: string; score: number
items: Items[]; label: string
}; }
export type ListItem = {
title: string;
list_key: string;
filter_key: string;
icon: string;
};
export type List = ListItem[];
// search
export type searchActiveTab = {
key: string;
label: string;
key_navbar:string;
description: string;
routeName: string;
searchContent: string;
showTableList: number;
summary: Summary;
filter: Filter[];
domain: {
tags: Tag;
domain: Domain[] | [];
}|{};
advance: Advance[];
searchType: SearchType[];
search_content: {
actions: SearchContentActions[];
collapse_items: SearchContentCollapseItems;
};
lists: List;
colors_qanon_etebar: {
منسوخه: "red";
معتبر: "green";
موقت: "blue";
"بااجرامنتفي مي شود": "blue";
تمديد: "coral";
آزمايشي: "blue";
تنفيذ: "coral";
};
}| undefined;
export type searchSchema = searchActiveTab[];
export type searchActiveSchema = [];
// search list export interface Highlight {
export type searchChartSchemaItem = { "content.fa": string[]
key: string; xml: string[]
label: string; "ai_classes.label"?: string[]
description: string; "content.ph": string[]
routeName: string; content: string[]
searchContent: string; type_key: string[]
showTableList: number; }
summary: Summary;
filter: Filter[];
search_content: {
actions: SearchContentActions[];
collapse_items: SearchContentCollapseItems;
};
info: {
title: string;
index_name: string;
meta: string;
table_columns: string;
table_columns_subject: string;
entity_view: string;
lists: [];
items: [{ name: string; title: string }];
};
actions: TableActions;
items: searchListActiveTab[];
};
export type searchListActiveTabItem = { export interface Aggregations {
key: string; book_title: BookTitle
id: number; ai_classes: AiClasses
url_GET_item: string; ai_keywords: AiKeywords
key_filter: string; vol_title: VolTitle
label: string; type_title: TypeTitle
}; lang: Lang
export type searchListActiveTab = { }
key: string;
label: string;
field_collapsed: string;
items: searchListActiveTabItem[];
};
export type searchListSchema = searchChartSchemaItem[]; export interface BookTitle {
export type activeSearchListSchema = searchChartSchemaItem; doc_count_error_upper_bound: number
sum_other_doc_count: number
buckets: Bucket[]
}
// search chart export interface Bucket {
export type searchChartActiveTab = { key: string
key: string; doc_count: number
componentName: string; }
label: string;
chartBase: {
key: string;
label: string;
items: [{ key: string; label: string }];
};
};
export type searchChartSchema = activeSearchChartSchema[];
export type activeSearchChartSchema = searchActiveTab & {
items: searchChartSchemaItem[];
};
export type searchSynonymTitle = {}; export interface AiClasses {
export type searchSynonymForm = []; doc_count_error_upper_bound: number
export type selectionFilterItems = []; sum_other_doc_count: number
buckets: Bucket2[]
}
export type helpSchema = helpActiveSchema[]; export interface Bucket2 {
export type helpActiveSchema = { key: string
key: string; doc_count: number
label: string; }
title: string;
comment: string; export interface AiKeywords {
}; doc_count_error_upper_bound: number
export type DomainActive = Domain; sum_other_doc_count: number
buckets: Bucket3[]
}
export interface Bucket3 {
key: string
doc_count: number
}
export interface VolTitle {
doc_count_error_upper_bound: number
sum_other_doc_count: number
buckets: Bucket4[]
}
export interface Bucket4 {
key: string
doc_count: number
}
export interface TypeTitle {
doc_count_error_upper_bound: number
sum_other_doc_count: number
buckets: Bucket5[]
}
export interface Bucket5 {
key: string
doc_count: number
}
export interface Lang {
doc_count_error_upper_bound: number
sum_other_doc_count: number
buckets: Bucket6[]
}
export interface Bucket6 {
key: string
doc_count: number
}
export interface Params {
index: string
body: Body
}
export interface Body {
query: Query
from: string
size: string
aggs: Aggs
highlight: Highlight2
}
export interface Query {
bool: Bool
}
export interface Bool {
must: Must[]
}
export interface Must {
bool: Bool2
}
export interface Bool2 {
should?: Should[]
filter?: Filter
}
export interface Should {
match_phrase?: MatchPhrase
match?: Match
bool?: Bool3
}
export interface MatchPhrase {
"content.ph": ContentPh
}
export interface ContentPh {
query: string
boost: number
}
export interface Match {
"content.fa"?: ContentFa
content?: Content
"content.ar"?: ContentAr
}
export interface ContentFa {
query: string
boost: number
}
export interface Content {
query: string
boost: number
}
export interface ContentAr {
query: string
boost: number
}
export interface Bool3 {
must: Must2[]
}
export interface Must2 {
match: Match2
}
export interface Match2 {
book_title: BookTitle2
}
export interface BookTitle2 {
query: string
boost: number
}
export interface Filter {
bool: Bool4
}
export interface Bool4 {
must: Must3[]
}
export interface Must3 {
term: Term
}
export interface Term {
type_key: string
}
export interface Aggs {
book_title: BookTitle3
ai_classes: AiClasses2
ai_keywords: AiKeywords2
vol_title: VolTitle2
type_title: TypeTitle2
lang: Lang2
}
export interface BookTitle3 {
terms: Terms
}
export interface Terms {
field: string
size: number
}
export interface AiClasses2 {
terms: Terms2
}
export interface Terms2 {
field: string
size: number
}
export interface AiKeywords2 {
terms: Terms3
}
export interface Terms3 {
field: string
size: number
}
export interface VolTitle2 {
terms: Terms4
}
export interface Terms4 {
field: string
size: number
}
export interface TypeTitle2 {
terms: Terms5
}
export interface Terms5 {
field: string
size: number
}
export interface Lang2 {
terms: Terms6
}
export interface Terms6 {
field: string
size: number
}
export interface Highlight2 {
pre_tags: string[]
post_tags: string[]
fields: Fields
require_field_match: boolean
fragment_size: number
number_of_fragments: number
boundary_scanner: string
}
export interface Fields {
"*": GeneratedType
}
export interface GeneratedType {}