Merge remote-tracking branch 'origin/dev/1.0' into yuanlaide2

# Conflicts:
#	.local.config.js
This commit is contained in:
2026-07-16 16:17:26 +08:00
48 changed files with 5248 additions and 1014 deletions

View File

@@ -281,13 +281,42 @@ export default {
.tab-bar {
background-color: #fff;
box-sizing: border-box;
position: fixed;
left: 0;
bottom: 0;
/* ============================================================
* 固定在最底端,不能位置漂移(微信小程序 / 鸿蒙元服务 / 快应用 H5)
* ------------------------------------------------------------
* 现象(只在客户端小程序里复现,浏览器 H5 没事):
* 页面带 navigationStyle:custom + 页面内有 scroll-view,
* 滚到底部时 .tab-bar 会被微信客户端的页面避让逻辑推上去,
* 出现"位置漂移"。
*
* 根因(微信小程序特性):
* 1) 微信小程序里 position:fixed 的 containing block 是 page
* 根容器(不是 viewport),可视区变化时 fixed 元素下沿会
* 跟着重算,造成漂移。
* 2) 父级一旦出现 transform/filter/will-change,fixed 的
* containing block 会被进一步改写,fixed 元素行为更不可控。
*
* 加固措施:
* - bottom: 0 !important 钉死下沿
* - 提升 z-index 到 2147483647,避免被其他 fixed 元素遮挡
* - transform: translateZ(0) 强制提升到独立合成层,降低父级
* transform 干扰;will-change:transform 提示浏览器持续合成
* - 微信小程序里 #ifdef MP-WEIXIN / #ifdef MP-HARMONY 走原生
* tabBar,diy-bottom-nav 通常不会同时存在,但保留兜底
* ============================================================ */
position: fixed !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
top: auto !important;
width: 100%;
z-index: 998;
z-index: 2147483647 !important;
display: flex;
border-top: 2rpx solid #f5f5f5;
/* 强制提升合成层,降低父级 transform/filter 改变 containing block 的概率 */
transform: translateZ(0) !important;
-webkit-transform: translateZ(0) !important;
will-change: transform !important;
padding-bottom: 0;
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);

View File

@@ -7,7 +7,7 @@
<view class="goods-img-wrap">
<image class="goods-img"
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
mode="widthFix" @error="imgError(index)"
:mode="imgMode" @error="imgError(index)"
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }"
show-menu-by-longpress />
<view class="sell-out" v-if="item.stock <= 0">
@@ -117,7 +117,7 @@
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-img-wrap">
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
:src="$util.img(item.goods_image, { size: 'mid' })" :mode="imgMode" @error="imgError(index)"
:lazy-load="true" show-menu-by-longpress />
<view class="sell-out" v-if="item.stock <= 0">
<text class="iconfont icon-shuqing"></text>
@@ -184,7 +184,7 @@
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
<view class="goods-img-wrap">
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
:src="$util.img(dataItem.goods_image, { size: 'mid' })" :mode="imgMode"
@error="imgError(dataIndex)" :lazy-load="true" show-menu-by-longpress />
<view class="sell-out" v-if="dataItem.stock <= 0">
<text class="iconfont icon-shuqing"></text>
@@ -302,6 +302,19 @@ export default {
}
},
computed: {
// 商品图 image 的 mode 模式:
// - 大图模式(large-mode):容器高度由图片决定,固定使用 widthFix 保持原比例
// - 鸿蒙元服务:其他模板下 image 的 widthFix 模式异常(图片被裁剪/显示不全),改用 aspectFill 填满固定容器
// - H5、微信小程序等其他环境:保持 widthFix 行为不变
imgMode() {
if (this.goodsValue.template == 'large-mode') return 'widthFix';
// #ifdef MP-HARMONY
return 'aspectFill';
// #endif
// #ifndef MP-HARMONY
return 'widthFix';
// #endif
},
goodsListWarpCss() {
var obj = '';
obj += 'background-color:' + this.goodsValue.componentBgColor + ';';

View File

@@ -300,6 +300,7 @@ export default {
handler() {
this.diyGlobalData = this.diyData ? this.$util.deepClone(this.diyData) : null;
this.processData();
this._notifyLoaded();
},
deep: true
}
@@ -308,8 +309,9 @@ export default {
this.processData();
},
mounted() {
// 通知父组件 diy-group 内容已渲染完毕
this.$emit('loaded');
if (this.diyData && this.diyData.value) {
this._notifyLoaded();
}
},
computed: {
topNavColor() {
@@ -323,7 +325,6 @@ export default {
return topNavColor;
},
// 过滤组件的渲染
diyDataArray() {
if (!this.processedData) {
this.processData();
@@ -347,6 +348,12 @@ export default {
}
},
methods: {
_notifyLoaded() {
if (this._loadedTimer) clearTimeout(this._loadedTimer);
this._loadedTimer = setTimeout(() => {
this.$emit('loaded');
}, 300);
},
processData() {
if (!this.diyGlobalData || !this.diyGlobalData.value) {
this.processedData = [];

View File

@@ -64,7 +64,9 @@
id="myVideo"
:src="video_url"
:controls="true"
object-fit="contain"
@loadedmetadata="onPopupVideoLoaded"
@error="onPopupVideoError"
></video>
</view>
</uni-popup>
@@ -88,11 +90,14 @@ export default {
pageWidth: '',
indicatorDots: false,
swiperCurrent: 0,
video_url: ''
video_url: '',
popupVideoWidth: 0,
popupVideoHeight: 0,
windowWidth: 0
}
},
created() {
// 组件创建时的逻辑
this.initWindowWidth();
},
watch: {
componentRefresh(newValue) {
@@ -140,24 +145,33 @@ export default {
// 弹窗视频容器样式
popupVideoStyle() {
let style = 'position:fixed;width:100%;left:0;';
if (this.popupVideoRatio) {
// 根据视频比例设置位置
if (this.popupVideoRatio === 'portrait') {
// 竖屏视频:居中显示,使用9/16比例
style += 'top:50%;transform:translateY(-50%);';
style += 'aspect-ratio: 9 / 16;';
} else {
// 横屏视频:靠近顶部显示,使用16/9比例
style += 'top:20%;';
style += 'aspect-ratio: 16 / 9;';
}
} else {
// 默认:居中显示,使用竖屏比例
style += 'top:50%;transform:translateY(-50%);';
style += 'aspect-ratio: 9 / 16;';
const defaultRatio = 9 / 16;
let ratio = defaultRatio;
if (this.popupVideoWidth && this.popupVideoHeight) {
ratio = this.popupVideoHeight / this.popupVideoWidth;
}
const isPortrait = ratio > 1;
if (isPortrait) {
style += 'top:50%;transform:translateY(-50%);';
} else {
style += 'top:20%;';
}
// #ifdef H5
style += 'padding-top: ' + (ratio * 100) + '%;';
// #endif
// #ifdef MP-WEIXIN
style += 'padding-top: ' + (ratio * 100) + '%;';
// #endif
// #ifdef MP-HARMONY
style += 'height: ' + (this.windowWidth * ratio) + 'px;';
// #endif
return style;
}
},
@@ -165,8 +179,8 @@ export default {
// 显示视频播放弹窗
showVideo(item) {
this.video_url = item.videoUrl;
// 重置视频比例为null,等待新的检测结果
this.popupVideoRatio = null;
this.popupVideoWidth = 0;
this.popupVideoHeight = 0;
this.$refs.videoPopup.open();
},
@@ -174,6 +188,16 @@ export default {
imgError(index) {
// 图片加载失败的处理逻辑
},
// 初始化窗口宽度
initWindowWidth() {
try {
const systemInfo = uni.getSystemInfoSync();
this.windowWidth = systemInfo.windowWidth || 375;
} catch (e) {
this.windowWidth = 375;
}
},
// 弹窗视频加载完成事件
onPopupVideoLoaded(event) {
@@ -198,13 +222,24 @@ export default {
}
// #endif
// 鸿蒙元服务端:通过事件对象获取视频宽高
// #ifdef MP-HARMONY
if (event && event.detail) {
width = event.detail.width || 0;
height = event.detail.height || 0;
}
// #endif
if (width && height) {
this.popupVideoRatio = width >= height ? 'landscape' : 'portrait';
} else {
// 获取失败,默认竖屏
this.popupVideoRatio = 'portrait';
this.popupVideoWidth = width;
this.popupVideoHeight = height;
}
});
},
// 弹窗视频错误事件
onPopupVideoError(event) {
console.error('Popup video load failed:', event);
}
}
}
@@ -576,8 +611,9 @@ export default {
.video-container {
width: 100%;
height: 300px;
position: relative;
overflow: hidden;
background-color: #000;
}
.adaptive-video {
@@ -589,6 +625,22 @@ export default {
left: 0;
}
/* #ifdef MP-WEIXIN */
.adaptive-video {
position: absolute;
top: 0;
left: 0;
}
/* #endif */
/* #ifdef MP-HARMONY */
.adaptive-video {
position: static;
display: block;
box-sizing: border-box;
}
/* #endif */
.video-nav {
padding: 16rpx;
box-sizing: border-box;

View File

@@ -26,6 +26,23 @@
:poster="posterUrl"
:style="videoWarpCss"
controls
object-fit="cover"
@loadedmetadata="onVideoLoaded"
@error="onVideoError"
></video>
<!-- #endif -->
<!-- 鸿蒙元服务端使用uni-app的video组件 -->
<!-- #ifdef MP-HARMONY -->
<video
ref="videoRef"
data-component-name="diy-video"
class="diy-video harmony-video"
:src="videoUrl"
:poster="posterUrl"
:style="videoWarpCss"
controls
object-fit="cover"
@loadedmetadata="onVideoLoaded"
@error="onVideoError"
></video>
@@ -44,14 +61,17 @@ export default {
}
},
data() {
return {
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
videoUrl: '',
posterUrl: ''
};
},
return {
videoWidth: 0,
videoHeight: 0,
videoUrl: '',
posterUrl: '',
windowWidth: 0
};
},
created() {
this.initVideoData();
this.initWindowWidth();
},
mixins: [DiyMinx],
watch: {
@@ -78,18 +98,26 @@ export default {
// 动态计算容器比例
containerStyle() {
let style = '';
const defaultRatio = 9 / 16;
if (this.videoRatio === 'landscape') {
// 横屏视频:16/9比例
style += 'aspect-ratio: 16 / 9;';
} else if (this.videoRatio === 'portrait') {
// 竖屏视频:9/16比例
style += 'aspect-ratio: 9 / 16;';
} else {
// 未加载完成 → 默认使用竖屏比例
style += 'aspect-ratio: 9 / 16;';
let ratio = defaultRatio;
if (this.videoWidth && this.videoHeight) {
ratio = this.videoHeight / this.videoWidth;
}
// #ifdef H5
style += 'padding-top: ' + (ratio * 100) + '%;';
// #endif
// #ifdef MP-WEIXIN
style += 'padding-top: ' + (ratio * 100) + '%;';
// #endif
// #ifdef MP-HARMONY
style += 'width: 100%;';
style += 'height: ' + (this.windowWidth * ratio) + 'px;';
// #endif
return style;
}
},
@@ -104,6 +132,16 @@ export default {
// #endif
},
// 初始化窗口宽度
initWindowWidth() {
try {
const systemInfo = uni.getSystemInfoSync();
this.windowWidth = systemInfo.windowWidth || 375;
} catch (e) {
this.windowWidth = 375;
}
},
// 获取视频URL
getVideoUrl() {
if (!this.value || !this.value.videoUrl) return '';
@@ -138,7 +176,8 @@ export default {
const height = video.videoHeight;
if (width && height) {
this.videoRatio = width >= height ? 'landscape' : 'portrait';
this.videoWidth = width;
this.videoHeight = height;
}
});
@@ -169,8 +208,16 @@ export default {
}
// #endif
// #ifdef MP-HARMONY
if (event && event.detail) {
width = event.detail.width || 0;
height = event.detail.height || 0;
}
// #endif
if (width && height) {
this.videoRatio = width >= height ? 'landscape' : 'portrait';
this.videoWidth = width;
this.videoHeight = height;
}
},
@@ -216,6 +263,11 @@ export default {
/* H5端样式 */
/* #ifdef H5 */
.h5-video {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: cover;
}
/* #endif */
@@ -225,6 +277,19 @@ export default {
.mp-video {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
/* #endif */
/* 鸿蒙元服务端样式 */
/* #ifdef MP-HARMONY */
.harmony-video {
width: 100%;
height: 100%;
display: block;
box-sizing: border-box;
}
/* #endif */
</style>