thainv: ghép navigation
This commit is contained in:
@@ -1,16 +1,21 @@
|
|||||||
.style_layout {
|
// .style_layout {
|
||||||
> .section-container {
|
// > .section-container {
|
||||||
> .layout_define {
|
// > .layout_define {
|
||||||
> .section_layout {
|
// > .section_layout {
|
||||||
@apply gap-x-10 #{!important};
|
// @apply gap-x-10 #{!important};
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
figure {
|
figure {
|
||||||
margin: auto !important;
|
margin: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: cover!important;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
& p {
|
& p {
|
||||||
@apply mb-2;
|
@apply mb-2;
|
||||||
@@ -37,3 +42,10 @@ div[layout="ARTICLE_PAGE"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .layout_define {
|
||||||
|
// & .section_layout.three_col_layout {
|
||||||
|
// @media (max-width: 768px) {
|
||||||
|
// grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
span
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { usePollStore } from "~/stores/poll";
|
import { usePollStore } from "~/stores/poll";
|
||||||
import { usePollOptionStore } from "~/stores/poll-option";
|
import { usePollOptionStore } from "~/stores/poll-option";
|
||||||
@@ -16,7 +17,7 @@ const { currentPoll } = storeToRefs(store.poll);
|
|||||||
const { currentPollOptions } = storeToRefs(store.pollOptions);
|
const { currentPollOptions } = storeToRefs(store.pollOptions);
|
||||||
const { currentPollResponses } = storeToRefs(store.pollResponse);
|
const { currentPollResponses } = storeToRefs(store.pollResponse);
|
||||||
const poll = reactive<Poll | any>({});
|
const poll = reactive<Poll | any>({});
|
||||||
const options = ref<PollOption[]>();
|
const options = ref<PollOption[] | any[]>([]);
|
||||||
async function loadData() {
|
async function loadData() {
|
||||||
await store.poll.fetchById(String(props.dataId));
|
await store.poll.fetchById(String(props.dataId));
|
||||||
await store.pollOptions.fetchByPollId(String(props.dataId));
|
await store.pollOptions.fetchByPollId(String(props.dataId));
|
||||||
@@ -33,7 +34,7 @@ onBeforeMount(async () => {
|
|||||||
await loadData();
|
await loadData();
|
||||||
});
|
});
|
||||||
|
|
||||||
const selectedOption = ref<any>(null);
|
const selectedOption = ref<any>(-1);
|
||||||
const showResult = ref(false);
|
const showResult = ref(false);
|
||||||
const alreadyVoted = ref(false);
|
const alreadyVoted = ref(false);
|
||||||
const canShowResult = computed(() => {
|
const canShowResult = computed(() => {
|
||||||
@@ -48,26 +49,20 @@ const canShowResult = computed(() => {
|
|||||||
return alreadyVoted.value && (!poll.endTime || new Date() > new Date(poll.endTime));
|
return alreadyVoted.value && (!poll.endTime || new Date() > new Date(poll.endTime));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const totalResponses = ref(0);
|
||||||
async function submitVote() {
|
async function submitVote() {
|
||||||
if (selectedOption.value) {
|
if (selectedOption.value >= 0 && !alreadyVoted.value) {
|
||||||
let option = options.value?.find((option: PollOption) => option.id === selectedOption.value);
|
const result = await store.pollResponse.create({ optionId: selectedOption.value });
|
||||||
if(option) {
|
if (result?.id) {
|
||||||
option.responsesCount = Number(option.responsesCount) + 1
|
totalResponses.value = options.value?.reduce((sum, option) => sum + Number(option.responseCount ?? 0), 1);
|
||||||
|
options?.value?.forEach((option: PollOption | any) => {
|
||||||
|
if (option.id === selectedOption.value) {
|
||||||
|
option.responseCount = (option.responseCount ?? 0) + 1;
|
||||||
|
}
|
||||||
|
option.percentage = Number(((option.responseCount / totalResponses.value) * 100).toFixed(1));
|
||||||
|
});
|
||||||
|
alreadyVoted.value = true;
|
||||||
}
|
}
|
||||||
const totalResponses = options.value?.reduce((sum, option) => sum + Number(option.responsesCount ?? 0), 0);
|
|
||||||
// const result = await store.pollResponse.create({ optionId: selectedOption.value });
|
|
||||||
// if (result) {
|
|
||||||
// alreadyVoted.value = true;
|
|
||||||
// if (options.value) {
|
|
||||||
// let option = options.value.find((option: PollOption) => option.id === selectedOption.value);
|
|
||||||
// // if (option) option?.responsesCount += 1;
|
|
||||||
// // options.value.filter((option) => {
|
|
||||||
// // option.votePercentage = (option.responsesCount / currentPollResponses.value.length) * 100;
|
|
||||||
// // });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,23 +83,22 @@ const toggleResults = () => {
|
|||||||
<span v-if="!showResult" class="p-1 block">
|
<span v-if="!showResult" class="p-1 block">
|
||||||
<span v-for="(option, index) in options" :key="index" class="block">
|
<span v-for="(option, index) in options" :key="index" class="block">
|
||||||
<label class="flex gap-2 m-2">
|
<label class="flex gap-2 m-2">
|
||||||
<input type="radio" :value="option.id" v-model="selectedOption" />
|
<input type="radio" :value="option.id" v-model="selectedOption" :disabled="selectedOption >= 0 && alreadyVoted ? true : false" />
|
||||||
<span class="font-semibold">{{ option?.title }}</span>
|
<span class="font-semibold">{{ option?.title }}</span>
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</span>
|
||||||
<button @click="submitVote" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Bình chọn</button>
|
<button @click="submitVote" class="bg-primary-500 text-white py-1 px-3 rounded-4px cursor-pointer hover:bg-primary-600 float-right">Bình chọn</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-else class="block">
|
<span v-else class="flex flex-col my-5 gap-4">
|
||||||
hoàn thành
|
<span v-for="(answer, index) in options" :key="index" class="flex gap-2">
|
||||||
<!-- <span v-for="(answer, index) in options" :key="index" class="block poll-result relative rounded-3xl overflow-hidden my-3">
|
<span class="w-50px">{{ answer.percentage }}%</span>
|
||||||
<span class="absolute top-0 start-0 bottom-0 bg-gradient-to-r from-sky-500 to-indigo-500"
|
<div class="w-full">
|
||||||
:style="{ width: `${calculatePercentage(answer?.voteCount)}%` }"></span>
|
<b class="mb-0.5 block">{{ answer.title }}</b>
|
||||||
<span class="block relative z-0 ps-1">
|
<div :style="{ width: `${answer.percentage}%` }" :class="answer.id === selectedOption ? 'bg-green-600' : 'bg-primary-500'" class="h-1.5 rounded-full"></div>
|
||||||
<span>{{ calculatePercentage(answer?.voteCount).toFixed(2) }}%</span>
|
</div>
|
||||||
<span class="">({{ answer?.voteCount }})</span>
|
</span>
|
||||||
</span>
|
<b>Tổng số lượt binh chọn: {{ totalResponses }}</b>
|
||||||
</span> -->
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { enumPageComponentTemplates, enumPageComponentLayouts } from "@/definitions/enum";
|
||||||
|
import DynamicComponent from "~/components/dynamic-page/page-component/templates/index.vue";
|
||||||
|
import { useDynamicPageStore } from '~/stores/dynamic-page';
|
||||||
|
const { currentPage } = storeToRefs(useDynamicPageStore());
|
||||||
|
const props = defineProps<{
|
||||||
|
type: string; // [TOP_NAVIGATION, BOTTOM_NAVIGATION]
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// const store = reactive({
|
||||||
|
// page: useCmsPageStore(),
|
||||||
|
// section: usePageSectionStore(),
|
||||||
|
// component: usePageComponentStore(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const { currentPage } = storeToRefs(useCmsPageStore());
|
||||||
|
|
||||||
|
const defineTypeRecusive = {
|
||||||
|
TOP_NAVIGATION: enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-TOP'],
|
||||||
|
BOTTOM_NAVIGATION: enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-BOTTOM'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const findDataPosition = computed(() => {
|
||||||
|
let result = {};
|
||||||
|
switch (props.type) {
|
||||||
|
case defineTypeRecusive.TOP_NAVIGATION:
|
||||||
|
result = currentPage.value.components && currentPage.value.components.find((component: any) => {
|
||||||
|
return component.settings?.template === enumPageComponentTemplates.NAVIGATION && component.settings?.layout === defineTypeRecusive.TOP_NAVIGATION
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case defineTypeRecusive.BOTTOM_NAVIGATION:
|
||||||
|
result = currentPage.value.components && currentPage.value.components.find((component: any) => {
|
||||||
|
return component.settings && component.settings?.template === enumPageComponentTemplates.NAVIGATION && component.settings?.layout === defineTypeRecusive.BOTTOM_NAVIGATION
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = {};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
console.log(result)
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
// const selectComponent = (data: any) => {
|
||||||
|
// store.page.selectComponent(data)
|
||||||
|
// }
|
||||||
|
console.log(findDataPosition, 'findDataPosition')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<DynamicComponent
|
||||||
|
v-if="findDataPosition && findDataPosition?.id"
|
||||||
|
:settings="findDataPosition?.settings"
|
||||||
|
:component="findDataPosition"
|
||||||
|
:content="findDataPosition?.content"
|
||||||
|
/>
|
||||||
|
<div v-else class="text-center">
|
||||||
|
<span>Hãy tạo thành phần "Thanh điều hướng ở đầu trang" để hiển thị thành điều hướng tại đây</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -89,7 +89,7 @@ const drop = (e: any) => {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.basic-article {
|
.basic-article {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 12px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
&.no-data {
|
&.no-data {
|
||||||
@@ -104,6 +104,11 @@ const drop = (e: any) => {
|
|||||||
&.reverse {
|
&.reverse {
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
flex-direction:column;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.border-custom {
|
&.border-custom {
|
||||||
@@ -111,24 +116,39 @@ const drop = (e: any) => {
|
|||||||
}
|
}
|
||||||
&.borderLeft {
|
&.borderLeft {
|
||||||
border-left: 1px solid;
|
border-left: 1px solid;
|
||||||
padding-left: 10px;
|
padding-left: 16px;
|
||||||
|
|
||||||
}
|
}
|
||||||
&.borderRight {
|
&.borderRight {
|
||||||
border-right: 1px solid;
|
border-right: 1px solid;
|
||||||
padding-right: 10px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
&.borderTop {
|
&.borderTop {
|
||||||
border-top: 1px solid;
|
border-top: 1px solid;
|
||||||
padding-top: 10px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
&.borderBottom {
|
&.borderBottom {
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
&.borderRight ,
|
||||||
|
&.borderLeft,
|
||||||
|
&.borderTop,
|
||||||
|
&.borderBottom {
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.horizontal {
|
&.horizontal {
|
||||||
flex-direction: row;
|
@apply sm:flex-row flex-col;
|
||||||
.basic-article_thumbnail {
|
.basic-article_thumbnail {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.reverse {
|
&.reverse {
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { isEmpty } from "lodash";
|
||||||
|
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/parseSQL";
|
||||||
|
|
||||||
import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from '@/utils/parseSQL';
|
const emit = defineEmits(["dropData", "selectComponent"]);
|
||||||
|
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
dataResult?: any[];
|
dataResult?: any[];
|
||||||
dataQuery?: string;
|
dataQuery?: string;
|
||||||
|
label?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const SETTING_OPTIONS = {
|
const SETTING_OPTIONS = {
|
||||||
@@ -12,27 +15,111 @@ const SETTING_OPTIONS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const _dataResult = computed(() => {
|
const _dataResult = computed(() => {
|
||||||
let _components = Array(SETTING_OPTIONS.MAX_ELEMENT).fill(null);
|
const designObject = _props.label ? getInputValue(_props.label, "OBJECT") : {};
|
||||||
const result = getInputValue(_props.dataResult, 'ARRAY');
|
let _components = Array(Number(designObject.MAX) || SETTING_OPTIONS.MAX_ELEMENT).fill(null);
|
||||||
result && result.length > 0 && _components.map((_ : any, index : any) => {
|
const result = getInputValue(_props.dataResult, "ARRAY");
|
||||||
_components[index] = result[index] || null;
|
result &&
|
||||||
})
|
result.length > 0 &&
|
||||||
return _components;
|
_components.map((_: any, index: any) => {
|
||||||
|
_components[index] = result[index] || null;
|
||||||
|
});
|
||||||
|
return Object.assign({}, _components);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const designObject = computed(() => {
|
||||||
|
return _props.label ? getInputValue(_props.label, "OBJECT") : {};
|
||||||
|
});
|
||||||
|
|
||||||
|
async function dropData(event: any) {
|
||||||
|
const { dataResult, dataType } = JSON.parse(event.dataTransfer.getData("category"));
|
||||||
|
const checkDataResult = getInputValue(_props.dataResult, "ARRAY");
|
||||||
|
const result = _props.dataResult ? [...checkDataResult, { ...dataResult }] : [{ ...dataResult }];
|
||||||
|
const getDataQuery = _props.dataQuery ? COLLECTION_QUERY_DROP(dataType, getValueStringWithKeyAndColon(_props.dataQuery) + "," + dataResult.id) : COLLECTION_QUERY_DROP(dataType, dataResult.id);
|
||||||
|
|
||||||
|
emit("dropData", {
|
||||||
|
dataResult: result,
|
||||||
|
dataType,
|
||||||
|
dataQuery: getDataQuery,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectComponent = () => {
|
||||||
|
emit("selectComponent");
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex gap-4 items-end">
|
<div
|
||||||
<template v-for="(component, index) in _dataResult">
|
class="categories-container p-2 border-custom"
|
||||||
<nuxt-link v-if="component" :key="index" :to="`/${component.code}`" class=" py-1 font-400 text-[16px] first:font-600 first:text-[22px] first:border-b first:border-primary-600 sm:block hidden first:block">
|
@click="selectComponent"
|
||||||
<h3 class="m-0 leading-none hover:text-primary-600 transition-all duration-300">{{ component.title }}</h3>
|
:class="[designObject['LAYOUT_WRAP'] || 'horizontal', ...(designObject['borderWrap']?.length > 0 ? designObject['borderWrap'] : [])]"
|
||||||
</nuxt-link>
|
:style="[designObject['background'] && `background: ${designObject['background']}`]"
|
||||||
</template>
|
>
|
||||||
|
<div v-for="(component, index) in _dataResult" :key="index" :class="[...(designObject['border']?.length > 0 ? designObject['border'] : []), 'border-custom', isEmpty(component) ? 'empty' : 'category']">
|
||||||
|
<template v-if="!isEmpty(component)">
|
||||||
|
<nuxt-link :to="`/${component.code}`"
|
||||||
|
:class="index != 0? 'sm:block hidden' : 'font-bold text-20px border-b-2px border-primary-600'"
|
||||||
|
class="hover:text-primary-600"
|
||||||
|
>
|
||||||
|
{{ component.title }}
|
||||||
|
</nuxt-link>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-else @dragover.prevent @drop.stop.prevent="dropData($event)"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.categories-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: flex-end;
|
||||||
|
width: fit-content;
|
||||||
|
overflow: hidden;
|
||||||
|
&.vertical {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
&.horizontal {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
.category {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
h3 {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.border-custom {
|
||||||
|
border-color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
.borderLeft {
|
||||||
|
border-left: 1px solid;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
.borderRight {
|
||||||
|
border-right: 1px solid;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
.borderTop {
|
||||||
|
border-top: 1px solid;
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
.borderBottom {
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -10,3 +10,4 @@ export { default as Dynamic_Advertising } from './advertising/index.vue'
|
|||||||
export { default as Dynamic_Category } from './categories/index.vue'
|
export { default as Dynamic_Category } from './categories/index.vue'
|
||||||
export { default as Dynamic_Article } from './articles/index.vue'
|
export { default as Dynamic_Article } from './articles/index.vue'
|
||||||
export { default as Dynamic_Collection } from './collections/index.vue'
|
export { default as Dynamic_Collection } from './collections/index.vue'
|
||||||
|
export { default as Dynamic_Navigation } from './navigations/index.vue'
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { enumPageComponentTemplates } from "@/definitions/enum";
|
import { enumPageComponentTemplates } from "@/definitions/enum";
|
||||||
import { Dynamic_Section, Dynamic_Category, Dynamic_Collection, CollectionPaging, Dynamic_Other, Dynamic_Advertising, Dynamic_Article } from "./index";
|
import { Dynamic_Section, Dynamic_Category, Dynamic_Collection, Dynamic_Navigation, Dynamic_Other, Dynamic_Advertising, Dynamic_Article } from "./index";
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
settings: any;
|
settings: any;
|
||||||
component?: any;
|
component?: any;
|
||||||
@@ -12,12 +12,11 @@ const definedDynamicComponent: Record<string, any> = {
|
|||||||
[enumPageComponentTemplates.COLLECTION]: Dynamic_Collection,
|
[enumPageComponentTemplates.COLLECTION]: Dynamic_Collection,
|
||||||
[enumPageComponentTemplates.SECTION]: Dynamic_Section,
|
[enumPageComponentTemplates.SECTION]: Dynamic_Section,
|
||||||
[enumPageComponentTemplates.OTHER]: Dynamic_Other,
|
[enumPageComponentTemplates.OTHER]: Dynamic_Other,
|
||||||
[enumPageComponentTemplates.ADVERTISING]: Dynamic_Advertising
|
[enumPageComponentTemplates.ADVERTISING]: Dynamic_Advertising,
|
||||||
|
[enumPageComponentTemplates.NONE]: Dynamic_Navigation,
|
||||||
};
|
};
|
||||||
|
// console.log(_props.settings.template, 'template')
|
||||||
const getCurrentComponent = computed(() => `${_props.settings.template}`);
|
const getCurrentComponent = computed(() => `${_props.settings.template}`);
|
||||||
|
|
||||||
|
|
||||||
const GET_PROPS = computed(() => {
|
const GET_PROPS = computed(() => {
|
||||||
return () => {
|
return () => {
|
||||||
let props: any = {};
|
let props: any = {};
|
||||||
@@ -36,5 +35,5 @@ const GET_PROPS = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- <component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...(GET_PROPS()), component: _props.component, settings: _props.settings }" /> -->
|
<!-- <component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...(GET_PROPS()), component: _props.component, settings: _props.settings }" /> -->
|
||||||
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...(GET_PROPS()), component: _props.component, settings: _props.settings }" />
|
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings }" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
+138
@@ -0,0 +1,138 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
// import RecusiveNavItem from "@/components/cms/page-component/templates/navigations/components/RecusiveNavItem.vue";
|
||||||
|
// import RecusiveSection from "@/components/cms/page-section/RecusiveSection.vue";
|
||||||
|
// import { enumPageComponentTemplates, enumPageComponentStaticChild } from "@/definitions/enum";
|
||||||
|
|
||||||
|
// const props = defineProps<{
|
||||||
|
// records?: any[]
|
||||||
|
// component: any;
|
||||||
|
// }>();
|
||||||
|
|
||||||
|
// const store = reactive({
|
||||||
|
// page: useCmsPageStore(),
|
||||||
|
// section: usePageSectionStore(),
|
||||||
|
// component: usePageComponentStore(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const globalState = ref({})
|
||||||
|
// const setGlobalState = (id: any) => {
|
||||||
|
// globalState.value[id] = !globalState.value[id];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const selectNavigationComponent = () => {
|
||||||
|
// store.page.selectComponentNavigation(props.component);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const dropSection = (event: any, child: any) => {
|
||||||
|
// if (event.dataTransfer.getData("section")) {
|
||||||
|
// const section = JSON.parse(event.dataTransfer.getData("section"));
|
||||||
|
// store.component.updateNavigationItemInfor(props.component, child, { data: section.id });
|
||||||
|
// store.section.updatePublishedSectionInGeneralPage(section.id, 9999999999);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
ábsabda
|
||||||
|
<!-- <div class="navigation-container d-flex gap-4 justify-content-center align-items-center">
|
||||||
|
<div v-for="(record) in props.records" :key="record.id" class="navigation-branch cursor-pointer">
|
||||||
|
<template v-if="record && record.childs && record.childs.length > 0 && record.typeChild === enumPageComponentStaticChild.DEFAULT">
|
||||||
|
<div class="navigation-submenu">
|
||||||
|
<div class="" @click="selectNavigationComponent">{{ record?.title }}</div>
|
||||||
|
<div class="navigation-item submenu-container dropdown-container">
|
||||||
|
<RecusiveNavItem :records="record.childs" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="record.typeChild === enumPageComponentStaticChild.LAYOUT">
|
||||||
|
<div class="navigation-submenu">
|
||||||
|
<div class="position-relative ps-3">
|
||||||
|
<span class="position-absolute " style="left: -10px; top: -7px" @click="() => setGlobalState(record.id)">
|
||||||
|
<i v-if="!globalState[record.id]" class="ri-eye-2-line fs-3"></i>
|
||||||
|
<i v-else class="ri-eye-close-line fs-3"></i>
|
||||||
|
</span>
|
||||||
|
<span @click="selectNavigationComponent">{{ record?.title }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="full-layout dropdown-container" :class="[!globalState[record.id] && 'show-menu']">
|
||||||
|
<template v-if="record.data">
|
||||||
|
<div class="p-2">
|
||||||
|
<RecusiveSection type="section" :id="record.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-empty description="Kéo Section vào đây" @dragover.prevent @drop.stop.prevent="dropSection($event, record)" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="navigation-item" @click="selectNavigationComponent">{{ record?.title }}</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.navigation-branch {
|
||||||
|
.navigation-submenu {
|
||||||
|
position: relative;
|
||||||
|
padding: 15px 5px;
|
||||||
|
&:hover {
|
||||||
|
> .dropdown-container {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, 0%);
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.submenu-container {
|
||||||
|
width: 200px;
|
||||||
|
display: flex;
|
||||||
|
> div {
|
||||||
|
justify-content: start !important;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
gap: 0px !important;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
.navigation-item {
|
||||||
|
width: 100% !important;
|
||||||
|
padding: 10px 20px;
|
||||||
|
&:hover {
|
||||||
|
background: #409eff;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigation-branch {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown-container {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, 10%);
|
||||||
|
left: 50%;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all .3s;
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #fff;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
.full-layout {
|
||||||
|
width: 800px;
|
||||||
|
z-index: 100;
|
||||||
|
// height: 400px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-menu {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate(-50%, 0%);
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// import { nanoid } from "nanoid"
|
||||||
|
// import RecusiveTopChild from "@/components/dynamic-page/page-component/templates/navigations/components/RecusiveTopChild.vue";
|
||||||
|
// import { enumPageComponentTemplates, enumPageComponentStaticChild } from "@/definitions/enum";
|
||||||
|
|
||||||
|
// const props = defineProps<{
|
||||||
|
// records?: any[]
|
||||||
|
// currentComponent?: any
|
||||||
|
// }>()
|
||||||
|
|
||||||
|
// const store = reactive({
|
||||||
|
// page: useCmsPageStore(),
|
||||||
|
// section: usePageSectionStore(),
|
||||||
|
// component: usePageComponentStore(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const showChildItem = ref<boolean>(false)
|
||||||
|
|
||||||
|
// const toggleStatusBar = (type: "section", id?: any) => {
|
||||||
|
// // if (type === "section") {
|
||||||
|
// // store.section.setCurrentSection(id);
|
||||||
|
// // } else {
|
||||||
|
// // store.section.setCurrentSection(null);
|
||||||
|
// // }
|
||||||
|
// // store.section.toggleStatusSectionBar(true);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const removeStaticRecord = (currentChild: any) => {
|
||||||
|
// store.component.removeChildtNavigation(props.currentComponent, currentChild);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const addChildRecord = (currentChild: any) => {
|
||||||
|
// const newChildItem = {
|
||||||
|
// id: nanoid(10),
|
||||||
|
// title: 'Mới mới',
|
||||||
|
// slug: '',
|
||||||
|
// childs: [],
|
||||||
|
// parentId: currentChild.id,
|
||||||
|
// data: null,
|
||||||
|
// typeChild: enumPageComponentStaticChild.DEFAULT,
|
||||||
|
// }
|
||||||
|
// store.component.setChildForComponentNavigation(props.currentComponent, newChildItem);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const setNavigationItem = (currentChild: any) => {
|
||||||
|
// console.log(currentChild)
|
||||||
|
// store.component.setNavigationItem(currentChild);
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
ádasd
|
||||||
|
<!-- <div class="lists-record">
|
||||||
|
<div v-for="(record) in props.records" :key="record.id">
|
||||||
|
<template v-if="record && record.childs && record.childs.length > 0 && record.typeChild === enumPageComponentStaticChild.DEFAULT">
|
||||||
|
<div class="record-item child">
|
||||||
|
<div class="record-infor d-flex align-items-center gap-2">
|
||||||
|
<span @click="() => showChildItem = !showChildItem" class="cursor-pointer">
|
||||||
|
<i :class="[showChildItem ? 'ri-arrow-down-s-line' : 'ri-arrow-right-s-line']"></i>
|
||||||
|
</span>
|
||||||
|
<h6>{{ record.title || '' }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="record-action">
|
||||||
|
<span @click="addChildRecord(record)"><i class="ri-add-line"></i></span>
|
||||||
|
<span @click="setNavigationItem(record)"><i class="ri-eye-line"></i></span>
|
||||||
|
<span @click="removeStaticRecord(record)"><i class="ri-delete-bin-7-line"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ps-4 mt-2" :class="[showChildItem ? 'is-show-item' : 'is-hidden-item']">
|
||||||
|
<RecusiveTopChild :records="record.childs" :currentComponent="props.currentComponent" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="record.typeChild === enumPageComponentStaticChild.LAYOUT">
|
||||||
|
<div class="record-item child">
|
||||||
|
<div class="record-infor d-flex align-items-center gap-2">
|
||||||
|
<h6>{{ record.title || '' }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="record-action">
|
||||||
|
<span @click="setNavigationItem(record)"><i class="ri-eye-line"></i></span>
|
||||||
|
<span @click="removeStaticRecord(record)"><i class="ri-delete-bin-7-line"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="record-item">
|
||||||
|
<div class="record-infor d-flex align-items-center gap-2">
|
||||||
|
<h6>{{ record.title || '' }}</h6>
|
||||||
|
</div>
|
||||||
|
<div class="record-action">
|
||||||
|
<span @click="addChildRecord(record)"><i class="ri-add-line"></i></span>
|
||||||
|
<span @click="setNavigationItem(record)"><i class="ri-eye-line"></i></span>
|
||||||
|
<span @click="removeStaticRecord(record)"><i class="ri-delete-bin-7-line"></i></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.lists-record {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
gap: 14px;
|
||||||
|
|
||||||
|
.record-item {
|
||||||
|
padding: 3px 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
cursor: move;
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
&.child {
|
||||||
|
padding: 3px 15px 3px 10px;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
> .record-action {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .record-action {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.3s;
|
||||||
|
color: #7e7e7e;
|
||||||
|
|
||||||
|
> span:hover {
|
||||||
|
color: #409eff;
|
||||||
|
transition: 0.3s all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .record-infor {
|
||||||
|
span i {
|
||||||
|
font-size: 18px;
|
||||||
|
cursor: point;
|
||||||
|
}
|
||||||
|
h6 {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.is-show-item {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.is-hidden-item {
|
||||||
|
height: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// Navigation
|
||||||
|
export { default as Top_Navigation } from './layouts/Top.vue'
|
||||||
|
export { default as Bottom_Navigation } from './layouts/Bottom.vue'
|
||||||
|
export { default as Direction_Navigation } from './layouts/Direction.vue'
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { enumPageComponentTemplates, enumPageComponentLayouts } from "@/definitions/enum";
|
||||||
|
import { Direction_Navigation, Bottom_Navigation, Top_Navigation } from "./index";
|
||||||
|
|
||||||
|
const _props = defineProps<{
|
||||||
|
settings: any;
|
||||||
|
component?: any;
|
||||||
|
content?: any
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const definedDynamicComponent: Record<string, any> = {
|
||||||
|
[enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-DIRECTION']]: Direction_Navigation,
|
||||||
|
[enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-BOTTOM']]: Bottom_Navigation,
|
||||||
|
[enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-TOP']]: Top_Navigation,
|
||||||
|
};
|
||||||
|
const getCurrentComponent = computed(() => `${_props.settings.layout}`);
|
||||||
|
|
||||||
|
const GET_PROPS = computed(() => {
|
||||||
|
return () => {
|
||||||
|
let props: any = {};
|
||||||
|
if (_props.settings) {
|
||||||
|
for (const [key, value] of Object.entries(_props.settings)) {
|
||||||
|
props = {
|
||||||
|
...props,
|
||||||
|
[key]: value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return props;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="definedDynamicComponent[getCurrentComponent]" v-bind="{ ...GET_PROPS(), component: _props.component, settings: _props.settings, content: _props.content }" />
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// import { isEmpty } from "lodash";
|
||||||
|
// import DynamicComponent from "~/components/cms/page-component/templates/index.vue";
|
||||||
|
// import { getInputValue } from "@/utils/cms/page/parseSQL";
|
||||||
|
|
||||||
|
// const emit = defineEmits(["selectComponent"]);
|
||||||
|
|
||||||
|
// const _props = defineProps<{
|
||||||
|
// dataResult?: any[];
|
||||||
|
// dataQuery?: string;
|
||||||
|
// component?: any;
|
||||||
|
// }>();
|
||||||
|
|
||||||
|
// const SETTING_OPTIONS = {
|
||||||
|
// MAX_ELEMENT: 10,
|
||||||
|
// };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
lay outa
|
||||||
|
<!-- <section>
|
||||||
|
<div v-for="navItem, index in Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})" :key="index">
|
||||||
|
<div class="empty"></div>
|
||||||
|
</div>
|
||||||
|
</section> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.empty {
|
||||||
|
width: 120px;
|
||||||
|
min-height: 100px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #409eff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { isEmpty } from "lodash";
|
||||||
|
// import DynamicComponent from "~/components/cms/page-component/templates/index.vue";
|
||||||
|
// import { getInputValue } from "@/utils/cms/page/parseSQL";
|
||||||
|
|
||||||
|
// const emit = defineEmits(["selectComponent"]);
|
||||||
|
|
||||||
|
// const _props = defineProps<{
|
||||||
|
// dataResult?: any[];
|
||||||
|
// dataQuery?: string;
|
||||||
|
// component?: any;
|
||||||
|
// }>();
|
||||||
|
|
||||||
|
// const SETTING_OPTIONS = {
|
||||||
|
// MAX_ELEMENT: 10,
|
||||||
|
// };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
ád
|
||||||
|
<!-- <section>
|
||||||
|
<div v-for="navItem, index in Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})" :key="index">
|
||||||
|
<div class="empty"></div>
|
||||||
|
</div>
|
||||||
|
</section> -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.empty {
|
||||||
|
width: 120px;
|
||||||
|
min-height: 100px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: #409eff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// import { isEmpty } from "lodash";
|
||||||
|
// import { nanoid } from "nanoid"
|
||||||
|
// import { enumPageComponentTemplates, enumPageComponentStaticChild } from "@/definitions/enum";
|
||||||
|
// import DynamicComponent from "~/components/cms/page-component/templates/index.vue";
|
||||||
|
// import { COLLECTION_QUERY_DROP, getValueStringWithKeyAndColon, getInputValue } from "@/utils/cms/page/parseSQL";
|
||||||
|
// import { buildTree } from "@/utils/cms/page/recusive";
|
||||||
|
// import RecusiveNavItem from "@/components/cms/page-component/templates/navigations/components/RecusiveNavItem.vue";
|
||||||
|
|
||||||
|
// const emit = defineEmits(["selectComponent"]);
|
||||||
|
|
||||||
|
// const _props = defineProps<{
|
||||||
|
// content?: any[];
|
||||||
|
// component?: any;
|
||||||
|
// }>();
|
||||||
|
|
||||||
|
// const store = reactive({
|
||||||
|
// page: useCmsPageStore(),
|
||||||
|
// section: usePageSectionStore(),
|
||||||
|
// component: usePageComponentStore(),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const SETTING_OPTIONS = {
|
||||||
|
// MAX_ELEMENT: 10,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const _dataResult = computed(() => {
|
||||||
|
// let _components = Array(SETTING_OPTIONS.MAX_ELEMENT).fill({});
|
||||||
|
// const result = getInputValue(_props.content, "ARRAY");
|
||||||
|
// result &&
|
||||||
|
// result.length > 0 &&
|
||||||
|
// _components.map((_: any, index: any) => {
|
||||||
|
// _components[index] = result[index] || null;
|
||||||
|
// });
|
||||||
|
// return _components;
|
||||||
|
// });
|
||||||
|
|
||||||
|
// async function dropData(event: any, data: any) {
|
||||||
|
// if (event.dataTransfer.getData(`${enumPageComponentTemplates.CATEGORY}`)) {
|
||||||
|
// const data = event.dataTransfer.getData(`${enumPageComponentTemplates.CATEGORY}`);
|
||||||
|
// const { dataResult } = JSON.parse(data);
|
||||||
|
// const dataInsert = {
|
||||||
|
// id: nanoid(10),
|
||||||
|
// title: dataResult.title,
|
||||||
|
// slug: dataResult.code,
|
||||||
|
// childs: [],
|
||||||
|
// parentId: null,
|
||||||
|
// data: null,
|
||||||
|
// typeChild: enumPageComponentStaticChild.DEFAULT,
|
||||||
|
// };
|
||||||
|
// const getJSonContent = JSON.parse(_props.content)
|
||||||
|
// const checkDataResult = getInputValue(getJSonContent, "ARRAY");
|
||||||
|
// const result: any = _props.content ? [...checkDataResult, { ...dataInsert }] : [{ ...dataInsert }];
|
||||||
|
// store.component.setStaticData(result, _props.component.id);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- <nav>
|
||||||
|
<div class="d-flex gap-3 justify-content-center align-items-center">
|
||||||
|
<RecusiveNavItem :records="content && buildTree(content)" :component="_props.component" />
|
||||||
|
|
||||||
|
<div class="empty" @dragover.prevent @drop.stop.prevent="dropData">
|
||||||
|
<i class="ri-add-fill"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav> -->
|
||||||
|
ád
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.empty {
|
||||||
|
width: 100px;
|
||||||
|
min-height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #409eff;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 18px;
|
||||||
|
color: white;
|
||||||
|
margin: 5px 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -146,20 +146,20 @@ watch(
|
|||||||
border-color: #e5e5e5 !important;
|
border-color: #e5e5e5 !important;
|
||||||
}
|
}
|
||||||
&.borderLeft {
|
&.borderLeft {
|
||||||
border-left: 2px solid;
|
border-left: 1px solid;
|
||||||
padding-left: 10px;
|
padding-left: 16px;
|
||||||
}
|
}
|
||||||
&.borderRight {
|
&.borderRight {
|
||||||
border-right: 2px solid;
|
border-right: 1px solid;
|
||||||
padding-right: 10px;
|
padding-right: 16px;
|
||||||
}
|
}
|
||||||
&.borderTop {
|
&.borderTop {
|
||||||
border-top: 2px solid;
|
border-top: 1px solid;
|
||||||
padding-top: 10px;
|
padding-top: 16px;
|
||||||
}
|
}
|
||||||
&.borderBottom {
|
&.borderBottom {
|
||||||
border-bottom: 2px solid;
|
border-bottom: 1px solid;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
&.vertical {
|
&.vertical {
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
@@ -168,6 +168,16 @@ watch(
|
|||||||
grid-template-rows: auto;
|
grid-template-rows: auto;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
}
|
}
|
||||||
|
&.borderRight ,
|
||||||
|
&.borderLeft,
|
||||||
|
&.borderTop,
|
||||||
|
&.borderBottom {
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.empty {
|
.empty {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ const CLASS_FOR_SECTION = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="section_layout grid sm:gap-x-5 sm:gap-y-2.5 gap-[10px] lg:grid-cols-2" :class="[CLASS_FOR_SECTION.section_layout]">
|
<div class="section_layout grid gap-[16px] lg:grid-cols-2" :class="[CLASS_FOR_SECTION.section_layout]">
|
||||||
<div
|
<div
|
||||||
v-for="(position, index) in props.content || Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})"
|
v-for="(position, index) in props.content || Array(SETTING_OPTIONS.MAX_ELEMENT).fill({})"
|
||||||
:key="index"
|
:key="index"
|
||||||
@@ -156,15 +156,7 @@ const CLASS_FOR_SECTION = computed(() => {
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.section_layout {
|
.section_layout {
|
||||||
&.basic_column {
|
&.basic_column {
|
||||||
grid-template-columns: repeat(1, minmax(0, 1fr));
|
@apply grid-cols-1;
|
||||||
|
|
||||||
// & > div:first-child {
|
|
||||||
// .basic-article {
|
|
||||||
// h3 {
|
|
||||||
// @apply text-24px;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.two_col_layout {
|
&.two_col_layout {
|
||||||
@@ -172,7 +164,7 @@ const CLASS_FOR_SECTION = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.three_col_layout {
|
&.three_col_layout {
|
||||||
@apply lg:grid-cols-3 grid-cols-1;
|
@apply md:grid-cols-3 grid-cols-1;
|
||||||
// grid-template-columns: repeat(3, minmax(0, 1fr));
|
// grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
&.four_col_layout {
|
&.four_col_layout {
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ const definedDynamicSection: Record<string, any> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getCurrentSection = computed(() => _props?.layout || "");
|
const getCurrentSection = computed(() => _props?.layout || "");
|
||||||
|
|
||||||
const GET_PROPS = computed(() => {
|
const GET_PROPS = computed(() => {
|
||||||
return () => {
|
return () => {
|
||||||
let props: any = {};
|
let props: any = {};
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { default as Article_Section_Default } from './articles/Default.vue'
|
export { default as Article_Section_Default } from './articles/Default.vue'
|
||||||
|
export { default as None_Section_Default } from './none/Default.vue'
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Article_Section_Default } from './index';
|
import { Article_Section_Default, None_Section_Default } from './index';
|
||||||
import { enumPageSectionLayouts } from "@/definitions/enum";
|
import { enumPageSectionLayouts } from "@/definitions/enum";
|
||||||
|
|
||||||
const _props = defineProps<{
|
const _props = defineProps<{
|
||||||
@@ -25,10 +25,27 @@ const definedDynamicSection: Record<string, any> = {
|
|||||||
[`Article_${enumPageSectionLayouts.HORIZONTAL_EIGHT}`]: Article_Section_Default,
|
[`Article_${enumPageSectionLayouts.HORIZONTAL_EIGHT}`]: Article_Section_Default,
|
||||||
[`Article_${enumPageSectionLayouts.HORIZONTAL_NINE}`]: Article_Section_Default,
|
[`Article_${enumPageSectionLayouts.HORIZONTAL_NINE}`]: Article_Section_Default,
|
||||||
[`Article_${enumPageSectionLayouts.HORIZONTAL_TEN}`]: Article_Section_Default,
|
[`Article_${enumPageSectionLayouts.HORIZONTAL_TEN}`]: Article_Section_Default,
|
||||||
|
|
||||||
|
'None_Default': None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.VERTICAL_TWO}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.VERTICAL_LEFT_TWO}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.VERTICAL_RIGHT_TWO}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.VERTICAL_THREE}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.VERTICAL_FOUR}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_ONE}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_TWO}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_THREE}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_FOUR}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_FIVE}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_SIX}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_SEVEN}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_EIGHT}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_NINE}`]: None_Section_Default,
|
||||||
|
[`None_${enumPageSectionLayouts.HORIZONTAL_TEN}`]: None_Section_Default,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCurrentSection = computed(() => `${_props.settings.template}_${_props.settings.layout}`);
|
const getCurrentSection = computed(() => `${_props.settings.template}_${_props.settings.layout}`);
|
||||||
|
|
||||||
const GET_PROPS = computed(() => {
|
const GET_PROPS = computed(() => {
|
||||||
return () => {
|
return () => {
|
||||||
let props: any = {};
|
let props: any = {};
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import DynamicLayout from '~/components/dynamic-page/page-section/layouts/index.vue';
|
||||||
|
import type { PageSection } from "~/server/models/dynamic-page/index";
|
||||||
|
|
||||||
|
const emit = defineEmits(['dropComponent', 'dropData', 'selectComponent']);
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
label?: any
|
||||||
|
layout?: string
|
||||||
|
settings?: any
|
||||||
|
content?: any
|
||||||
|
section: PageSection
|
||||||
|
}>()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DynamicLayout
|
||||||
|
:layout="props.layout"
|
||||||
|
:content="props.content"
|
||||||
|
:settings="props.settings"
|
||||||
|
:section= "props.section"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { CurrentDateTime, LangSwitcher, TopNavigation, Mega } from "./index";
|
import { CurrentDateTime, LangSwitcher, TopNavigation, Mega } from "./index";
|
||||||
|
import AssignComponent from "~/components/dynamic-page/page-component/AssignComponent.vue";
|
||||||
const widgetsStore = useWidgetsStore();
|
const widgetsStore = useWidgetsStore();
|
||||||
const layoutstore = useLayoutStore();
|
const layoutstore = useLayoutStore();
|
||||||
|
import { enumPageComponentTemplates, enumPageComponentLayouts } from "@/definitions/enum";
|
||||||
const { weather } = storeToRefs(widgetsStore);
|
const { weather } = storeToRefs(widgetsStore);
|
||||||
const { megaMenuActive } = storeToRefs(layoutstore);
|
const { megaMenuActive } = storeToRefs(layoutstore);
|
||||||
|
|
||||||
@@ -87,7 +88,9 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<TopNavigation />
|
<div class="top-navigation">
|
||||||
|
<AssignComponent :type="enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-TOP']" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<Mega />
|
<Mega />
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import DynamicLayout from '~/components/dynamic-page/page/layouts/index.vue';
|
import DynamicLayout from "~/components/dynamic-page/page/layouts/index.vue";
|
||||||
import HeaderHomeTemplate from '~/components/dynamic-page/page/templates/components/headers/HeaderHomeTemplate.vue'
|
import HeaderHomeTemplate from "~/components/dynamic-page/page/templates/components/headers/HeaderHomeTemplate.vue";
|
||||||
import FooterHomeTemplate from '~/components/dynamic-page/page/templates/components/footers/FooterHomeTemplate.vue'
|
import FooterHomeTemplate from "~/components/dynamic-page/page/templates/components/footers/FooterHomeTemplate.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
settings?: any
|
settings?: any;
|
||||||
}>()
|
}>();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<HeaderHomeTemplate />
|
<HeaderHomeTemplate>
|
||||||
<DynamicLayout :settings="props.settings">
|
<DynamicLayout :settings="props.settings">
|
||||||
<slot />
|
<slot />
|
||||||
</DynamicLayout>
|
</DynamicLayout>
|
||||||
<FooterHomeTemplate />
|
</HeaderHomeTemplate>
|
||||||
</div>
|
<DynamicLayout :settings="props.settings">
|
||||||
|
<slot />
|
||||||
|
</DynamicLayout>
|
||||||
|
<FooterHomeTemplate />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ const getCurrentTemplate = computed(() => {
|
|||||||
return _props.settings && _props.settings.template || '';
|
return _props.settings && _props.settings.template || '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(getCurrentTemplate.value, 'tempalte')
|
||||||
|
|
||||||
const GET_PROPS = computed(() => {
|
const GET_PROPS = computed(() => {
|
||||||
return () => {
|
return () => {
|
||||||
let props : any = {};
|
let props : any = {};
|
||||||
|
|||||||
@@ -169,6 +169,11 @@ export const pageComponentLayouts = {
|
|||||||
[`${enumPageComponentTemplates.CATEGORY}`]: [
|
[`${enumPageComponentTemplates.CATEGORY}`]: [
|
||||||
{ title: "Danh mục", value: enumPageComponentLayouts[enumPageComponentTemplates.CATEGORY]['DEFAULT'] }
|
{ title: "Danh mục", value: enumPageComponentLayouts[enumPageComponentTemplates.CATEGORY]['DEFAULT'] }
|
||||||
],
|
],
|
||||||
|
[`${enumPageComponentTemplates.NAVIGATION}`]: [
|
||||||
|
{ title: "Thanh điều hướng ở đầu trang", value: enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-TOP'] },
|
||||||
|
{ title: "Tab điều hướng trong các phân vùng", value: enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-BOTTOM'] },
|
||||||
|
{ title: "Bộ điều hướng ở chân trang", value: enumPageComponentLayouts[enumPageComponentTemplates.NAVIGATION]['NAVIGATION-DIRECTION'] },
|
||||||
|
],
|
||||||
[`${enumPageComponentTemplates.COLLECTION}`]: [
|
[`${enumPageComponentTemplates.COLLECTION}`]: [
|
||||||
{ title: "Cụm Bài viết 5 phần tử, Bài viết ngang", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5'] },
|
{ title: "Cụm Bài viết 5 phần tử, Bài viết ngang", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5'] },
|
||||||
{ title: "Cụm Bài viết Mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['DEFAULT'] },
|
{ title: "Cụm Bài viết Mặc định", value: enumPageComponentLayouts[enumPageComponentTemplates.COLLECTION]['DEFAULT'] },
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export { PublishTypes as publishTypes } from "./publishTypes.enum";
|
export { PublishTypes as publishTypes } from "./publishTypes.enum";
|
||||||
export { categoryTypes } from "./categoryTypes.enum";
|
export { categoryTypes } from "./categoryTypes.enum";
|
||||||
export { templates, layouts, dataTypes, dataQuery, sectionTypes, sectionTaxonomy, enumPageType, enumPageSectionLayouts, enumPageComponentLayouts, enumPageComponentTemplates } from "./page.enum";
|
export { templates, layouts, dataTypes, dataQuery, sectionTypes, sectionTaxonomy, enumPageType, enumPageSectionLayouts, enumPageComponentLayouts, enumPageComponentTemplates, enumPageComponentStaticChild } from "./page.enum";
|
||||||
export { enumStatus } from "./status.enum";
|
export { enumStatus } from "./status.enum";
|
||||||
export { actionCommands } from "./actionCommands.enum";
|
export { actionCommands } from "./actionCommands.enum";
|
||||||
export { moduleCodes } from "./module.enum";
|
export { moduleCodes } from "./module.enum";
|
||||||
|
|||||||
@@ -119,7 +119,9 @@ export const enumPageComponentTemplates = { // KHÔNG ĐƯỢC XÓA KEY - BIẾN
|
|||||||
QUIZ: "Quiz", // Trang quiz
|
QUIZ: "Quiz", // Trang quiz
|
||||||
SURVEY: "Survey", // Trang survey
|
SURVEY: "Survey", // Trang survey
|
||||||
ADVERTISING: "Advertising", // Trang quảng cáo
|
ADVERTISING: "Advertising", // Trang quảng cáo
|
||||||
OTHER: "Other" // Trang khác
|
OTHER: "Other", // Trang khác
|
||||||
|
NAVIGATION: "Navigation" // Navigation
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const enumPageComponentLayouts = {
|
export const enumPageComponentLayouts = {
|
||||||
@@ -137,6 +139,11 @@ export const enumPageComponentLayouts = {
|
|||||||
NONE: "None",
|
NONE: "None",
|
||||||
'DEFAULT': "DEFAULT"
|
'DEFAULT': "DEFAULT"
|
||||||
},
|
},
|
||||||
|
[`${enumPageComponentTemplates.NAVIGATION}`]: {
|
||||||
|
'NAVIGATION-TOP': "TYPE:Navigation-PLACEMENT:Top",
|
||||||
|
'NAVIGATION-BOTTOM': "TYPE:Navigation-PLACEMENT:Bottom",
|
||||||
|
'NAVIGATION-DIRECTION': 'TYPE:Navigation-PLACEMENT:Direction',
|
||||||
|
},
|
||||||
[`${enumPageComponentTemplates.COLLECTION}`]: {
|
[`${enumPageComponentTemplates.COLLECTION}`]: {
|
||||||
'ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5': 'TYPE:Article-LAYOUT:vertical-DATA:HORIZONTAL-MAX:5'
|
'ARTICLE-VERTICAL-|HORIZONTAL|-MAX_5': 'TYPE:Article-LAYOUT:vertical-DATA:HORIZONTAL-MAX:5'
|
||||||
},
|
},
|
||||||
@@ -148,3 +155,8 @@ export const enumPageComponentLayouts = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const enumPageComponentStaticChild = {
|
||||||
|
LAYOUT: "Layout", // Không xác định
|
||||||
|
DEFAULT: "Default", // Chuyên trang
|
||||||
|
};
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ watch(currentPage, () => {
|
|||||||
useHead({
|
useHead({
|
||||||
title: 'Trang chủ'
|
title: 'Trang chủ'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface PageComponentSettings {
|
|||||||
dataQuery?: string; // Truy vấn dữ liệu: IDS | NEW | VIEW | SQL | REQUEST | ...
|
dataQuery?: string; // Truy vấn dữ liệu: IDS | NEW | VIEW | SQL | REQUEST | ...
|
||||||
dataResult?: string; // Kết quả dữ liệu (Json)
|
dataResult?: string; // Kết quả dữ liệu (Json)
|
||||||
}
|
}
|
||||||
interface PageSection extends Base {
|
export type PageSection = {
|
||||||
id?: number; // Mã định danh
|
id?: number; // Mã định danh
|
||||||
siteId?: number; // Mã hệ thống
|
siteId?: number; // Mã hệ thống
|
||||||
pageId?: number; // Mã trang
|
pageId?: number; // Mã trang
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export type PollOption = {
|
|||||||
type?: number; // Phân loại
|
type?: number; // Phân loại
|
||||||
order?: number; // Sắp xếp
|
order?: number; // Sắp xếp
|
||||||
status?: number; // Trạng thái
|
status?: number; // Trạng thái
|
||||||
responsesCount?: number //số lượng response của option
|
responseCount?: number //số lượng response của option
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchByPollId = async (event: H3Event) => {
|
export const fetchByPollId = async (event: H3Event) => {
|
||||||
|
|||||||
@@ -871,6 +871,7 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
// "updatedOn": "2024-05-30T16:18:55.254121"
|
// "updatedOn": "2024-05-30T16:18:55.254121"
|
||||||
// })
|
// })
|
||||||
currentPage.value = {}
|
currentPage.value = {}
|
||||||
|
console.log(currentPage.value, data.value, 'dynamic page')
|
||||||
currentPage.value = data.value
|
currentPage.value = data.value
|
||||||
} catch (error: any) {}
|
} catch (error: any) {}
|
||||||
}
|
}
|
||||||
@@ -895,18 +896,19 @@ export const useDynamicPageStore = defineStore("dynamicPageStore", () => {
|
|||||||
(section: any) => section.isPublished && !contentArr.flat().some((_section: any) => _section && _section.data && _section.type === "section" && section.id === _section.data)
|
(section: any) => section.isPublished && !contentArr.flat().some((_section: any) => _section && _section.data && _section.type === "section" && section.id === _section.data)
|
||||||
).sort((a: any, b: any) => a.order - b.order);
|
).sort((a: any, b: any) => a.order - b.order);
|
||||||
|
|
||||||
console.log(sectionPublished.value, 'section');
|
console.log(sectionPublished.value, 'sections');
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const setComponentPublished = () => {
|
const setComponentPublished = () => {
|
||||||
|
const exsitsTemplate = ['None']
|
||||||
const contentArr: any = [];
|
const contentArr: any = [];
|
||||||
currentPage.value.sections && currentPage.value.sections.map((section: any) => {
|
currentPage.value.sections && currentPage.value.sections.map((section: any) => {
|
||||||
contentArr.push(section.content && JSON.parse(section.content) && JSON.parse(section.content));
|
contentArr.push(section.content && JSON.parse(section.content) && JSON.parse(section.content));
|
||||||
return section;
|
return section;
|
||||||
});
|
});
|
||||||
componentPublished.value = currentPage.value.components && currentPage.value.components.filter((section: any) => section.isPublished);
|
componentPublished.value = currentPage.value.components && currentPage.value.components.filter((section: any) => section.isPublished);
|
||||||
console.log(componentPublished.value ,'123123')
|
console.log(currentPage.value.components ,'components 2')
|
||||||
};
|
};
|
||||||
|
|
||||||
const setDataQuery = (query: any, componentId: number | string) => {
|
const setDataQuery = (query: any, componentId: number | string) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user