From 34c712db32a1c18f4f65457e33237618cef61c2e Mon Sep 17 00:00:00 2001 From: jing <1683105490@qq.com> Date: Sat, 19 Sep 2026 16:03:13 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E5=90=8C=E6=AD=A5=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=A1=86=E4=B8=8E=E6=BB=91=E5=8A=A8=E5=9B=BE=E7=89=87=E7=9B=B8?= =?UTF-8?q?=E5=85=B35=E4=B8=AA=E6=96=87=E4=BB=B6=E5=88=B0=20dev/1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .local.config.js | 52 +++-- components-diy/diy-category-item.vue | 147 ++++++++---- components-diy/diy-category.vue | 202 ++++++++++++++++- components-diy/diy-group.vue | 41 +++- components-diy/diy-image-nav.vue | 325 ++++++++++++++++++++++++++- 5 files changed, 677 insertions(+), 90 deletions(-) diff --git a/.local.config.js b/.local.config.js index bc43ffd..564de8a 100644 --- a/.local.config.js +++ b/.local.config.js @@ -68,7 +68,7 @@ const localDevConfig = ({ uniacid: 11, domain: 'http://localhost:8050/', }, - '100': { + '100': {// 口译教学 uniacid: 100, domain: 'https://5g.aigc-quickapp.com/', }, @@ -76,15 +76,15 @@ const localDevConfig = ({ uniacid: 1, domain: 'https://5g.aigc-quickapp.com/', }, - '115': { + '115': {// 低压断路器 uniacid: 115, domain: 'https://5g.aigc-quickapp.com/', }, - '5g-11': { + '5g-11': {// 铝箔袋包装 uniacid: 11, domain: 'https://5g.aigc-quickapp.com/', }, - '5g-206': { + '5g-206': {// 气体探测 uniacid: 206, domain: 'https://5g.aigc-quickapp.com/', }, @@ -92,19 +92,19 @@ const localDevConfig = ({ uniacid: 165, domain: 'https://5g.aigc-quickapp.com/', }, - '47': { // 修改弹窗 + '47': { // 免疫细胞干细胞外泌体 ,修改弹窗 uniacid: 47, domain: 'https://5g.aigc-quickapp.com/', }, - '145': { // 表单链接转义问题 + '145': { //昆山昆创净化科技有限公司 , 表单链接转义问题 uniacid: 145, domain: 'https://5g.aigc-quickapp.com/', }, - '5g-213': { // 单图组点击链接无法跳转 + '5g-213': { // 碱性康养水天然泡茶水 , 单图组点击链接无法跳转 uniacid: 213, domain: 'https://5g.aigc-quickapp.com/', }, - '5g-4': { // 公告点击链接无法跳转 + '5g-4': { // 高端硅钢制造装备 , 公告点击链接无法跳转 uniacid: 4, domain: 'https://5g.aigc-quickapp.com/', }, @@ -116,11 +116,11 @@ const localDevConfig = ({ uniacid: 50, domain: 'https://5g.aigc-quickapp.com/', }, - '5g-237': { // 商品分类,没有立即咨询文字 + '5g-237': { //高活性氧化镁 商品分类,没有立即咨询文字 uniacid: 237, domain: 'https://5g.aigc-quickapp.com/', }, - '2847': { // + '2847': { // 家居装饰品 uniacid: 2847, domain: 'https://xcx.aigc-quickapp.com/', }, @@ -128,7 +128,7 @@ const localDevConfig = ({ uniacid: 2482, domain: 'https://xcx6.aigc-quickapp.com/', }, - '2485': { // 验证电子表单前后端数据一致性 + '2485': { // 智能物流仓储 , 验证电子表单前后端数据一致性 uniacid: 2485, domain: 'https://xcx6.aigc-quickapp.com/', }, @@ -152,11 +152,11 @@ const localDevConfig = ({ uniacid: 12, domain: 'https://test.aigc-quickapp.com', }, - '248': { // 大宗商品贸易,支持自定义字体大小、颜色 + '248': { // 工业称重系统垃圾吊电子秤,支持自定义字体大小、颜色 uniacid: 248, domain: 'https://5g.aigc-quickapp.com/', }, - '228': { // 商品分类,没有立即咨询文字 + '228': { // 反渗透阻垢剂RO装置 商品分类,没有立即咨询文字 uniacid: 228, domain: 'https://5g.aigc-quickapp.com/', }, @@ -164,7 +164,7 @@ const localDevConfig = ({ uniacid: 2797, domain: 'https://xcx.aigc-quickapp.com/', }, - '5g-95': { // 商品分类,没有立即咨询文字 + '5g-95': { // 加热器 ,商品分类,没有立即咨询文字 uniacid: 95, domain: 'https://5g.aigc-quickapp.com/', }, @@ -185,7 +185,7 @@ const localDevConfig = ({ domain: 'http://192.168.8.118:8050/', // domain: 'http://localhost:8050/', }, - '5g-59': { // 合成孔径雷达,一级分类背景字体颜色 + '5g-59': { // 脱模剂粘合剂乐瑞固Lorechem uniacid: 59, domain: 'https://5g.aigc-quickapp.com/', }, @@ -210,6 +210,18 @@ const localDevConfig = ({ uniacid: 2505, domain: 'https://xcx.aigc-quickapp.com/', }, + '3007': { // 钎焊材料 + uniacid: 3007, + domain: 'https://xcx.aigc-quickapp.com/', + }, + '5g-317': { // 电磁兼容,模板显示不全商品 + uniacid: 317, + domain: 'https://5g.aigc-quickapp.com/', + }, + '5g-312': { // 天然植物功效活性物 + uniacid: 312, + domain: 'https://5g.aigc-quickapp.com/', + }, // })['5g-237']; // 商品分类,没有立即咨询文字 // })['5g-97']; // 大宗商品贸易,支持自定义字体大小、颜色 // })['5g-50']; // 燃气安全产品机器人,购物车无反应 @@ -222,10 +234,16 @@ const localDevConfig = ({ // })['2881']; // 鸡肉调理品, 优惠卷显示不全,及逻辑错误 // })['2724']; // 生物菌肥 // })['2811']; // 选择要使用的环境配置 +// })['5g-351']; //洗车机 +// })['5g-204']; //热固性塑料 +// })['5g-59']; //合成孔径雷达 +// })['2709']; //中央厨房 +// })['3007']; //钎焊材料 +// })['2505']; //煤矿钻机 // })['local-11']; // 选择要使用的环境配置 // })['2811']; // 本地 - -})['2821']; // 本地 +//})['5g-317']; // 电磁兼容 +})['5g-351']; // // })['local-2']; // 本地 // })['local-11']; // 本地 // })['1-test']; // test diff --git a/components-diy/diy-category-item.vue b/components-diy/diy-category-item.vue index 3e4e2c6..4fe9db6 100644 --- a/components-diy/diy-category-item.vue +++ b/components-diy/diy-category-item.vue @@ -98,7 +98,8 @@ - + {{ category.category_name }} @@ -139,8 +140,51 @@ - - + + + + {{ category.category_name }} + + + + + + {{ item.label_name }} + + + + {{ isEnEnv ? item.en_goods_name : item.goods_name }} + + + + + {{ $lang('common.currencySymbol') }} + {{ parseFloat(showPrice(item)).toFixed(2).split('.')[0] }} + .{{ parseFloat(showPrice(item)).toFixed(2).split('.')[1] }} + + + + {{ $lang('common.currencySymbol') }} + {{ showMarketPrice(item) }} + + + + {{ $lang('components-diy.diy-category-item.consultNow') }} + + + + + + + 暂无商品 + + + + + {{ category.category_name }} - - - - {{ one.category_name }} - - - - - - {{ two.category_name }} - - - - + - + {{ category.category_name }} @@ -617,13 +647,13 @@ export default { * 三级分类 (value.level == 3) → true → 按二级分类分别显示各自商品 */ isGroupedDisplay() { + // 仅模板1 走"按二级分类分组显示商品"; 模板5 的层级由 value.level 直接决定(见下方 value.template == 5 分支) return this.value.template == 1 && this.value.level == 3; }, /** - * 模板1三级分类: 渲染所有二级分类(包括无商品的空分类) - * 不再按"是否有商品"过滤, 保证一级分类下的二级分类全部显示, - * 避免 10 个二级分类只显示 8 个(2 个被当成空分类过滤掉)的问题 - * 加载中(template1ChildLoading[id] === true)的二级分类暂不渲染, 避免闪烁 + * 模板1三级分类: 只渲染"有商品"的二级分类 + * 无商品的二级分类整块(标题 + 网格)都不渲染; 加载中的二级分类也暂不渲染(避免闪烁) + * 判定时机: 该二级分类加载完成(template1ChildLoading[id] === false)且商品列表非空 */ filteredGroupedChildren() { if (!this.isGroupedDisplay) return []; @@ -631,8 +661,9 @@ export default { return this.category.child_list.filter(one => { // 还在加载中: 暂不渲染(避免闪烁) if (this.template1ChildLoading[one.category_id]) return false; - // 加载完成(无论是否有商品)都渲染, 无商品时显示空状态 - return true; + // 加载完成: 只有该二级分类下有商品时才显示, 无商品则整块隐藏 + const list = this.template1ChildGoodsList[one.category_id]; + return !!(list && list.length); }); }, /** @@ -642,7 +673,7 @@ export default { * 若 type 不跟随更新, 模板1 会误走 goods 分支, 导致"资讯类商品=否"的商品不显示立即咨询按钮 */ type() { - return this.value.template == 1 || this.value.template == 99 ? 'category' : 'goods'; + return this.value.template == 1 || this.value.template == 5 || this.value.template == 99 ? 'category' : 'goods'; }, }, created() { @@ -664,7 +695,14 @@ export default { // 模板1:根据后台"展示分类"配置 + 数据层级决定加载方式 // 三级分类模式 (isGroupedDisplay) + 有二级分类时,按二级分类分别加载各自商品 // 其他情况(二级分类模式 / 无二级分类),直接加载当前一级分类下的所有商品 - if (this.value.template == 1 && this.category && this.category.category_id) { + // 模板5 渲染规则: + // 二级分类(value.level == 2) → 商品网格(图2), 需要加载该一级分类下所有商品(合并其二级分类) + // 三级分类(value.level == 3) → 二级分类网格(图3), 静态网格无需加载商品 + // 若该一级分类下没有子分类(兜底), 仍需要加载商品 + const template5NeedGoods = this.value.template == 5 && + (this.value.level == 2 || + !(this.category && this.category.child_list && this.category.child_list.length)); + if ((this.value.template == 1 || template5NeedGoods) && this.category && this.category.category_id) { if (this.isGroupedDisplay && this.category.child_list && this.category.child_list.length) { this.category.child_list.forEach(child => { this.getTemplate1ChildGoods(child.category_id); @@ -739,6 +777,8 @@ export default { } // 模板1:切换一级分类时重新加载该分类下的商品 // 三级分类模式 + 有二级分类时,按二级分类分别重新加载,否则直接加载当前分类 + // 注意: 模板5 是"全部分类纵向平铺", 商品由 created 首次加载 + 父级链式懒加载提供, + // 滚动时 select 会随 listenScroll 变化, 若此处也重载会导致滚动中反复清空/重复请求, 故排除 5 if (this.value.template == 1 && this.index == this.select && this.category && this.category.category_id) { this.template1GoodsList = []; this.template1ChildGoodsList = {}; @@ -1489,42 +1529,42 @@ export default { } } +// 分类网格(模板5 / legacy 商品分类): 白底卡片 + 3 列 图片 + 名称 +// 与 Branch_5cfee417 的商品分类保持一致 .category-list { - display: grid !important; - grid-template-columns: repeat(3, 1fr) !important; - background: transparent; + display: flex; + flex-wrap: wrap; + background: #fff; margin: 0 20rpx; - border-radius: 0; - padding: 0; - gap: 20rpx 0; + border-radius: 10rpx; + padding: 10rpx 0; .category-item { - width: 100% !important; + width: 33.33%; display: flex; flex-direction: column; align-items: center; justify-content: center; - padding: 0; + padding: 16rpx; box-sizing: border-box; .img-box { - width: 70% !important; + width: 80%; height: 0; - padding-bottom: 70%; + padding-top: 80%; margin: 0 auto; overflow: hidden; - margin-bottom: 16rpx; + margin-bottom: 20rpx; position: relative; - background: transparent !important; - border-radius: 0 !important; + background: transparent; image { position: absolute; - width: 100% !important; - height: 100% !important; - left: 0 !important; - top: 0 !important; - transform: none !important; + width: 100%; + height: 100%; + left: 0; + top: 0; + transform: none; } } @@ -1539,7 +1579,6 @@ export default { font-size: var(--diy-category-item-name-size, 24rpx); } - // 模板1选中状态 &.selected { .img-box { border: 2rpx solid var(--base-color, #FF6B35); @@ -2490,18 +2529,28 @@ export default { .screen-category-wrap { display: flex; + align-items: center; + position: relative; .icon-unfold { - font-size: 24rpx; + position: absolute; + right: 15rpx; + top: 0; + z-index: 2; + width: 70rpx; + height: 70rpx; + line-height: 62rpx; + text-align: center; + font-size: 36rpx; color: #999; - padding: 0 0 0 20rpx; + padding: 0; } } .screen-category { flex: 1; width: 0; - padding: 0 0 20rpx 0; + padding: 0 70rpx 20rpx 0; white-space: nowrap; height: 60rpx; diff --git a/components-diy/diy-category.vue b/components-diy/diy-category.vue index 4664df9..c8faf84 100644 --- a/components-diy/diy-category.vue +++ b/components-diy/diy-category.vue @@ -122,7 +122,7 @@ { select: select == index }, { 'border-bottom': value.template == 4 && select + 1 === index }, { 'border-top': value.template == 4 && select - 1 === index }, - { 'first-category-item': index == 0 && (value.template == 99 || value.template == 1) } + { 'first-category-item': index == 0 && (value.template == 99 || value.template == 1 || value.template == 5) } ]" @tap.stop="switchOneCategory(index)"> {{ item.category_name }} @@ -152,11 +152,44 @@ + @saveSecondCategory="saveSecondCategoryName"> - + - + + + + + + + + + + + + {{ $lang('components-diy.diy-category.reachedBottom') }} + + + { if (!this.heightArea.length) this.getHeightArea(-1); + // 分类渲染完成后重新对齐到当前选中的一级分类顶部, + // 避免首屏第一个分类的标题被顶出可视区 + if (this.categoryTree && this.categoryTree.length) this.alignToCategory(this.select); }); } } @@ -536,8 +573,30 @@ export default { switchOneCategory(index) { if (index >= this.categoryTree.length) return; this.select = index; - this.categoryId = 'category-' + index; this.scrollLock = true; + this.alignToCategory(index); + }, + /** + * 把右侧滚动区定位到指定一级分类的顶部 + * + * uni-app 只在 scroll-into-view 的值"发生变化"时才重新滚动, + * 而 categoryId 的初值就是 'category-0', 且只有点击左侧分类才会被改写; + * 用户在右侧手动滚动后 categoryId 仍是 'category-0', 此时再点第一个分类(index 0) + * 值时没有变化, 右侧不会回滚到该分类, 该分类的标题就被顶出可视区 + * (看起来像"标题丢了 / 卡片被切了一半"), 而点其它分类因为值变了所以都正常。 + * 这里先置空、下一帧再设置目标 id, 保证每次点击都能重新定位到分类顶部。 + * @param {Number} index 一级分类下标 + */ + alignToCategory(index) { + const target = 'category-' + index; + if (this.categoryId === target) { + this.categoryId = ''; + this.$nextTick(() => { + this.categoryId = target; + }); + } else { + this.categoryId = target; + } }, saveSecondCategoryName(name) { this.lastSecondCategoryName = name; @@ -559,7 +618,10 @@ export default { break; } } - if (this.value.template != 1 && this.value.loadType == 'all' && this.heightArea[this.select][1] - + // 模板5 三级分类为静态分类网格平铺, 不需要懒加载商品; 这里只保留 loadType=all 的懒加载, + // 并补上 heightArea[this.select] 越界保护 + if (this.value.template != 1 && this.value.loadType == 'all' && + this.heightArea[this.select] && this.heightArea[this.select][1] - scrollTop - contentWrapHeight < 300) { if (Array.isArray(this.$refs.categoryItem) && this.$refs.categoryItem[this.select]) this.$refs.categoryItem[this.select].getGoodsList(); } @@ -1674,6 +1736,134 @@ export default { } } +// ===================== 模板5 商品分类样式(新增: 基于模板1双栏布局) ===================== +.category-template-5 { + .search-box { + padding: 20rpx 24rpx; + background: #fff; + + .search-content { + background-color: #f5f5f5; + border-radius: 40rpx; + + input { + background: #f5f5f5; + border-radius: 40rpx; + padding: 0 30rpx; + font-size: 26rpx; + color: #333; + } + + .iconfont { + right: 16rpx; + color: #89899a; + font-size: 32rpx; + } + } + } + + .content-box { + // 模板5 + 三级分类: 标题行所在整片右半边去掉白色, 与模板1一致 + background: transparent; + + .tree-wrap { + width: 170rpx; + background-color: #fff; + } + + .right-flex-wrap { + background: #f5f5f5; + + .content-wrap { + background: transparent; + } + + // 模板5 纵向平铺: 每个一级分类独占一行(与模板99"全部分类"结构一致) + .child-category { + width: 100%; + box-sizing: border-box; + } + } + } + + // 穿透到子组件 diy-category-item: 调整 banner 横向内边距 + 分类网格容器为透明 + ::v-deep .category-adv { + padding: 0 20rpx; + margin-top: 0; + } + + // 模板5: .category-list 直接沿用子组件的 legacy 白底卡片样式(不再覆盖为透明) + + // 穿透到子组件 diy-category-item: 模板5标题行定高, 与左侧第一个一级分类等高对齐 + ::v-deep .category-title-with-lines { + height: 100rpx; + box-sizing: border-box; + padding: 30rpx 0 20rpx; + } + + // 模板5: 左侧第一个一级分类定高, 与右侧标题行垂直对齐 + .tree-wrap .category-item.first-category-item { + height: 100rpx; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + overflow: hidden; + + view { + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + // 模板5: 分类网格的 .img-box / .name 直接沿用子组件 legacy 尺寸(80% + 名称), + // 不再做 70%/透明 覆盖, 以与 Branch_5cfee417 的商品分类保持一致 + + // 左侧分类栏样式 + .tree-wrap .category-item { + padding: 28rpx 16rpx; + background-color: var(--diy-category-tree-normal-bg-color, #f5f5f5); + border-radius: 0; + + view { + color: var(--diy-category-tree-normal-text-color, #222222); + font-size: 26rpx; + line-height: 1.3; + } + + &.border-top, + &.border-bottom { + border-radius: 0; + } + + &.select { + background: var(--diy-category-tree-select-bg-color, #fff); + + view { + color: var(--diy-category-tree-select-text-color, #333); + font-weight: bold; + font-size: 28rpx; + } + + &::before { + content: ' '; + width: 6rpx; + height: 32rpx; + background: var(--base-color, #FF6B35); + display: block; + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + border-radius: 0 6rpx 6rpx 0; + } + } + } +} + // ===================== 模板99 商品分类样式 ===================== .category-template-99 { .search-box { diff --git a/components-diy/diy-group.vue b/components-diy/diy-group.vue index 4169969..7183878 100644 --- a/components-diy/diy-group.vue +++ b/components-diy/diy-group.vue @@ -377,14 +377,41 @@ export default { : index + 1; if (newItem.componentName !== 'Search' || newItem.positionWay !== 'fixed') { - newItem.pageStyle = `background-color:${newItem.pageBgColor};`; + // PR-DIY-SEARCH-MARGIN-COLOR (2026-09-17): 搜索组件的上下左右边距区域颜色 + // 与搜索框背景色(componentBgColor, 后台自定义)保持一致, 使边距和搜索框融为一体; + // 兼容旧数据: 未配置 componentBgColor 时回退 pageBgColor。其余组件仍用 pageBgColor。 + const wrapBgColor = (newItem.componentName === 'Search' && newItem.componentBgColor) + ? newItem.componentBgColor + : newItem.pageBgColor; + newItem.pageStyle = `background-color:${wrapBgColor};`; - if (newItem.margin) { - newItem.pageStyle += `padding-top:${newItem.margin.top * 2}rpx;`; - newItem.pageStyle += `padding-bottom:${newItem.margin.bottom * 2}rpx;`; - newItem.pageStyle += `padding-right:${newItem.margin.both * 2}rpx;`; - newItem.pageStyle += `padding-left:${newItem.margin.both * 2}rpx;`; - } + // 边距归一化: 兼容后台两种数据结构(否则边距不生效) + // ① 标准对象形态 margin = { top, bottom, both } —— 大多数组件 + // ② 扁平字段形态 marginTop / marginBottom / marginBoth + // —— 如"滑动图片"(ImageNav), 其 margin 是空数组 [], 左右边距存在 marginBoth 里 + // both / marginBoth 表示"左右边距"; 数值 → rpx 统一 × 2 (与其它组件一致) + const rawMargin = newItem.margin; + const objMargin = (rawMargin && typeof rawMargin === 'object' && !Array.isArray(rawMargin)) ? rawMargin : null; + const toMarginNum = (v) => { const n = Number(v); return isNaN(n) ? 0 : n; }; + const pickMargin = (objKey, flatKey) => { + if (objMargin && objMargin[objKey] !== undefined && objMargin[objKey] !== null && objMargin[objKey] !== '') { + return toMarginNum(objMargin[objKey]); + } + return toMarginNum(newItem[flatKey]); + }; + const marginTopNum = pickMargin('top', 'marginTop'); + const marginBottomNum = pickMargin('bottom', 'marginBottom'); + const marginBothNum = pickMargin('both', 'marginBoth'); + // 左右: 若有独立的 left/right 字段则优先, 否则用 both(左右一致) + const marginLeftNum = (objMargin && objMargin.left !== undefined) ? toMarginNum(objMargin.left) + : (newItem.marginLeft !== undefined ? toMarginNum(newItem.marginLeft) : marginBothNum); + const marginRightNum = (objMargin && objMargin.right !== undefined) ? toMarginNum(objMargin.right) + : (newItem.marginRight !== undefined ? toMarginNum(newItem.marginRight) : marginBothNum); + + newItem.pageStyle += `padding-top:${marginTopNum * 2}rpx;`; + newItem.pageStyle += `padding-bottom:${marginBottomNum * 2}rpx;`; + newItem.pageStyle += `padding-left:${marginLeftNum * 2}rpx;`; + newItem.pageStyle += `padding-right:${marginRightNum * 2}rpx;`; } return newItem; diff --git a/components-diy/diy-image-nav.vue b/components-diy/diy-image-nav.vue index e36e4d8..37fcd4d 100644 --- a/components-diy/diy-image-nav.vue +++ b/components-diy/diy-image-nav.vue @@ -1,10 +1,16 @@