374 lines
15 KiB
Vue
374 lines
15 KiB
Vue
<template>
|
||
<div class="oh" :style="style_container">
|
||
<div :style="style_img_container">
|
||
<div class="re oh" :style="style">
|
||
<div v-if="!['4'].includes(article_theme)" class="flex-warp" :class="article_theme_class" :style="article_theme != '3' ? article_spacing : ''">
|
||
<div v-for="(item, index) in data_list" :key="index" class="item bg-f oh" :class="article_theme == '0' ? 'flex-row' : 'flex-col'" :style="article_style">
|
||
<template v-if="article_theme != '3'">
|
||
<template v-if="item.new_cover.length > 0">
|
||
<image-empty v-model="item.new_cover[0].url" class="img" :style="img_radius" :error-img-style="error_img"></image-empty>
|
||
</template>
|
||
<template v-else> <image-empty v-model="item.data.cover" class="img" :style="img_radius" :error-img-style="error_img"></image-empty> </template>
|
||
</template>
|
||
<div class="jc-sb flex-1" :class="article_theme == '3' ? 'flex-row align-c' : 'flex-col'" :style="article_theme != '0' ? content_padding : ''">
|
||
<div class="title" :class="article_theme == '3' ? 'text-line-1 flex-1 flex-width' : 'text-line-2'" :style="article_name">{{ !isEmpty(item.new_title) ? item.new_title : item.data.title }}</div>
|
||
<div class="flex-row jc-sb gap-8" :class="article_theme == '3' ? 'ml-10' : 'align-e mt-10'">
|
||
<div :style="article_date">{{ field_show.includes('0') ? (!is_obj_empty(item.data) ? item.data.add_time : '2020-06-05 15:20') : '' }}</div>
|
||
<div v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||
<icon name="eye"></icon>
|
||
<div>
|
||
{{ item.data.access_count ? item.data.access_count : '16' }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div v-else class="oh" :class="article_theme_class">
|
||
<el-carousel :key="carousel_key" indicator-position="none" :interval="interval_time" arrow="never" :autoplay="is_roll ? true : false">
|
||
<el-carousel-item v-for="(item1, index1) in article_carousel_list" :key="index1" class="flex" :style="article_spacing">
|
||
<div v-for="(item, index) in item1.carousel_list" :key="index" class="item bg-f oh flex-col" :style="article_style">
|
||
<template v-if="item.new_cover.length > 0">
|
||
<image-empty v-model="item.new_cover[0].url" class="img" :style="img_radius" :error-img-style="error_img"></image-empty>
|
||
</template>
|
||
<template v-else> <image-empty v-model="item.data.cover" class="img" :style="img_radius" :error-img-style="error_img"></image-empty> </template>
|
||
<div class="jc-sb flex-1 flex-col" :style="article_theme != '0' ? content_padding : ''">
|
||
<div class="title text-line-2" :style="article_name">{{ !isEmpty(item.new_title) ? item.new_title : item.data.title }}</div>
|
||
<div class="flex-row jc-sb gap-8 align-e mt-10">
|
||
<div :style="article_date">{{ field_show.includes('0') ? (!is_obj_empty(item.data) ? item.data.add_time : '2020-06-05 15:20') : '' }}</div>
|
||
<div v-show="field_show.includes('1')" class="flex-row align-c gap-3" :style="article_page_view">
|
||
<icon name="eye"></icon>
|
||
<div>
|
||
{{ item.data.access_count ? item.data.access_count : '16' }}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-carousel-item>
|
||
</el-carousel>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { common_styles_computer, padding_computer, radius_computer, get_math, is_obj_empty, common_img_computer } from '@/utils';
|
||
import { isEmpty, cloneDeep } from 'lodash';
|
||
import ArticleAPI from '@/api/article';
|
||
/**
|
||
* @description: 文章列表(渲染)
|
||
* @param value{Object} 样式数据
|
||
* @param isCommonStyle{Object} 是否为通用样式
|
||
*/
|
||
const props = defineProps({
|
||
value: {
|
||
type: Object,
|
||
default: () => ({}),
|
||
},
|
||
isCommonStyle: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
});
|
||
const error_img = ref('width:50px;padding:10px;');
|
||
const style = ref('');
|
||
const style_container = ref('');
|
||
const style_img_container = ref('');
|
||
interface dataObj {
|
||
cover?: string;
|
||
add_time?: string;
|
||
access_count?: string;
|
||
title?: string;
|
||
}
|
||
interface ArticleList {
|
||
id: number | string;
|
||
data: dataObj;
|
||
new_title: string;
|
||
new_cover: uploadList[];
|
||
}
|
||
// 数据
|
||
const data_list = ref<ArticleList[]>([]);
|
||
// 风格
|
||
const article_theme = ref('0');
|
||
// 是否显示
|
||
const field_show = ref(['0', '1']);
|
||
// 文章
|
||
const article_name = ref('');
|
||
// 日期
|
||
const article_date = ref('');
|
||
// 浏览量
|
||
const article_page_view = ref('');
|
||
// 内容圆角
|
||
const content_radius = ref('');
|
||
// 图片圆角
|
||
const img_radius = ref('');
|
||
// 内间距
|
||
const content_padding = ref('');
|
||
// 内容间距
|
||
const content_spacing = ref('');
|
||
// 文章间距
|
||
const article_spacing = ref('');
|
||
const article_item_height = ref('155');
|
||
|
||
const article_style = ref({});
|
||
const default_data_list: ArticleList = {
|
||
id: 0,
|
||
data: {},
|
||
new_title: '测试文章标题',
|
||
new_cover: [],
|
||
};
|
||
// 轮播图列数
|
||
const carousel_col = ref('2');
|
||
// 轮播图key值
|
||
const carousel_key = ref('0');
|
||
// 轮播图定时轮播
|
||
const interval_time = ref(2000);
|
||
// 轮播图是否滚动
|
||
const is_roll = ref(1);
|
||
// 获取自动数据
|
||
const get_auto_data_list = async () => {
|
||
const { category_ids, number, order_by_type, order_by_rule, is_cover } = new_content.value;
|
||
const new_data = {
|
||
article_keywords: '',
|
||
article_category_ids: category_ids.join(','),
|
||
article_order_by_type: order_by_type,
|
||
article_order_by_rule: order_by_rule,
|
||
article_number: number,
|
||
article_is_cover: is_cover,
|
||
};
|
||
const res = await ArticleAPI.getAutoList(new_data);
|
||
new_content.value.data_auto_list = [];
|
||
if (!isEmpty(res.data)) {
|
||
data_list.value = [];
|
||
res.data.forEach((child: any) => {
|
||
data_list.value.push({
|
||
id: get_math(),
|
||
new_title: '',
|
||
new_cover: [],
|
||
data: child,
|
||
});
|
||
new_content.value.data_auto_list.push({
|
||
id: get_math(),
|
||
new_title: '',
|
||
new_cover: [],
|
||
data: child,
|
||
});
|
||
});
|
||
} else {
|
||
data_list.value = Array(4).fill(default_data_list);
|
||
}
|
||
};
|
||
// 内容
|
||
const new_content = computed(() => props.value?.content || {});
|
||
// 样式
|
||
const new_style = computed(() => props.value?.style || {});
|
||
onMounted(() => {
|
||
// 判断数据类型是选择文章且数据不为空
|
||
if (new_content.value.data_type == '0' && !isEmpty(new_content.value.data_list)) {
|
||
data_list.value = new_content.value.data_list;
|
||
} else if (new_content.value.data_type == '1' && !isEmpty(new_content.value.data_auto_list)) {
|
||
// 判断数据是筛选文章且数据不为空
|
||
data_list.value = new_content.value.data_auto_list.map((item: any) => ({
|
||
id: get_math(),
|
||
new_title: '',
|
||
new_cover: [],
|
||
data: item,
|
||
}));
|
||
} else {
|
||
// 否则走默认数据
|
||
data_list.value = Array(4).fill(default_data_list);
|
||
}
|
||
});
|
||
// 监听new_content指定的数据变化
|
||
const data_list_computer = computed(() => {
|
||
const { data_type, category_ids, number, order_by_type, order_by_rule, is_cover, data_list } = new_content.value;
|
||
return { data_type, category_ids, number, order_by_type, order_by_rule, is_cover, data_list };
|
||
});
|
||
// 监听new_content指定的数据的变化,来获取最新数据
|
||
watch(
|
||
() => data_list_computer.value,
|
||
(new_value, old_value) => {
|
||
// 使用JSON.stringify()进行判断 新值和旧值是否一样 不一样就重新获取数据
|
||
if (JSON.stringify(new_value) !== JSON.stringify(old_value) || props.isCommonStyle) {
|
||
if (new_value.data_type == '1') {
|
||
get_auto_data_list();
|
||
} else {
|
||
if (!isEmpty(new_content.value.data_list)) {
|
||
data_list.value = cloneDeep(new_content.value.data_list);
|
||
} else {
|
||
data_list.value = Array(4).fill(default_data_list);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
{ deep: true }
|
||
);
|
||
// 轮播宽度
|
||
const multicolumn_columns_width = computed(() => {
|
||
const { carousel_col } = toRefs(new_content.value);
|
||
// 计算间隔的空间。(gap * gap数量) / 模块数量
|
||
let gap = carousel_col.value != '0' ? (new_style.value.article_spacing * carousel_col.value) / (Number(carousel_col.value) + 1) : '0';
|
||
return `calc(${100 / (Number(carousel_col.value) + 1)}% - ${gap}px)`;
|
||
});
|
||
// 文章内容高度
|
||
const article_name_height_computer = computed(() => {
|
||
return new_style.value.name_size * 2.4 + 'px';
|
||
});
|
||
// 文章行高计算
|
||
const article_name_line_height_computer = computed(() => {
|
||
return new_style.value.name_size * 1.2 + 'px';
|
||
});
|
||
// 轮播高度
|
||
const carousel_height_computer = computed(() => {
|
||
return new_style.value.name_size * 2 + new_style.value.article_height + 'px';
|
||
});
|
||
// 监听value数据变化
|
||
watch(
|
||
() => props.value,
|
||
(newVal, oldValue) => {
|
||
const new_content = newVal?.content;
|
||
const new_style = newVal?.style;
|
||
article_theme.value = new_content.theme;
|
||
field_show.value = new_content.field_show;
|
||
// 样式
|
||
article_name.value = 'font-size:' + new_style.name_size + 'px;' + 'font-weight:' + new_style.name_weight + ';' + 'color:' + new_style.name_color + ';';
|
||
article_date.value = 'font-size:' + new_style.time_size + 'px;' + 'font-weight:' + new_style.time_weight + ';' + 'color:' + new_style.time_color + ';';
|
||
article_page_view.value = 'font-size:' + new_style.page_view_size + 'px;' + 'font-weight:' + new_style.page_view_weight + ';' + 'color:' + new_style.page_view_color + ';';
|
||
content_radius.value = radius_computer(new_style.content_radius);
|
||
img_radius.value = radius_computer(new_style.img_radius);
|
||
// 内间距
|
||
content_padding.value = padding_computer(new_style.padding);
|
||
// 内容间距
|
||
content_spacing.value = `gap: ${new_style.content_spacing}px;`;
|
||
// 文章间距
|
||
article_spacing.value = `gap: ${new_style.article_spacing}px;`;
|
||
// 文章样式
|
||
article_style.value = '';
|
||
style.value = '';
|
||
if (article_theme.value == '0') {
|
||
article_style.value += content_spacing.value + content_padding.value + content_radius.value;
|
||
} else if (article_theme.value == '1') {
|
||
article_style.value += `width: calc(50% - ${new_style.article_spacing / 2}px);` + content_radius.value;
|
||
} else if (article_theme.value == '2') {
|
||
article_style.value += content_radius.value;
|
||
} else if (article_theme.value == '3') {
|
||
style.value = `padding: 0 ${new_style.content_spacing}px;background:#fff;` + content_radius.value;
|
||
} else if (article_theme.value == '4') {
|
||
// 更新轮播图的key,确保更换时能重新更新轮播图
|
||
carousel_col.value = new_content.carousel_col || '1';
|
||
carousel_key.value = new_style.interval_time + new_style.is_roll;
|
||
// 滚动时间
|
||
interval_time.value = (new_style.interval_time || 2) * 1000;
|
||
// 是否滚动修改
|
||
is_roll.value = new_style.is_roll;
|
||
article_item_height.value = `${new_style.article_height}px`;
|
||
article_style.value += content_radius.value;
|
||
}
|
||
if (new_style.common_style && props.isCommonStyle) {
|
||
style_container.value = common_styles_computer(new_style.common_style);
|
||
style_img_container.value = common_img_computer(new_style.common_style);
|
||
}
|
||
},
|
||
{ deep: true, immediate: true }
|
||
);
|
||
// 文章主题class计算
|
||
const article_theme_class = computed(() => {
|
||
switch (article_theme.value) {
|
||
case '0':
|
||
return 'style1 flex-col';
|
||
case '1':
|
||
return 'style2 flex-row flex-wrap';
|
||
case '2':
|
||
return 'style3 flex-col';
|
||
case '3':
|
||
return 'style4 flex-col';
|
||
default:
|
||
return 'style5';
|
||
}
|
||
});
|
||
|
||
interface ArticleCarouselList {
|
||
carousel_list: ArticleList[];
|
||
}
|
||
// 文章轮播
|
||
const article_carousel_list = computed(() => {
|
||
// 深拷贝一下,确保不会出现问题
|
||
const cloneList = cloneDeep(data_list.value);
|
||
// 如果是分页滑动情况下,根据选择的行数和每行显示的个数来区分具体是显示多少个
|
||
if (cloneList.length > 0) {
|
||
// 每页显示的数量
|
||
const num = Number(carousel_col.value) + 1;
|
||
// 存储数据显示
|
||
let nav_list: ArticleCarouselList[] = [];
|
||
// 拆分的数量
|
||
const split_num = Math.ceil(cloneList.length / num);
|
||
for (let i = 0; i < split_num; i++) {
|
||
nav_list.push({ carousel_list: cloneList.slice(i * num, (i + 1) * num) });
|
||
}
|
||
return nav_list;
|
||
} else {
|
||
// 否则的话,就返回全部的信息
|
||
return [{ carousel_list: cloneList }];
|
||
}
|
||
});
|
||
</script>
|
||
<style lang="scss" scoped>
|
||
.style1 {
|
||
.item {
|
||
width: 100%;
|
||
.img {
|
||
height: 8.3rem;
|
||
width: 11rem;
|
||
}
|
||
}
|
||
}
|
||
.style2 {
|
||
.item {
|
||
width: calc(50% - 0.5rem);
|
||
.img {
|
||
height: 18rem;
|
||
}
|
||
}
|
||
}
|
||
.style3 {
|
||
.item {
|
||
width: 100%;
|
||
.img {
|
||
width: 100%;
|
||
height: 18rem;
|
||
}
|
||
}
|
||
}
|
||
.style4 {
|
||
.item {
|
||
width: 100%;
|
||
&:not(:last-child) {
|
||
border-bottom: 0.1rem solid #eee;
|
||
}
|
||
}
|
||
}
|
||
.style5 {
|
||
.item {
|
||
width: v-bind(multicolumn_columns_width);
|
||
min-width: v-bind(multicolumn_columns_width);
|
||
.img {
|
||
width: 100%;
|
||
max-height: v-bind(article_item_height);
|
||
}
|
||
.title {
|
||
height: v-bind(article_name_height_computer);
|
||
line-height: v-bind(article_name_line_height_computer);
|
||
}
|
||
}
|
||
}
|
||
|
||
:deep(.el-carousel) {
|
||
width: 100%;
|
||
.el-carousel__container {
|
||
// height: v-bind(article_item_height);
|
||
height: v-bind(carousel_height_computer);
|
||
}
|
||
}
|
||
</style>
|