2024-06-13 17:24:46 +07:00
|
|
|
<script setup lang="ts">
|
2024-06-17 09:55:33 +07:00
|
|
|
import isEmpty from "lodash/isEmpty";
|
2024-06-13 17:24:46 +07:00
|
|
|
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
|
|
|
|
|
import { COLLECTION_PAGING_QUERY_DROP, getInputValue } from "@/utils/parseSQL";
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["dropData", "selectComponent"]);
|
|
|
|
|
|
|
|
|
|
const _props = defineProps<{
|
|
|
|
|
dataResult?: any[];
|
|
|
|
|
dataQuery?: string;
|
|
|
|
|
component?: any;
|
|
|
|
|
label?: string;
|
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const SETTING_OPTIONS = {
|
|
|
|
|
MAX_ELEMENT: 5,
|
|
|
|
|
TEMPLATE: "Article",
|
|
|
|
|
LAYOUT: "TYPE:Card",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// const page = ref(1);
|
|
|
|
|
const limit = ref(1);
|
|
|
|
|
const totals = ref(1);
|
|
|
|
|
const type = "Article";
|
|
|
|
|
|
|
|
|
|
const listArticleByCategory = computed(() => {
|
|
|
|
|
return getInputValue(_props.dataResult, "ARRAY");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const designObject = computed(() => {
|
|
|
|
|
return _props.label ? getInputValue(_props.label, "OBJECT") : {};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const dropData = (event: any) => {
|
|
|
|
|
const queryBy = {
|
|
|
|
|
Category: "Categories",
|
|
|
|
|
};
|
|
|
|
|
const { dataResult, dataType } = JSON.parse(event.dataTransfer.getData("category"));
|
|
|
|
|
// const getDataQuery = `Get[${type}] Top[20] With[${queryBy[dataType]}:${dataResult.id}]`;
|
|
|
|
|
const getDataQuery = COLLECTION_PAGING_QUERY_DROP(type, { key: queryBy[dataType], value: dataResult.id });
|
|
|
|
|
emit("dropData", {
|
|
|
|
|
dataResult: [],
|
|
|
|
|
dataType,
|
|
|
|
|
dataQuery: getDataQuery,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//?cpn_1=page:2&cpn_2=page:1
|
|
|
|
|
// Get[Article] Top[5] With[Categories:1]
|
|
|
|
|
const select = (page: number) => {
|
|
|
|
|
const componentId = _props.component?.id;
|
|
|
|
|
if (componentId) {
|
|
|
|
|
router.push({
|
|
|
|
|
query: {
|
|
|
|
|
...route.query,
|
|
|
|
|
[`cpn_${componentId}`]: `page:${page}`,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const handleRouteChange = (query: any) => {
|
|
|
|
|
const [_, value] = query[`cpn_${_props.component?.id}`]?.split(":");
|
|
|
|
|
if (value) {
|
|
|
|
|
loadPage(Number(value));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onBeforeMount(() => {
|
|
|
|
|
if (route.query[`cpn_${_props.component?.id}`]) handleRouteChange(route.query);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const loadPage = (page: string | number) => {
|
|
|
|
|
console.log(`Loading page ${page}`);
|
|
|
|
|
// listArticleByCategory.value =
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const selectComponent = () => {
|
|
|
|
|
emit("selectComponent");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => route.query,
|
|
|
|
|
(newQuery) => {
|
|
|
|
|
handleRouteChange(newQuery);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<section>
|
|
|
|
|
<div class="section-container" @click="selectComponent" @dragover.prevent @drop.stop.prevent="dropData($event)" :class="[listArticleByCategory && listArticleByCategory?.length > 0 ? '' : 'noData']">
|
|
|
|
|
<div
|
|
|
|
|
class="collection-container"
|
|
|
|
|
:class="[designObject['LAYOUT_WRAP'] || 'vertical', ...(designObject['borderWrap']?.length > 0 ? designObject['borderWrap'] : [])]"
|
|
|
|
|
:style="[designObject['background'] && `background: ${designObject['background']}`]"
|
|
|
|
|
>
|
|
|
|
|
<template v-if="listArticleByCategory?.length > 0">
|
|
|
|
|
<template v-for="(component, index) in listArticleByCategory">
|
|
|
|
|
<DynamicComponent
|
|
|
|
|
:key="index"
|
|
|
|
|
v-if="!isEmpty(component)"
|
|
|
|
|
:settings="{
|
|
|
|
|
template: SETTING_OPTIONS.TEMPLATE,
|
|
|
|
|
layout: SETTING_OPTIONS.LAYOUT,
|
|
|
|
|
dataResult: { ...component },
|
|
|
|
|
label,
|
|
|
|
|
}"
|
|
|
|
|
/>
|
|
|
|
|
</template>
|
|
|
|
|
</template>
|
|
|
|
|
<template v-else>
|
|
|
|
|
<div class="empty"><h6 class="px-2 text-center">Nội dung danh sách bài viết của danh mục sẽ ở đây</h6></div>
|
|
|
|
|
</template>
|
|
|
|
|
<div class="button-page flex">
|
|
|
|
|
<a class="btn-page prev-page cursor-pointer" >
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="w-7 h-6 text-primary-600">
|
|
|
|
|
<path
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
d="M609.408 149.376 277.76 489.6a32 32 0 0 0 0 44.672l331.648 340.352a29.12 29.12 0 0 0 41.728 0 30.592 30.592 0 0 0 0-42.752L339.264 511.936l311.872-319.872a30.592 30.592 0 0 0 0-42.688 29.12 29.12 0 0 0-41.728 0z"
|
|
|
|
|
></path>
|
|
|
|
|
</svg>
|
|
|
|
|
</a>
|
|
|
|
|
<a class="btn-page" @click="() => select(index + 1)" v-for="(_, index) in totals">{{ index + 1 }}</a>
|
|
|
|
|
<a class="btn-page next-page cursor-pointer">
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" class="w-7 h-6 text-primary-600">
|
|
|
|
|
<path
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
d="M340.864 149.312a30.592 30.592 0 0 0 0 42.752L652.736 512 340.864 831.872a30.592 30.592 0 0 0 0 42.752 29.12 29.12 0 0 0 41.728 0L714.24 534.336a32 32 0 0 0 0-44.672L382.592 149.376a29.12 29.12 0 0 0-41.728 0z"
|
|
|
|
|
></path>
|
|
|
|
|
</svg>
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.section-container {
|
|
|
|
|
.collection-container {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
&.border-custom {
|
|
|
|
|
border-color: #e5e5e5 !important;
|
|
|
|
|
}
|
|
|
|
|
&.borderLeft {
|
|
|
|
|
border-left: 2px solid;
|
|
|
|
|
padding-left: 10px;
|
|
|
|
|
}
|
|
|
|
|
&.borderRight {
|
|
|
|
|
border-right: 2px solid;
|
|
|
|
|
padding-right: 10px;
|
|
|
|
|
}
|
|
|
|
|
&.borderTop {
|
|
|
|
|
border-top: 2px solid;
|
|
|
|
|
padding-top: 10px;
|
|
|
|
|
}
|
|
|
|
|
&.borderBottom {
|
|
|
|
|
border-bottom: 2px solid;
|
|
|
|
|
padding-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
&.vertical {
|
|
|
|
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
|
|
|
}
|
|
|
|
|
&.horizontal {
|
|
|
|
|
grid-template-rows: auto;
|
|
|
|
|
grid-auto-flow: column;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.empty {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
min-height: 50px;
|
|
|
|
|
background-color: #409eff;
|
|
|
|
|
display: flex;
|
|
|
|
|
white-space: normal;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
h6 {
|
|
|
|
|
color: #fff;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.basic-article {
|
|
|
|
|
&.article {
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
display: flex;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
&.noData {
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.flex {
|
|
|
|
|
display: flex;
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.button-page {
|
|
|
|
|
-webkit-box-align: center;
|
|
|
|
|
-ms-flex-align: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.btn-page {
|
|
|
|
|
width: 40px;
|
|
|
|
|
height: 40px;
|
|
|
|
|
text-align: center;
|
|
|
|
|
line-height: 36px;
|
|
|
|
|
border: 1px solid #409eff;
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
margin-left: 10px;
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.el-empty {
|
|
|
|
|
padding: 12px 0;
|
|
|
|
|
}
|
|
|
|
|
</style>
|