公告新增全部显示内容

This commit is contained in:
于肖磊
2026-05-18 16:18:48 +08:00
parent 1e653cb53c
commit 84395a14ba
4 changed files with 271 additions and 69 deletions

View File

@ -49,9 +49,13 @@
</div>
</template>
<template v-else-if="form.notice_style == 'marquee'">
<div class="news-box news-box-marquee" :style="container_background_style">
<div class="news-marquee-row flex-row align-c gap-y-8" :style="container_background_img_style">
<div class="flex-shrink-0 flex-row align-c">
<div
class="news-box news-box-marquee"
:class="{ 'news-box-marquee--full': is_marquee_full_display }"
:style="container_background_style"
>
<div class="news-marquee-row flex-row gap-y-8" :style="container_background_img_style">
<div class="flex-shrink-0 flex-row" :style="left_icon_container_style">
<template v-if="form.title_type == 'img-icon'">
<div v-if="!isEmpty(form.img_src)">
<image-empty v-model="form.img_src[0]" :style="img_style"></image-empty>
@ -64,36 +68,45 @@
<div :style="topic_style" class="pl-6 pr-6 radius-sm">{{ form.title }}</div>
</template>
</div>
<template v-if="marquee_scroll_enabled">
<!-- 与销售记录横向平移一致free-mode + linear + delay:0 + speed 用间隔时间 -->
<div class="news-marquee-viewport flex-1 flex-width swiper-free-mode swiper-horizontal-free-mode">
<swiper
:key="marquee_swiper_key"
class="news-marquee-swiper w flex"
direction="horizontal"
:modules="swiper_modules"
:loop="true"
slides-per-view="auto"
:space-between="marquee_scroll_gap"
:allow-touch-move="false"
:autoplay="marquee_swiper_autoplay"
:speed="marquee_swiper_speed"
>
<swiper-slide v-for="i in marquee_swiper_slides" :key="i" class="news-marquee-slide">
<div class="news-marquee-slide-inner flex-row align-c">
<div class="news-marquee-slide-text news-marquee-slide-text--scroll" :style="`${news_style} color: ${new_style.news_color}`">{{ marquee_display_text }}</div>
</div>
</swiper-slide>
</swiper>
<!-- 全部显示文本完整显示不滚动超出换行 -->
<template v-if="form.is_full_display === '1'">
<div class="news-marquee-full flex-1 flex-width">
<div class="news-marquee-full-text" :style="`${news_style} color: ${new_style.news_color}`">{{ marquee_display_text }}</div>
</div>
</template>
<!-- 全部显示关闭文本隐藏显示滚动效果 -->
<template v-else>
<template v-if="marquee_scroll_enabled">
<!-- 与销售记录横向平移一致free-mode + linear + delay:0 + speed 用间隔时间 -->
<div class="news-marquee-viewport flex-1 flex-width swiper-free-mode swiper-horizontal-free-mode">
<swiper
:key="marquee_swiper_key"
class="news-marquee-swiper w flex"
direction="horizontal"
:modules="swiper_modules"
:loop="true"
slides-per-view="auto"
:space-between="marquee_scroll_gap"
:allow-touch-move="false"
:autoplay="marquee_swiper_autoplay"
:speed="marquee_swiper_speed"
>
<swiper-slide v-for="i in marquee_swiper_slides" :key="i" class="news-marquee-slide">
<div class="news-marquee-slide-inner flex-row align-c">
<div class="news-marquee-slide-text news-marquee-slide-text--scroll" :style="`${news_style} color: ${new_style.news_color}`">{{ marquee_display_text }}</div>
</div>
</swiper-slide>
</swiper>
</div>
</template>
<div v-else class="news-marquee-static flex-1 flex-width">
<div class="news-marquee-static-text" :style="`${news_style} color: ${new_style.news_color}`">{{ marquee_display_text }}</div>
</div>
</template>
<div v-else class="news-marquee-static flex-1 flex-width">
<div class="news-marquee-static-text" :style="`${news_style} color: ${new_style.news_color}`">{{ marquee_display_text }}</div>
</div>
<div
v-if="form.is_right_button == '1'"
class="flex-shrink-0 flex-row align-c"
:style="`color: ${new_style.right_button_color}; font-size: ${new_style.right_button_size}px`"
class="flex-shrink-0 flex-row"
:style="`${right_icon_container_style} color: ${new_style.right_button_color}; font-size: ${new_style.right_button_size}px`"
>
{{ form.right_title }}<icon name="arrow-right" :color="new_style.right_button_color || '#999'"></icon>
</div>
@ -130,8 +143,15 @@ const { form, new_style } = toRefs(state);
// 用于样式显示
const style_container = computed(() => common_styles_computer(new_style.value.common_style));
const style_img_container = computed(() => common_img_computer(new_style.value.common_style));
/** 样式三且开启全部显示:由内容撑开,不使用固定高度 */
const is_marquee_full_display = computed(
() => form.value.notice_style === 'marquee' && form.value.is_full_display === '1'
);
// 容器高度
const container_height = computed(() => new_style.value.container_height + 'px');
const container_height = computed(() => {
if (is_marquee_full_display.value) return 'auto';
return new_style.value.container_height + 'px';
});
// 容器背景
const container_background_style = computed(() => {
const { container_color_list, container_direction, container_background_img_style, container_background_img} = new_style.value;
@ -151,17 +171,19 @@ const container_background_img_style = computed(() => {
background_img_style: container_background_img_style,
};
let padding = '';
// 不等于空的时候使用新数据
const inherit_padding = { padding: 0, padding_top: 0, padding_right: 10, padding_bottom: 0, padding_left: 10 };
const card_padding = { padding: 15, padding_top: 15, padding_right: 15, padding_bottom: 15, padding_left: 15 };
let pad: Record<string, number>;
if (!isEmpty(container_padding)) {
padding = padding_computer(container_padding);
pad = { ...container_padding };
} else if (form.value.notice_style === 'inherit') {
pad = { ...inherit_padding };
} else if (form.value.notice_style === 'card') {
pad = { ...card_padding };
} else {
// 为空的时候使用默认数据,兼容老数据没有这个值时的处理
let old_padding = { padding: 15, padding_top: 15, padding_right: 15, padding_bottom: 15, padding_left: 15 };
if (form.value.notice_style === 'inherit' || form.value.notice_style === 'marquee') {
old_padding = { padding: 0, padding_top: 0, padding_right: 10, padding_bottom: 0, padding_left: 10, }
}
padding = padding_computer(old_padding);
pad = { ...inherit_padding };
}
padding = padding_computer(pad);
return background_computer(styles) + padding + `overflow:hidden;`;
});
// 图片设置
@ -195,6 +217,46 @@ const notice_list = computed(() => {
return arry_list.filter((item: { is_show: string }) => item.is_show == '1');
});
// 图标位置映射
const get_icon_align = (position: string) => {
const alignMap: Record<string, string> = {
top: 'flex-start',
center: 'center',
bottom: 'flex-end'
};
return alignMap[position] || 'center';
};
const default_icon_margin = { padding: 0, padding_top: 0, padding_right: 0, padding_bottom: 0, padding_left: 0 };
const build_icon_container_style = (position?: string, margin?: paddingStyle) => {
const align = get_icon_align(position || 'center');
const m = margin || default_icon_margin;
const mt = Number(m.padding_top || 0);
const mr = Number(m.padding_right || 0);
const mb = Number(m.padding_bottom || 0);
const ml = Number(m.padding_left || 0);
return `align-items: ${align}; margin-top: ${mt}px; margin-right: ${mr}px; margin-bottom: ${mb}px; margin-left: ${ml}px;`;
};
/** 左侧图标容器样式 */
const left_icon_container_style = computed(() => {
const legacy_position = new_style.value.icon_position;
const legacy_margin = new_style.value.icon_margin;
const position = new_style.value.left_icon_position || legacy_position || 'center';
const margin = new_style.value.left_icon_margin || legacy_margin || default_icon_margin;
return build_icon_container_style(position, margin);
});
/** 右侧更多按钮图标容器样式 */
const right_icon_container_style = computed(() => {
const legacy_position = new_style.value.icon_position;
const legacy_margin = new_style.value.icon_margin;
const position = new_style.value.right_icon_position || legacy_position || 'center';
const margin = new_style.value.right_icon_margin || legacy_margin || default_icon_margin;
return build_icon_container_style(position, margin);
});
const marquee_scroll_enabled = computed(() => form.value.marquee_scroll != '0');
const marquee_display_text = computed(() => {
@ -211,7 +273,7 @@ const marquee_swiper_slides = computed(() => Array.from({ length: marquee_repeat
const marquee_swiper_key = computed(
() =>
`notice-marquee-${marquee_display_text.value}-${form.value.interval_time}-${form.value.marquee_scroll}-${form.value.notice_style}`
`notice-marquee-${marquee_display_text.value}-${form.value.interval_time}-${form.value.marquee_scroll}-${form.value.notice_style}-${form.value.is_full_display}`
);
/** 与销售记录横向 translation 一致delay 0 + waitForTransition靠 speed 控制平移快慢 */
@ -273,6 +335,11 @@ watchEffect(() => {
flex-direction: column;
justify-content: center;
}
/* 全部显示:高度随内容,不固定、不自适应占位 */
.news-box-marquee--full {
height: auto;
min-height: 0;
}
.num {
padding-right: 0.7rem;
color: #999;
@ -304,7 +371,7 @@ watchEffect(() => {
.news-marquee-row {
width: 100%;
align-items: center;
align-items: stretch;
}
.news-marquee-viewport {
flex: 1 1 0;
@ -313,7 +380,7 @@ watchEffect(() => {
overflow: hidden;
display: flex;
align-items: center;
align-self: stretch;
align-self: center;
position: relative;
/* 供 slide 使用 cqi每条至少占满中间区域宽度短文案不再并排「切片」 */
container-type: inline-size;
@ -361,7 +428,7 @@ watchEffect(() => {
overflow: hidden;
display: flex;
align-items: center;
align-self: stretch;
align-self: center;
}
.news-marquee-static-text {
width: 100%;
@ -370,4 +437,21 @@ watchEffect(() => {
white-space: nowrap;
text-overflow: ellipsis;
}
/* 全部显示:文本完整显示,超出换行 */
.news-marquee-full {
flex: 1 1 0;
min-width: 0;
overflow: visible;
display: flex;
align-items: center;
align-self: center;
}
.news-marquee-full-text {
width: 100%;
min-width: 0;
overflow: visible;
white-space: normal;
word-break: break-all;
word-wrap: break-word;
}
</style>

View File

@ -30,12 +30,17 @@
</el-form-item>
<template v-if="!is_card">
<template v-if="is_marquee">
<el-form-item label="开启滚动">
<el-switch v-model="form.marquee_scroll" active-value="1" inactive-value="0"></el-switch>
</el-form-item>
<el-form-item v-if="form.marquee_scroll === '1'" label="间隔时间">
<slider v-model="form.interval_time" :min="1" :max="100"></slider>
<el-form-item label="全部显示">
<el-switch v-model="form.is_full_display" active-value="1" inactive-value="0"></el-switch>
</el-form-item>
<template v-if="form.is_full_display !== '1'">
<el-form-item label="开启滚动">
<el-switch v-model="form.marquee_scroll" active-value="1" inactive-value="0"></el-switch>
</el-form-item>
<el-form-item v-if="form.marquee_scroll === '1'" label="间隔时间">
<slider v-model="form.interval_time" :min="1" :max="100"></slider>
</el-form-item>
</template>
</template>
<template v-else>
<el-form-item label="滚动方式">
@ -75,8 +80,6 @@
type="textarea"
:rows="3"
placeholder="请输入公告文字"
maxlength="500"
show-word-limit
clearable
></el-input>
</el-form-item>
@ -132,6 +135,25 @@ if (form.value.marquee_content == null || form.value.marquee_content === undefin
if (form.value.marquee_scroll == null || form.value.marquee_scroll === undefined) {
form.value.marquee_scroll = '1';
}
if (form.value.is_full_display == null || form.value.is_full_display === undefined) {
form.value.is_full_display = '1';
}
const INHERIT_PADDING = {
padding: 0,
padding_top: 0,
padding_right: 10,
padding_bottom: 0,
padding_left: 10,
};
const CARD_PADDING = {
padding: 15,
padding_top: 15,
padding_right: 15,
padding_bottom: 15,
padding_left: 15,
};
const sync_marquee_from_list = () => {
const t = String(form.value.marquee_content ?? '').trim();
@ -142,30 +164,49 @@ const sync_marquee_from_list = () => {
}
};
const change_style = (val: string | number | boolean | undefined) => {
if (val === 'inherit' || val === 'marquee') {
new_style.value.container_padding = {
padding: 0,
padding_top: 0,
padding_right: 10,
padding_bottom: 0,
padding_left: 10,
};
} else {
new_style.value.container_padding = {
padding: 15,
padding_top: 15,
padding_right: 15,
padding_bottom: 15,
padding_left: 15,
};
/** 原地更新内边距,避免替换对象导致 padding 组件持有旧引用 */
const apply_container_padding = (patch: Record<string, number>) => {
if (!new_style.value.container_padding) {
new_style.value.container_padding = { ...patch };
return;
}
Object.assign(new_style.value.container_padding, patch);
};
/** 样式三:全部显示时上下 14关闭时上下 0左右保持 10 */
const sync_marquee_padding = () => {
const tb = form.value.is_full_display === '1' ? 14 : 0;
const cp = new_style.value.container_padding || {};
apply_container_padding({
padding: 0,
padding_top: tb,
padding_right: cp.padding_right ?? 10,
padding_bottom: tb,
padding_left: cp.padding_left ?? 10,
});
};
const change_style = (val: string | number | boolean | undefined) => {
if (val === 'marquee') {
sync_marquee_padding();
sync_marquee_from_list();
// 仅切换到样式三时统一左侧图标为喇叭,样式一/二不改动
form.value.icon_class = 'speaker';
} else if (val === 'inherit') {
apply_container_padding(INHERIT_PADDING);
} else {
apply_container_padding(CARD_PADDING);
}
};
watch(
() => form.value.is_full_display,
() => {
if (is_marquee.value) {
sync_marquee_padding();
}
}
);
const add = () => {
form.value.notice_list.push({
id: get_math(),
@ -185,6 +226,7 @@ const on_sort = (new_list: nav_group[]) => {
onMounted(() => {
if (is_marquee.value) {
sync_marquee_from_list();
sync_marquee_padding();
}
});
</script>

View File

@ -37,6 +37,19 @@
</el-form-item>
</template>
</template>
<!-- 样式三全部显示左侧图标位置与外边距 -->
<template v-if="is_marquee_full_display">
<el-form-item label="图标位置">
<el-radio-group v-model="form.left_icon_position">
<el-radio value="top">居上</el-radio>
<el-radio value="center">居中</el-radio>
<el-radio value="bottom">居下</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图标外边距">
<padding v-model:value="form.left_icon_margin"></padding>
</el-form-item>
</template>
<el-form-item label="内容标题">
<color-text-size-group v-model:color="form.news_color" v-model:typeface="form.news_typeface" v-model:size="form.news_size" default-color="#000000"></color-text-size-group>
</el-form-item>
@ -50,20 +63,37 @@
<el-form-item label="按钮文字">
<slider v-model="form.right_button_size" :max="100"></slider>
</el-form-item>
<!-- 样式三全部显示右侧更多按钮图标位置与外边距 -->
<template v-if="is_marquee_full_display">
<el-form-item label="图标位置">
<el-radio-group v-model="form.right_icon_position">
<el-radio value="top">居上</el-radio>
<el-radio value="center">居中</el-radio>
<el-radio value="bottom">居下</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="图标外边距">
<padding v-model:value="form.right_icon_margin"></padding>
</el-form-item>
</template>
</card-container>
<div class="bg-f5 divider-line" />
<card-container>
<div class="mb-12">容器设置</div>
<template v-if="substance.notice_style === 'inherit' || substance.notice_style === 'marquee'">
<!-- 样式三开启全部显示时不配置固定高度由内容撑开 -->
<template v-if="show_container_height">
<el-form-item label="高度">
<slider v-model="form.container_height" :max="1000"></slider>
<slider v-model="form.container_height" :min="1" :max="1000"></slider>
</el-form-item>
</template>
<el-form-item label="背景">
<background-common v-model:color_list="form.container_color_list" v-model:direction="form.container_direction" v-model:img_style="form.container_background_img_style" v-model:img="form.container_background_img" @mult_color_picker_event="mult_color_picker_event" />
</el-form-item>
<el-form-item label="内边距">
<padding :value="form.container_padding"></padding>
<padding
:key="`notice-container-padding-${substance.notice_style}-${substance.is_full_display}`"
v-model:value="form.container_padding"
></padding>
</el-form-item>
<el-form-item label="圆角">
<radius :value="form.container_radius"></radius>
@ -94,6 +124,16 @@ const state = reactive({
const { form, substance } = toRefs(state);
const is_img = computed(() => substance.value.title_type == 'img-icon');
/** 样式三且开启全部显示 */
const is_marquee_full_display = computed(
() => substance.value.notice_style == 'marquee' && substance.value.is_full_display === '1'
);
/** 样式一固定高度;样式三未开启全部显示时固定高度 */
const show_container_height = computed(() => {
if (substance.value.notice_style === 'inherit') return true;
if (substance.value.notice_style === 'marquee' && substance.value.is_full_display !== '1') return true;
return false;
});
const common_styles_update = (val: Object) => {
form.value.common_style = val;

View File

@ -20,6 +20,8 @@ interface defaultSearch {
marquee_content: string;
/** 样式三是否开启横向滚动1/0 */
marquee_scroll: string;
/** 样式三是否全部显示1/0 */
is_full_display: string;
/** 兼容旧数据,样式三已不再使用 */
notice_left_img: uploadList[];
notice_right_img: uploadList[];
@ -43,6 +45,15 @@ interface defaultSearch {
title_width: number;
title_height: number;
container_height: number;
/** 样式三全部显示:左侧图标垂直对齐 */
left_icon_position: string;
left_icon_margin: paddingStyle;
/** 样式三全部显示:右侧更多图标垂直对齐 */
right_icon_position: string;
right_icon_margin: paddingStyle;
/** 兼容旧数据 */
icon_position: string;
icon_margin: paddingStyle;
icon_size: number;
icon_color: string;
/** 兼容旧数据 */
@ -70,6 +81,7 @@ const defaultSearch: defaultSearch = {
img_src: [],
marquee_content: '',
marquee_scroll: '1',
is_full_display: '1',
notice_left_img: [],
notice_right_img: [],
// 滚动方式
@ -120,6 +132,30 @@ const defaultSearch: defaultSearch = {
right_button_size: 12,
// 容器高度
container_height: 44,
left_icon_position: 'center',
left_icon_margin: {
padding: 0,
padding_top: 0,
padding_right: 0,
padding_bottom: 0,
padding_left: 0,
},
right_icon_position: 'center',
right_icon_margin: {
padding: 0,
padding_top: 0,
padding_right: 0,
padding_bottom: 0,
padding_left: 0,
},
icon_position: 'center',
icon_margin: {
padding: 0,
padding_top: 0,
padding_right: 0,
padding_bottom: 0,
padding_left: 0,
},
// 容器信息
container_color_list: [{ color: '#fff', color_percentage: undefined }],
container_direction: '180deg',