公告修改

This commit is contained in:
于肖磊
2026-05-19 10:24:41 +08:00
parent 7c811a3618
commit 64b841e301

View File

@ -33,11 +33,15 @@
</view>
</view>
</template>
<!-- 样式三marquee中间区 uni-notice-bar 横向滚动或静态一行 -->
<!-- 样式三marqueeis_full_display 全部显示 / marquee_scroll 横向滚动 -->
<template v-else-if="form_content.notice_style == 'marquee'">
<view class="news-box" :style="container_background_style + container_height">
<view class="flex-row align-c gap-8" :style="container_background_img_style">
<view class="flex-row align-c flex-shrink">
<view
class="news-box news-box-marquee"
:class="{ 'news-box-marquee--full': is_marquee_full_display }"
:style="marquee_box_style"
>
<view class="news-marquee-row flex-row gap-8" :style="container_background_img_style">
<view class="flex-shrink-0 flex-row align-c" :style="is_marquee_full_display ? left_icon_container_style : ''">
<template v-if="form_content.title_type == 'img-icon'">
<view v-if="form_content.img_src && form_content.img_src.length > 0">
<image :src="form_content.img_src[0].url" class="border-radius-sm dis-block" mode="aspectFill" :style="img_style"></image>
@ -50,36 +54,53 @@
<view :style="title_style" class="padding-horizontal-sm border-radius-sm">{{ form_content.title || '' }}</view>
</template>
</view>
<!-- 样式三滚动区直接使用 uni-notice-bar与官方实现一致小程序端可正常滚动 -->
<view
class="notice-marquee-host flex-1 oh notice-marquee-uni-wrap"
:style="container_height"
>
<uni-notice-bar
v-if="marquee_scroll_on"
:key="marquee_notice_bar_key"
:scrollable="true"
:show-icon="false"
:show-get-more="false"
:single="false"
:text="marquee_display_text"
:speed="marquee_notice_speed"
:color="marquee_notice_color"
:font-size="marquee_notice_font_px"
background-color="rgba(0,0,0,0)"
@click.stop="marquee_uni_click"
/>
<!-- 全部显示完整展示超出换行高度随内容 -->
<template v-if="form_content.is_full_display === '1'">
<view class="news-marquee-full flex-1 flex-width">
<view class="news-marquee-full-text" :style="marquee_body_text_style" :data-value="marquee_link_page" @tap="url_event">{{ marquee_display_text }}</view>
</view>
</template>
<!-- 非全部显示滚动或单行省略 -->
<template v-else>
<view v-if="marquee_scroll_on" class="notice-marquee-host flex-1 flex-width oh notice-marquee-uni-wrap" :style="marquee_content_height">
<!-- 用于测量文案真实宽度speed = 宽度 / interval_time DIY swiper 整段平移一致 -->
<view
:id="marquee_measure_id"
class="notice-marquee-measure"
:style="marquee_body_text_style"
>{{ marquee_display_text }}</view>
<uni-notice-bar
v-if="marquee_notice_bar_ready"
:key="marquee_notice_bar_key"
:scrollable="true"
:show-icon="false"
:show-get-more="false"
:single="false"
:text="marquee_display_text"
:speed="marquee_notice_speed"
:color="marquee_notice_color"
:font-size="marquee_notice_font_px"
background-color="rgba(0,0,0,0)"
@click.stop="marquee_uni_click"
/>
</view>
<view
v-else
class="flex-row align-c ht-auto notice-marquee-static"
:style="container_height + marquee_body_text_style"
class="news-marquee-static flex-1 flex-width"
:style="marquee_content_height"
:data-value="marquee_link_page"
@tap="url_event"
>
<view class="text-line-1 flex-1">{{ marquee_display_text }}</view>
<view class="news-marquee-static-text" :style="marquee_body_text_style">{{ marquee_display_text }}</view>
</view>
</view>
<view v-if="form_content.is_right_button == '1'" class="flex-row align-c flex-shrink" :style="'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'" :data-value="form_content.more_link.page" @tap="url_event">
</template>
<view
v-if="form_content.is_right_button == '1'"
class="flex-row align-c flex-shrink-0"
:style="(is_marquee_full_display ? right_icon_container_style : '') + 'color: ' + form_style.right_button_color + ';font-size:' + form_style.right_button_size * 2 + 'rpx;'"
:data-value="form_content.more_link.page"
@tap="url_event"
>
{{ form_content.right_title }}
<view class="pr">
<iconfont name="icon-arrow-right" :color="form_style.right_button_color || '#999'" :size="form_style.right_button_size * 2 + 'rpx'" propContainerDisplay="flex"></iconfont>
@ -88,7 +109,7 @@
</view>
</view>
</template>
<!-- 样式二默认卡片标题区 + 序号列表 -->
<!-- 样式二card标题区 + 序号列表 -->
<template v-else>
<view class="news-card" :style="container_background_style">
<view class="flex-col gap-10" :style="container_background_img_style">
@ -127,8 +148,8 @@
import { background_computer, common_styles_computer, common_img_computer, gradient_computer, gradient_handle, radius_computer, padding_computer, isEmpty } from '@/common/js/common/common.js';
import uniNoticeBar from '@/uni_modules/uni-notice-bar/components/uni-notice-bar/uni-notice-bar.vue';
/**
* DIY 公告notice_style = inherit | marquee | 其他(卡片列表)
* 样式三横向滚动使用 uni-notice-bar仅 mounted 内测宽算速),故跑马灯相关字段随 init 写入并靠 key 重建子组件。
* DIY 公告notice_style = inherit | marquee | card
* 样式三滚动:测文案宽度后 speed = 宽度/interval_time与 DIY swiper 在间隔时间内滚完全文一致
*/
export default {
components: {
@ -166,8 +187,10 @@
// 内容标题设置
content_title_style: '',
// 指示器的样式
// 轮播间隔 ms与 DIY 一致优先 content.interval_time其次 style默认 3s
// 样式一 swiper 轮播间隔ms
interval_time: 3000,
/** 样式三横向滚动content.interval_time与 DIY 配置一致 */
marquee_interval_sec: 0,
// 样式三平移周期参考;样式一 swiper 仍用 interval_time
swiper_duration: 500,
// 轮播图滚动方向(仅样式一)
@ -175,14 +198,20 @@
// 公告数据
notice_list: [],
/** 样式三marquee由 init / setData 维护 */
is_marquee_full_display: false,
marquee_box_style: '',
marquee_content_height: '',
left_icon_container_style: '',
right_icon_container_style: '',
marquee_scroll_on: true,
marquee_display_text: '',
marquee_notice_speed: 35,
marquee_measure_id: 'notice-marquee-measure',
marquee_notice_bar_ready: false,
marquee_notice_speed: 100,
marquee_notice_bar_key: '',
marquee_notice_font_px: 14,
marquee_notice_color: '#333333',
marquee_link_page: '',
/** 仅样式三:关闭滚动时正文行(原 marquee_item_style */
marquee_body_text_style: '',
};
},
@ -202,6 +231,15 @@
this.init();
},
methods: {
/** 样式三滚动间隔(秒):仅读 content.interval_time */
get_marquee_interval_sec(content) {
const raw = content && content.interval_time;
if (raw === undefined || raw === null || raw === '') {
return 0;
}
const sec = Number(raw);
return Number.isFinite(sec) && sec > 0 ? sec : 0;
},
/**
* 解析 propValuecontent/style算出模板所需字符串与样式三跑马灯参数一次 setData。
*/
@ -260,15 +298,50 @@
// ---------- 资讯标题字号(样式一/二在模板里拼 color样式三静态行用 marquee_body_text_style ----------
const content_title_style = `font-size: ${new_style.news_size * 2}rpx; font-weight: ${new_style.news_typeface};`;
// ---------- 样式三:marquee_scroll、文案、链接、uni-notice-bar 的 speed/font/color/key ----------
// marquee_scroll'0' / 0 / false 关闭自动滚动,其余视为开启
// ---------- 样式三:is_full_display、marquee_scroll、图标位置、文案 ----------
const is_full_raw = new_content.is_full_display;
const is_full_display = is_full_raw === null || is_full_raw === undefined || is_full_raw === '' ? '1' : String(is_full_raw);
const is_marquee_full_display = new_content.notice_style === 'marquee' && is_full_display === '1';
const scroll_v = new_content.marquee_scroll;
const marquee_scroll_on = !(scroll_v === '0' || scroll_v === 0 || scroll_v === false);
// 展示文案:优先 content.marquee_content否则取列表首条标题
let marquee_display_text = String(new_content.marquee_content ?? '').trim();
if (!marquee_display_text && new_notice_list.length > 0 && new_notice_list[0].notice_title != null) {
marquee_display_text = String(new_notice_list[0].notice_title).trim();
}
if (!marquee_display_text) {
marquee_display_text = '';
}
// 图标位置/外边距仅在「全部显示」开启时生效(与 DIY 配置面板一致)
let left_icon_container_style = '';
let right_icon_container_style = '';
if (is_marquee_full_display) {
const get_icon_align = (position) => {
const alignMap = { 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, margin) => {
const align = get_icon_align(position || 'center');
const m = margin || default_icon_margin;
const mt = Number(m.padding_top || 0) * 2;
const mr = Number(m.padding_right || 0) * 2;
const mb = Number(m.padding_bottom || 0) * 2;
const ml = Number(m.padding_left || 0) * 2;
return `align-items: ${align}; margin-top: ${mt}rpx; margin-right: ${mr}rpx; margin-bottom: ${mb}rpx; margin-left: ${ml}rpx;`;
};
const legacy_position = new_style.icon_position;
const legacy_margin = new_style.icon_margin;
left_icon_container_style = build_icon_container_style(
new_style.left_icon_position || legacy_position || 'center',
new_style.left_icon_margin || legacy_margin || default_icon_margin
);
right_icon_container_style = build_icon_container_style(
new_style.right_icon_position || legacy_position || 'center',
new_style.right_icon_margin || legacy_margin || default_icon_margin
);
}
const marquee_content_height = is_marquee_full_display ? '' : 'height:' + new_style.container_height * 2 + 'rpx;';
const marquee_box_style = temp_container_background_style + (is_marquee_full_display ? 'height:auto;' : 'height:' + new_style.container_height * 2 + 'rpx;');
// 点击跳转:首条公告链接,无则用「更多」链接
let marquee_link_page = '';
if (new_notice_list[0] && new_notice_list[0].notice_link && new_notice_list[0].notice_link.page != null) {
@ -277,19 +350,7 @@
if (marquee_link_page === '' && new_content.more_link && new_content.more_link.page != null) {
marquee_link_page = new_content.more_link.page;
}
// speed像素/秒uni-notice-bar 内部 duration = textWidth/speed105000 = 35×3000使默认 3s 间隔对应官方默认 speed≈35
const ms = Number(time) > 0 ? Number(time) : 3000;
const marquee_notice_speed = Math.max(6, Math.min(120, Math.round(105000 / ms)));
// 子组件 keyinterval、speed、文案任一变化即重建否则改间隔不重新 initSize
const marquee_notice_bar_key =
String(this.propKey) +
'-ub-' +
String(ms) +
'-' +
String(marquee_notice_speed) +
'-' +
String(marquee_display_text || '');
// uni-notice-bar 的 fontSize 为 pxDIY news_size 为设计值×2 为 rpx 再 upx2px
const marquee_interval_sec = this.get_marquee_interval_sec(new_content);
const news_sz = Number(new_style && new_style.news_size);
const news_base = Number.isFinite(news_sz) && news_sz > 0 ? news_sz : 14;
const news_rpx = news_base * 2;
@ -306,14 +367,37 @@
}
const news_c = new_style && new_style.news_color;
const marquee_notice_color = news_c != null && news_c !== '' ? news_c : '#333333';
// 样式三关闭滚动时:与原先 content_title_style + color 一致
const marquee_body_text_style = content_title_style + 'color:' + marquee_notice_color;
const marquee_measure_id = 'notice-marquee-measure-' + String(this.propKey);
// speed = 文案宽度 / interval_timeinit 后按实测宽度再校正
let est_w = 0;
for (let i = 0; i < marquee_display_text.length; i++) {
est_w += marquee_display_text.charCodeAt(i) > 127 ? marquee_notice_font_px : marquee_notice_font_px * 0.55;
}
est_w = Math.max(est_w, marquee_notice_font_px * 3);
const marquee_notice_speed =
marquee_interval_sec > 0 ? Math.max(30, Math.ceil(est_w / marquee_interval_sec)) : 100;
const marquee_notice_bar_key =
String(this.propKey) +
'-ub-' +
String(marquee_interval_sec) +
'-' +
String(marquee_notice_speed) +
'-' +
String(is_full_display) +
'-' +
String(marquee_display_text || '');
const form_content_out = { ...new_content };
if (form_content_out.is_full_display == null || form_content_out.is_full_display === undefined || form_content_out.is_full_display === '') {
form_content_out.is_full_display = is_full_display;
}
this.setData({
// —— 通用 ——
form_content: new_content,
form_content: form_content_out,
form_style: new_style,
container_height: 'height:' + new_style.container_height * 2 + 'rpx',
container_height: is_marquee_full_display ? '' : 'height:' + new_style.container_height * 2 + 'rpx',
container_background_style: temp_container_background_style,
container_background_img_style: temp_container_background_img_style,
img_style: `height: ${new_style.title_height * 2}rpx; width: ${new_style.title_width * 2}rpx`,
@ -326,21 +410,70 @@
style_container: common_styles_computer(new_style.common_style),
style_img_container: common_img_computer(new_style.common_style, this.propIndex),
// —— 仅样式三模板使用 ——
is_marquee_full_display,
marquee_box_style,
marquee_content_height,
left_icon_container_style,
right_icon_container_style,
marquee_scroll_on,
marquee_interval_sec,
marquee_display_text,
marquee_measure_id,
marquee_notice_bar_ready: false,
marquee_notice_speed,
marquee_notice_bar_key,
marquee_notice_font_px,
marquee_notice_color,
marquee_link_page,
marquee_body_text_style,
}, () => {
this.sync_marquee_notice_speed();
});
},
/** 测量文案宽度textWidth/speed = content.interval_time */
sync_marquee_notice_speed() {
const sec = Number(this.marquee_interval_sec);
if (!this.marquee_scroll_on || this.is_marquee_full_display || !this.marquee_display_text || !Number.isFinite(sec) || sec <= 0) {
return;
}
const next = () => {
const query = uni.createSelectorQuery().in(this);
query
.select('#' + this.marquee_measure_id)
.boundingClientRect((rect) => {
if (!rect || !rect.width) {
this.setData({ marquee_notice_bar_ready: true });
return;
}
const speed = Math.max(30, Math.ceil(rect.width / sec));
const key =
String(this.propKey) +
'-ub-' +
String(sec) +
'-' +
String(speed) +
'-' +
String(this.form_content.is_full_display) +
'-' +
String(this.marquee_display_text || '');
this.setData({
marquee_notice_speed: speed,
marquee_notice_bar_key: key,
marquee_notice_bar_ready: true,
});
})
.exec();
};
if (typeof this.$nextTick === 'function') {
this.$nextTick(next);
} else {
setTimeout(next, 50);
}
},
// 跳转链接
url_event(e) {
app.globalData.url_event(e);
},
/** uni-notice-bar 的 click 无 dataset与 url_event 对齐 */
marquee_uni_click() {
const v = this.marquee_link_page;
if (v === '' || v == null) {
@ -384,14 +517,55 @@
overflow-wrap: break-word;
word-wrap: break-word;
}
.news-box-marquee {
display: flex;
flex-direction: column;
justify-content: center;
}
.news-box-marquee--full {
height: auto;
min-height: 0;
}
.news-marquee-row {
width: 100%;
align-items: stretch;
}
.flex-width {
min-width: 0;
}
.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;
}
.notice-marquee-measure {
position: fixed;
left: -9999px;
top: 0;
white-space: nowrap;
pointer-events: none;
visibility: hidden;
z-index: -1;
}
.notice-marquee-uni-wrap {
min-width: 0;
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
align-self: center;
}
/* 嵌入 DIY 一行:去掉官方默认外边距/内边距,避免占不满 flex */
.notice-marquee-uni-wrap ::v-deep .uni-noticebar {
width: 100%;
padding: 0 !important;
@ -404,8 +578,18 @@
flex: 1;
min-width: 0;
}
.notice-marquee-static {
.news-marquee-static {
min-width: 0;
overflow: hidden;
display: flex;
align-items: center;
align-self: center;
}
.news-marquee-static-text {
width: 100%;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
</style>