تغییرات برای جستجو

This commit is contained in:
Mehdi104797 2025-02-26 16:31:22 +03:30
parent 9a5f23287f
commit 6d8478f019
12 changed files with 585 additions and 30 deletions

15
apis/favoriteApi.js Normal file
View File

@ -0,0 +1,15 @@
export default {
favorite: {
add: "favorite/add/{{data_type}}/{{ref_key}}",
delete: "favorite/delete/{{data_type}}/{{id}}", //id = portal_meet_22569
deleteByRefid: "favorite/delete/{{data_type}}/{{index_key}}/{{ref_id}}", //id = portal_meet_22569
// getListSearch: "favorite/list/{{data_type}}/{{offset}}/{{limit}}", //offset=0 , limit=10
// counts: "favorite/counts/@data_type", // get
setFavoritesCat: "favorite/tags/@data_type/set/doc/@id",
getCategories: "favorite/tags/@data_type/get",
setCategories: "favorite/tags/@data_type/set",
getCounts: "favorite/tags/@data_type/counts",
getList: "favorite/list/@data_type/@offset/@limit/@filter",
},
};

24
apis/researchApi.js Normal file
View File

@ -0,0 +1,24 @@
export default {
admin: {
list: "",
show: "",
edit: "",
update: "",
delete: "",
},
research:{
listDefault:"research/search/{{user_id}}/{{offset}}/{{limit}}",
listBySearch:"research/search/{{user_id}}/{{offset}}/{{limit}}/q=",
deleteItem: "/public/{{index_key}}/delete/{{id}}", //ایدی فیش و یا حاشیه
},
subject: {
move: 'subject/order/move/parent',
order: 'subject/order/move/one',
list: 'list/subject/list',
add: 'list/subject/add',
edit: 'list/subject/edit',
delete: 'list/subject/delete',
order: 'list/subject/order',
},
};

View File

@ -373,11 +373,11 @@
</template>
<script>
import searchApis from "~/apis/searchApi";
import searchApis from "@search/apis/searchApi";
import adminApi from "~/apis/adminApi";
import settingsApi from "~/apis/settingsApi";
import { mapState, mapActions } from "pinia";
import stopWordContextMenu from "~/json/entity/stopWordContextMenu";
import stopWordContextMenu from "@search/json/entity/stopWordContextMenu";
import { useEntityStore } from "@search/stores/entityStore";
/**

View File

@ -62,11 +62,11 @@
import repoApi from "~/apis/repoApi";
import { mapActions, mapState } from "pinia";
import { useSearchStore } from "~/stores/searchStore";
import { useSearchStore } from "@search/stores/searchStore";
import { useCommonStore } from "~/stores/commonStore";
import { useEntityStore } from "@search/stores/entityStore";
import entityTextMixin from "~/mixins/entity/entityTextMixin";
import entityTextMixin from "@search/mixins/entity/entityTextMixin";
/**
* @vue-prop {String} [propText=""] - مقدار متنی که به عنوان ورودی به کامپوننت داده میشود.
* @vue-data {String} [httpService=undefined] - محل قرارگیری آدرس URL سرویس HTTP.

View File

@ -0,0 +1,192 @@
<template>
<div class="form-group" :key="$attrs.name">
<div class="d-flex switch-main">
<div class="custom-control custom-switch">
<input
type="checkbox"
@change="updateMode"
:id="$attrs.name"
:name="$attrs.name"
v-model="textValue"
:true-value="true"
:false-value="false"
class="custom-control-input"
/>
<label class="custom-control-label" :for="$attrs.name">{{
$t(text1)
}}</label>
</div>
<label class="mb-0 mr-2 text-2" :for="$attrs.name">{{ $t(text2) }}</label>
</div>
</div>
</template>
<script>
import formBuilderMixin from "~/extensions/formBuilderExtension.js";
/**
* @vue-prop {string} [texts2 = Statistics] - متنی که برای نمایش به عنوان "ChartList" استفاده میشود.
* @vue-prop {string} [texts1 = Normal] - متنی که برای نمایش به عنوان "Chart" استفاده میشود.
*
* @vue-data {boolean} [textValue = true] - حالت انتخاب شده ی سوئیچ در حالت true فعال و در حالت false غیر فعال می باشد
* @vue-data {String} [text1 = ""] - متن اول که در برچسب اول نمایش داده میشود.
* @vue-data {String} [text2 = ""] - متن دوم که در برچسب دوم نمایش داده میشود.
*/
export default {
extends: formBuilderMixin,
// props: ["texts1", "texts2"],
props: {
texts2: {
default: "Statistics",
},
texts1: {
default: "Normal",
},
value: {
default: true,
},
},
data() {
return {
textValue: true,
text1: "Chart",
text2: "ChartList",
};
},
mounted() {
this.textValue = this.value;
this.updateText();
},
methods: {
/**
* متنهای پراپها را به متغیرهای اختصاص میدهد.
* اگر texts1 تعریف شده باشد، مقادیر text1 و text2 را به ترتیب با texts1 و texts2 جایگزین میکند.
*/
updateText() {
if (this.texts1 !== undefined) {
this.text1 = this.texts1;
this.text2 = this.texts2;
}
},
/**
* رویداد تغییر وضعیت چکباکس را مدیریت میکند.
* مقدار جدید textValue را از طریق رویداد "change-mode" به والد کامپوننت ارسال میکند.
*/
updateMode() {
this.$emit("change-mode", this.textValue);
},
},
};
</script>
<style scoped lang="scss">
.custom-control-label {
white-space: nowrap;
&::before {
border-color: var(--primary-color) !important ;
// background-color: var(--primary-color)!important;
}
}
.entity-text-switch {
.switch-main {
justify-content: end;
margin-left: 3em;
}
.custom-control-input {
width: 5em;
z-index: 99;
}
}
.custom-control {
.custom-control-input {
&:checked ~ .custom-control-label::before {
background-color: var(--primary-color);
}
}
}
.task-admin-switch {
&.form-group {
margin-bottom: 0 !important;
margin-top: 1em;
margin-right: 1em;
}
.custom-control-label {
&::before {
border-color: #fff;
background-color: rgb(135, 255, 249);
}
&::after {
background-color: #fff;
}
}
}
.compare-switch {
.custom-control-label {
&::before {
border-color: #fff;
background-color: rgb(135, 255, 249);
}
&::after {
background-color: #fff;
}
}
}
.text-2 {
white-space: nowrap;
}
/* .form-control {
height: auto !important;
} */
/*
.checkbox-4 {
width: 100px;
appearance: none;
height: 40px;
border-radius: 100px;
cursor: pointer;
background: #ffffff;
position: relative;
background: #e0e5ec;
box-shadow: 4px 4px 6px 0 rgba(255, 255, 255, 0.3),
-4px -4px 6px 0 rgba(116, 125, 136, 0.2),
inset -4px -4px 6px 0 rgba(255, 255, 255, 0.2),
inset 4px 4px 6px 0 rgba(0, 0, 0, 0.2);
transition: all 0.5s;
}
.checkbox-4::after {
content: "";
width: 30px;
height: 30px;
position: absolute;
left: 8px;
top: 5px;
border-radius: 100%;
background-color: #ffffff;
box-shadow: inset 2px 2px 2px 0px rgba(255, 255, 255, 0.5),
7px 7px 20px 0px rgba(0, 0, 0, 0.1), 4px 4px 5px 0px rgba(0, 0, 0, 0.1);
transition: all 0.5s;
}
.checkbox-4:checked::after {
left: 65px;
}
.checkbox-4-pink:checked {
background: #fb2175;
}
.checkbox-4-danger:checked {
background: var(--danger);
}
.checkbox-4-success:checked {
background: var(--success);
}
.checkbox-4-info:checked {
background: var(--info);
}
.checkbox-4-dark:checked {
background: #1a1a1a;
}
.checkbox-4-magic:checked {
background: var(--magic);
} */
</style>

View File

@ -0,0 +1,178 @@
<template>
<div class="advanced-search firefox-scrollbar">
<div class="container-fluid">
<div class="row">
<div class="col-12">
<form>
<component
v-for="(formElement, index) in localFormElements"
:key="index"
:formElement="getValueToFormElement(formElement)"
:inputClass="formElement.inputClass"
:labelClass="formElement.labelClass"
:is="returnComponentName(formElement.type)"
@tribute-on-search="remoteSearch"
@oninput="createQuery($event, index)"
class="inside-advanced-search"
></component>
<div class="d-flex justify-content-end align-items-baseline">
<div class="bottom-close-form ms-3">
<a @click.prevent="closeAdvancedSearch">بستن</a>
</div>
<div class="bottom-save-form">
<button
type="submit"
class="btn btn-primary"
style="font-size: 11px; height: 3em; width: 7em"
@click.prevent="searchStart()"
>
جستجو
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import { useResearchStore } from "../../../stores/researchStore";
import { mapState } from "pinia";
export default {
data() {
return {
listUpdatedText: {},
localFormElements: [],
value: "",
};
},
computed: {
...mapState(useSearchStore, ["searchActiveTabGetter"]),
...mapState(useResearchStore, ["researchSchemaGetter"]),
},
watch: {
researchSchemaGetter: {
handler: function (newSchema) {
if (newSchema[0].advance)
this.localFormElements = structuredClone(newSchema[0].advance);
},
// deep: true,
immediate: true,
},
},
beforeMount() {
this.httpService = new HttpService(import.meta.env.VITE_BASE_URL);
},
mounted() {
this.localFormElements = structuredClone(
this.researchSchemaGetter[0].advance
);
},
methods: {
closeAdvancedSearch() {
this.$emit("closeAdvancedSearch");
},
remoteSearch({ text, cb, item }) {
// for clearing the query when user remove by keyboard backspace.
if (text == "") this.makeSearchParams(undefined, 1);
let url = item.completion;
text = text.trim();
url = url.replace("{{key}}", this.researchSchemaGetter[0].key);
if (text == "") url = url.replace("/{{query}}", "");
else url = url.replace("{{query}}", text);
this.httpService.getRequest(url).then((response) => {
cb(response.data);
});
},
getValueToFormElement(elements) {
Object.keys(elements).forEach((key, index) => {
elements["value"] = this.researchSchemaGetter[0][elements.key];
});
return elements;
},
saveComponentValue(value, formElement) {
// در صورت تغییر نگهداری می شود تا وقتی کلید ثبت زد، ذخیره شود
if (this.researchSchemaGetter[0][formElement.key] != value) {
this.listUpdatedText[formElement.key] = value;
}
},
returnComponentName(type) {
// if(!this.isEditable(searchActiveTabGetter?.key))
// return "LabelComponent";
if (type == "select") return "SelectComponent";
else if (type == "range_date") return "RangeDateComponent";
else if (type == "completion") return "TributeComponent";
else return "InputComponent";
},
// این لازم نیست و استفاده نداره!!!!!
// saveProperty() {
// let id = this.$route.params.id;
// let key = this.$route.params.key;
// let formData = {
// id: id,
// meta: JSON.stringify(this.listUpdatedText),
// };
// let url = "/public/{{index_key}}/update/{{id}}";
// url = url.replace("{{index_key}}", key).replace("{{id}}", id);
// this.httpService.postRequest(url, formData).then((res) => {
// this.getServerItem();
// });
// },
createQuery(evt, index) {
// evt.target.value => from input component.
//evt => from datetime component.
let value = evt?.target?.value ?? evt;
this.$emit("set-query-advanced", this.makeSearchParams(value, index));
},
makeSearchParams(value, index) {
if (value != undefined) this.localFormElements[index].value = value;
else this.localFormElements[index].value = undefined;
let query = "";
this.localFormElements.forEach((item, rowIndex, array) => {
if (item.value?.length)
query += "#" + item.tag + " " + item.value + " ";
});
return query;
},
searchStart() {
this.$emit("searchStart", this.searchStartValue());
},
searchStartValue() {
let query = "";
this.localFormElements.forEach((item, rowIndex, array) => {
if (item.value?.length)
query += "#" + item.tag + " " + item.value + " ";
});
return myEncodeQuery(query);
},
myEncodeQuery(text) {
let ch1 = encodeURIComponent("#");
let ch2 = encodeURIComponent("/");
let ch3 = encodeURIComponent("\\");
// let ch4 = encodeURIComponent(".");
text = text.replaceAll("#", ch1);
text = text.replaceAll("/", "\\");
text = text.replaceAll("\\", ch3);
// text = text.replaceAll(".", '%2E');
return text;
},
},
};
</script>

View File

@ -399,13 +399,14 @@
<script>
// import HttpService from "@services/httpService";
// import tableActions from "@search/json/listTableContextMenu";
import favoriteApi from "~/apis/favoriteApi";
import researchApi from "~/apis/researchApi";
import favoriteApi from "@search/apis/favoriteApi";
import researchApi from "@search/apis/researchApi";
import { mapState, mapActions } from "pinia";
import { useSearchStore } from "~/stores/searchStore";
// import { useResearchStore } from "@search/stores/researchStore";
import { useSearchStore } from "@search/stores/searchStore";
import { useEntityStore } from "@search/stores/entityStore";
import { useAuthStore } from "~/stores/authStore";
export default {
props: {
@ -476,8 +477,8 @@ export default {
};
},
computed: {
// ...mapState(useResearchStore, ["searchActiveTabGetter"]),
...mapState(useSearchStore, ["searchActiveTabGetter"]),
...mapState(useAuthStore, ["isRealUser"]),
},
methods: {
...mapActions(useEntityStore, ["SET_ITEM_ENTITY", "SET_LIST_ENTITY"]),
@ -713,7 +714,8 @@ export default {
}
this.$router.push({
path: `/search/${key}/${valueId}`,
name:'showEntity',
// path: `/search/${key}/${valueId}`,
params: {
id: valueId,
key: key,
@ -732,7 +734,7 @@ export default {
},
showTextPage(event) {},
async deleteResearch(item) {
this.mySwalConfirm({
mySwalConfirm({
title: "هشدار!!!",
html: `از حذف <b>${item._source.text_subject}</b> اطمینان دارید؟ `,
icon: "warning",
@ -749,7 +751,7 @@ export default {
method: "post",
});
this.mySwalToast({
mySwalToast({
html: res.message,
});
setTimeout(() => {

View File

@ -16,7 +16,8 @@
<script>
import { mapState } from "pinia";
import { useSearchStore } from "~/stores/searchStore";
// import { useSearchStore } from "~/stores/searchStore";
// import { useSearchStore } from "@search/stores/searchStore";
export default {
props: {
filters: {
@ -32,7 +33,7 @@ export default {
},
},
computed: {
...mapState(useSearchStore, ["selectionFilterItemsGetter"]),
// ...mapState(useSearchStore, ["selectionFilterItemsGetter"]),
},
};
</script>

View File

@ -129,7 +129,7 @@
<script>
import { mapState, mapActions } from "pinia";
import { useEntityStore } from "@search/stores/entityStore";
import { useSearchStore } from "~/stores/searchStore";
import { useSearchStore } from "@search/stores/searchStore";
/**
*
* @vue-prop {Array} [listAggregations=[]] - یک آرایه حاوی جمعبندیهای لیست.

View File

@ -1,5 +1,5 @@
<template>
<NuxtLayout name="search-layout" :menu="sidbarMenu">
<SearchLayout :menu="sidbarMenu">
<!-- <Head> -->
<!-- <Title>{{ metaTitle }}</Title> -->
<!-- <Meta name="description" :content="title" /> -->
@ -421,7 +421,7 @@
<!-- #endregion -->
</div>
</div>
</NuxtLayout>
</SearchLayout>
</template>
<script>
@ -1688,6 +1688,9 @@ export default {
DraftImportEffectModal: defineAsyncComponent(() =>
import("@search/components/entity/modals/DraftImportEffectModal.vue")
),
SearchLayout: defineAsyncComponent(() =>
import("@search/layouts/SearchLayout.vue")
),
},
};
</script>

View File

@ -795,7 +795,7 @@ import { mapActions, mapState } from "pinia";
import { useSearchStore } from "@search/stores/searchStore";
import { useCommonStore } from "~/stores/commonStore";
import searchApi from "@search/apis/searchApi.js";
import searchApi from "@search/apis/searchApi";
import adminApi from "~/apis/adminApi";
import sidbarMenuDefault from "@search/json/search/menu.json";
@ -960,6 +960,7 @@ export default {
// showFilter: false,
ismultiWord: false,
showButton: false,
showSummary: false,
// topRepeatInListMode: true,
iscode: false,
lastSearchInListMode: true,
@ -1035,7 +1036,6 @@ export default {
computed: {
...mapState(useSearchStore, [
"domainActiveGetter",
"searchActiveTabGetter",
"searchSchemaGetter",
"searchSynonymTitleGetter",
@ -1045,6 +1045,7 @@ export default {
"organNameGetter",
"isSidebarCollapsed",
"userPermisionGetter",
"domainActiveGetter",
]),
// metaTitle() {
// return import.meta.env.VITE_SEARCH_PAGE_TITLE;
@ -1162,14 +1163,35 @@ export default {
...mapActions(useCommonStore, [
"TOGGLE_SIDEBAR_MENU",
"sidebarCollapsedSetter",
"domainActiveSetter",
]),
...mapActions(useSearchStore, [
"searchActiveTabSetter",
"searchSchemaSetter",
"domainActiveSetter",
"searchSynonymTitleSetter",
]),
initComponent() {
let activeItem = this.searchSchemaGetter[0];
if (this.$route.query.key) {
let key = this.$route.query.key;
activeItem = this.searchSchemaGetter?.find((item) => item.key === key);
}
this.searchActiveTabSetter(activeItem);
if (this.$route.query.q) {
this.setInputText(this.$route.query.q);
}
setTimeout(() => {
this.searchStart(this.textSearch);
// if (this.textSearch != undefined && this.textSearch != "") {
// this.searchStart(this.textSearch);
// } else {
// this.getDefaultByFilter();
// }
}, 500);
},
setMode(item) {
this.mode = item;
},
@ -1197,7 +1219,8 @@ export default {
* @param {string} value.domain[].key - کلید دامنه.
*/
setSearchDomain(value) {
this.searchDomain = value.domain.domain;
this.searchDomain = value.domain?.domain;
if (this.searchDomain == undefined) return;
let update = false;
if (this.searchDomain && this.searchDomain[0].key != "all") {
@ -1211,8 +1234,7 @@ export default {
// this.searchDomain = [...this.searchDomain, ...value.domain.domain];
}
// if (update || !this.domainActiveGetter)
{
if (update || !this.domainActiveGetter) {
if (isMajlesBuild()) this.domainActiveSetter(this.searchDomain[1]);
else this.domainActiveSetter(this.searchDomain[0]);
}
@ -2056,3 +2078,107 @@ export default {
},
};
</script>
<style scoped lang="scss">
.synonym-queries {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #fff;
z-index: 99;
padding: 0.5em 1em;
display: flex;
align-items: center;
span {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: auto;
}
}
.v-popper--theme-dropdown {
display: flex;
.v-popper__inner {
.my-tooltip-content {
color: white;
background-color: black;
padding: 1em;
}
}
}
.synonym-btn {
&.show-active {
position: relative;
&::before {
content: "";
display: inline-block;
position: absolute;
top: 0;
right: -0.3em;
width: 1em;
height: 1em;
border-radius: 50%;
background-color: green;
}
}
}
.container {
width: 100%;
max-width: 100em;
}
.filterlist {
box-shadow: 0 0.4688rem 2.1875rem rgba(4, 9, 20, 0.03),
0 0.9375rem 1.4063rem rgba(4, 9, 20, 0.03),
0 0.25rem 0.5313rem rgba(4, 9, 20, 0.03),
0 0.125rem 0.1875rem rgba(4, 9, 20, 0.03);
}
.nav-tabs {
border-bottom: unset !important;
}
.search-page__result {
li {
&:hover {
background-color: #d8f8fd !important;
}
}
}
.my-dropdown {
.dropdown-toggle {
background-color: #fff !important;
display: flex;
justify-content: space-between;
border: 1px solid var(--primary-color) !important;
&-color {
// width: 21em;
height: 2.5em;
border-radius: 0.5em !important;
}
&::after {
margin: unset !important;
}
}
.dropdown-menu {
min-width: 100%;
border-radius: var(--bs-dropdown-border-radius);
margin-top: unset;
}
.input-group-text {
background-color: #fff !important;
}
}
.dropdown-menu {
min-width: 100%;
}
.switch-with-icon {
align-items: flex-end;
}
.offcanvas-title {
font-family: sahel-semi-bold;
}
</style>

View File

@ -1,4 +1,5 @@
import type {
ActiveEntityViewSchema,
activeResearchType,
ActiveTab,
EntityViewSchema,
@ -21,6 +22,7 @@ export const useEntityStore = defineStore("entityStore", {
"activeTab",
"isReadingMode",
"entityViewSchema",
"activeEntityViewSchema",
"qruleActiveTab",
"qruleSchema",
@ -31,9 +33,11 @@ export const useEntityStore = defineStore("entityStore", {
],
},
state: () => ({
activeTab: undefined as ActiveTab | undefined,
entityViewSchema: undefined as EntityViewSchema | undefined,
selectedItemEntity: undefined as SelectedItemEntity | undefined,
listEntity: undefined as ListEntity | undefined,
activeEntityViewSchema: undefined as ActiveEntityViewSchema | undefined,
similarInfo: {} as SimilarInfo | undefined,
vuexEntity: undefined, //پیدا نکردم
qruleActiveSchema: undefined as qruleActiveTabGetter | undefined,
@ -100,7 +104,9 @@ export const useEntityStore = defineStore("entityStore", {
entityViewSchemaGetter(state) {
return state.entityViewSchema;
},
activeTabGetter(state) {
return state.activeTab;
},
qruleActiveTabGetter(state) {
return state.qruleActiveTab;
},
@ -113,6 +119,9 @@ export const useEntityStore = defineStore("entityStore", {
listEntityGetter(state) {
return state.listEntity;
},
activeEntityViewSchemaGetter(state) {
return state.activeEntityViewSchema;
},
fontSizeGerrer(state) {
return state.fontSize;
},
@ -174,7 +183,9 @@ export const useEntityStore = defineStore("entityStore", {
entityViewSchemaSetter(entityViewSchema = undefined) {
this.entityViewSchema = entityViewSchema;
},
activeEntityViewSchemaSetter(activeEntityViewSchema = undefined) {
this.activeEntityViewSchema = activeEntityViewSchema;
},
qruleActiveTabSetter(qruleActiveTab = undefined) {
this.qruleActiveTab = qruleActiveTab;
},
@ -184,15 +195,18 @@ export const useEntityStore = defineStore("entityStore", {
qruleActiveSchemaSetter(qruleActiveSchema = undefined) {
this.qruleActiveSchema = qruleActiveSchema;
},
activeTabSetter(activeTab = undefined) {
this.activeTab = activeTab;
},
SET_ITEM_ENTITY(item) {
SET_ITEM_ENTITY(item=undefined) {
this.selectedItemEntity = item;
},
SET_LIST_ENTITY(list) {
SET_LIST_ENTITY(list=undefined) {
this.listEntity = list;
},
SET_FONT(fontSize) {
SET_FONT(fontSize=undefined) {
this.fontSize = fontSize;
},
// SET_QUERY( queryParams) {
@ -201,10 +215,10 @@ export const useEntityStore = defineStore("entityStore", {
SET_ITEM_LIST_SELECTED_ID(itemListIdSelected) {
this.itemListIdSelected = itemListIdSelected;
},
SET_STATUS_BUTTON(statusButton) {
SET_STATUS_BUTTON(statusButton = undefined) {
this.statusButton = statusButton;
},
SET_STATUS_ENTITY_VIEWPAGE(statusEntityViewPage) {
SET_STATUS_ENTITY_VIEWPAGE(statusEntityViewPage=undefined) {
this.statusEntityViewPage = statusEntityViewPage;
},
SET_STATUS_REMOVE_CHECKBOX(statusRemovCheckBox) {