search_ui/components/entity/components/EntityQModelSimilar.vue
2025-02-01 14:36:10 +03:30

478 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="mb-2">
<div class="container-fluid similar-section firefox-scrollbar">
<div class="row mt-2 main-similar justify-content-center">
<!-- border-similar remov -->
<div
class="col-12 d-flex my-2 content"
v-for="(item, index) in listSimilar"
:key="index"
>
<div class="row d-flex flex-column border-bottom pb-2 ">
<div class="d-flex align-items-center link-similar">
<button-component
title="کپی لینک"
buttonText=""
classes="color-1 "
@click="copyToClipboard()"
>
<svg class="icon icon-copy2">
<use xlink:href="#icon-copy2"></use>
</svg>
</button-component>
<div class="">
<router-link
:to="{ name: 'searchResult' }"
class="text-title-QSection1"
>قوانین</router-link
>
<span class="me-2"></span>
<a
class="text-title-QSection2"
:href="urlResolver(item._source.qanon_id, 'qasection')"
target="_blank"
>
{{ item._source.qanon_title }}
</a>
<span class="me-2 ms-2"></span>
<a
class="text-title-QSection2"
v-if="item._source.other_info?.full_path"
:href="getDetailUrl(item)"
target="_blank"
>{{ item._source.other_info.full_path }}</a
>
</div>
</div>
<div class="d-flex me-5 date-content">
<span class="" v-if="item._source.ts_ref" style="color: #4b5567"
><span class="text__dark-gray">مرجع تصویب :</span>
{{ item._source.ts_ref }}</span
>
<span
class="me-2"
v-if="item._source.ts_date"
style="color: #4b5567"
><span class="text__dark-gray">تاریخ تصویب :</span>
{{ item._source.ts_date }}</span
>
</div>
<div v-html="getSimilarHtml(item)" class="me-5 mt-2 ms-2 list-similar"></div>
</div>
</div>
</div>
</div>
<jahat-Pagination
:paginationInfo="pagination"
@page-changed="pageChanged"
@page-limit-changed="pageLimitChanged"
@sort-changed="sortChanged"
></jahat-Pagination>
</div>
</template>
<script>
import { mapState, mapActions } from "pinia";
import entityApi from "~/apis/entityApi";
import searchApi from "~/apis/searchApi";
const Diffcomponent = require("diff");
export default {
props: {
bmCurrentItemEntity: {
default: "",
},
currentSchemaEntityContent: {
type: Object,
default() {
return {};
},
},
},
beforeMount() {
this.httpService = useNuxtApp()["$http"];
},
mounted() {
this.similarStart();
this.getSimilar();
},
data() {
return {
httpService: undefined,
listSimilar: [],
pagination: {
page: 1,
pages: 0,
total: 0,
offset: 0, // page * per_page
limit: 10, //per_page
},
};
},
computed: {
...mapState("entity", [
"entityViewSchemaGetter",
"activeEntityViewSchemaGetter",
"similarInfoGetter",
]),
},
methods: {
...mapActions("entity", ["similarInfoSetter"]),
getSimilarHtml(item) {
let res = [];
if (item["highlight"]["rules.text"])
res = item["highlight"]["rules.text"];
if (item["highlight"]["rules_logics.text"])
res = item["highlight"]["rules_logics.text"];
if (item["highlight"]["rules_logics_triples.text"])
res = item["highlight"]["rules_logics_triples.text"];
let result = "";
res.forEach((el) => {
if(result != "")
result += "<br>"
result += '<span class="similar-text">' + el + "</span>";
});
return result;
},
similarStart() {
// let sm = smObject ? smObject : this.similarInfoGetter;
let sm = this.similarInfoGetter;
// console.log(sm);
if (sm?.text || sm?.id) {
if (sm?.type == "vector") this.getVectorSimilar(sm.text, sm.id);
else this.getSimilar(sm.text, sm.id);
}
},
/**
* ساخت نشانی پیوند انتقال به جزئیات هر بخش قانون.
* @param {Object} item - شیء اصلی.
*/
getDetailUrl(item) {
let key = "";
key = this.myKey;
if (!key) key = "qasection"; // برای شرایطی که بصورت مدال استفاده می شود گتر بالا پر نیست
let id = item._id;
let hash = "";
hash = "#qmodel";
key = "qsection";
id = item._source?.ref_id ? item._source.ref_id : id;
if (key == "qasection") {
key = "qsection";
}
let name = "detail";
const routeData = this.$router.resolve({
name: name,
params: {
id: id,
key: key,
},
hash: hash,
query: {},
});
return routeData.href;
},
getSimilar(text, id = undefined) {
let url = repoUrl()+entityApi.similar.textual;
url = url.replace("{{index_key}}", "qmodel");
url = url.replace("{{field}}", this.currentSchemaEntityContent.key +"__text");
url = url.replace("{{offset}}", this.pagination.offset);
url = url.replace("{{limit}}", this.pagination.limit);
const payload = {
text: this.bmCurrentItemEntity.text,
};
// url = url.replace("/q={{text}}", "");
this.httpService.postRequest(url, payload).then((res) => {
this.listSimilar = res.hits.hits;
// PAGA
const total = res.hits.total.value;
const pages = Math.ceil(total / this.pagination.limit);
const pagination = {
total: total,
pages: pages == 0 ? 1 : pages,
};
this.pagination = { ...this.pagination, ...pagination };
});
},
pageLimitChanged(paging) {
this.resetPagination();
this.pagination.limit = paging.limit;
this.getSimilar();
},
pageChanged(paging) {
let page = paging.pageNumber;
page -= 1;
this.pagination.offset = page * paging.limit;
this.pagination.limit = paging.limit;
this.pagination.page = paging.pageNumber;
this.getSimilar();
},
sortChanged(sorting) {
this.pagination.page = this.pagination.offset = 0;
this.sorting = sorting;
this.getSimilar();
},
resetPagination() {
this.pagination = {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
};
},
getVectorSimilar(text, id = undefined) {
// console.log("getRequestSimilar", text);
// let url = entityApi.similar.vector;
// url = url.replace("{{index_key}}", "qmodel");
// url = url.replace("{{sort_state}}", "searchsort");
// url = url.replace("{{offset}}", 0);
// url = url.replace("{{limit}}", 10);
let url = repoUrl()+searchApi.search.queryNormal;
url = url.replace("{{appname}}", buildName());
url = url.replace("{{index_key}}", "qmodel");
url = url.replace("{{search_type}}", "vector");
url = url.replace("{{sortKey}}", "searchsort");
url = url.replace("{{field_collapse}}", this.activeEntityViewSchemaGetter?.field_collapse);
url = url.replace("{{offset}}", 0);
url = url.replace("{{limit}}", 10);
url = url.replace("/{{filter}}", "");
const payload = {
text: text,
id: id,
};
this.httpService.postRequest(url, payload).then((res) => {
this.listSimilar = res.hits.hits;
});
},
similarHandler(key, list) {
return list[key];
},
similarHref(key, list) {
return this.urlResolver(list._source.qanon_id, "qmodel");
// if (key == "qanon_title")
// return this.urlResolver(list._source?.qanon_id, "mqanon");
// else return this.urlResolver(list._id, "mqsection");
},
closedSimiler() {
this.$emit("setShowSimilar", false);
// let sm = this.similarInfoGetter;
// sm.show = false;
// this.similarInfoSetter(sm);
},
normalizdPersain(text) {
text = text.replaceAll("ي", "ی");
text = text.replaceAll("ك", "ک");
text = text.replaceAll("ة", "ه");
// text = text.replaceAll(/[ىی]/g, 'ي');
return text;
},
similarDiff(newText, oldText = undefined) {
let diffType = "diffWords"; // تعریف متغیر diffType
let resText; // تعریف متغیر resText
oldText = oldText ? oldText : this.similarInfoGetter?.text;
oldText = this.normalizdPersain(oldText);
newText = this.normalizdPersain(newText);
const extractedDifferences = Diffcomponent[diffType](oldText, newText);
let res = extractedDifferences;
resText = this.makeCorrectedText(res);
return resText;
},
makeCorrectedText(extractedDifferences) {
var newItem = "";
// var result = diff(good, bad);
// [[-1, "Goo"], [1, "Ba"], [0, "d dog"]]
// -1 : removed
// 0 : no change
// 1 : added change
let i = 0;
for (i = 0; i < extractedDifferences.length; i++) {
var diffItem = extractedDifferences[i];
// var diffItem1 = p2e(diffItem[1]);
// var diffItem1 = diffItem[1]?.value;
// if (!diffItem1) continue;
if (!diffItem.added && !diffItem.removed) {
newItem += diffItem.value;
} else {
if (diffItem.removed) {
newItem += `<a target="_blank" class="removed-change">${diffItem.value}</a>`;
} else if (diffItem.added) {
newItem += `<a target="_blank" class="added-change">${diffItem.value}</a>`;
}
}
}
return newItem;
},
// urlResolver(_parent, key = "") {
// if (key == "") key = this.myKey;
// if (!key) key = "qasection"; // برای شرایطی که بصورت مدال استفاده می شود گتر بالا پر نیست
// let name = "navigationView";
// if (key == "qsection") name = "detail";
// const routeData = this.$router.resolve({
// name: name,
// params: {
// id: _parent,
// key: key,
// },
// query: {},
// });
// return routeData.href;
// },
urlResolver(_id, key = "") {
if (key == "") key = "qmodel";
const routeData = this.$router.resolve({
name: "navigationView",
params: {
id: _id,
key: key,
},
query: {},
});
return routeData.href;
},
},
};
</script>
<style lang="scss" scoped>
.content {
text-align: justify;
}
.text-title-QSection2 {
color: #3279C7 !important;
&:hover {
// color: blue !important;
text-decoration: underline !important;
}
}
.text-title-QSection1 {
color: #3279C7 !important;
&:hover {
// color: blue !important;
text-decoration: underline !important;
}
}
.icon-copy2 {
font-size: 0.7rem;
}
.similar-section {
height: 21em;
overflow: auto;
}
.link-similar{
font-size: 0.97rem;
}
.list-similar{
font-size: 0.91rem;
}
.date-content{
font-size: 0.92rem;
}
// .added-change {
// font-family: sahel-bold;
// color: green;
// }
// .removed-change {
// // font-family: sahel-bold;
// color: red;
// text-decoration: line-through;
// }
//
</style>
//
<style scoped lang="scss">
// .label-text {
// }
// .P-text {
// color: var(--text-primary);
// }
// .similar-row {
// font-size: 12px;
// line-height: 1rem;
// p {
// overflow: hidden;
// white-space: nowrap;
// text-overflow: ellipsis;
// }
// }
// .header-similar {
// width: 95%;
// margin: 0 auto;
// height: 6em;
// }
// .main-similar {
// // height: calc(100vh - 16em);
// height: 19em;
// overflow: auto;
// overflow-x: hidden;
// padding: 0 1em;
// }
// .similar-title {
// max-width: 14em;
// width: 100%;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
// font-weight: normal;
// font-size: 14px;
// text-align: right;
// color: var(--blue-color);
// border: 1px solid rgba(0, 0, 0, 0);
// text-decoration: none;
// }
// .border-similar {
// position: relative;
// &::after {
// content: "";
// position: absolute;
// width: 18.5em;
// border-bottom: 1px solid #dee2e6;
// // background-color: #dee2e6;
// }
// }
// @media only screen and (min-width: 768px) and (max-width: 991.98px) {
// }
// @media only screen and (min-width: 576px) and (max-width: 766.98px) {
// }
// @media (max-width: 575.98px) {
// }
</style>