Files
lucky_shop/components-diy/diy-category.vue
ZF sun 5f41febd70 chore(i18n): 清理死代码 + 遗留 lang 文件 + 旧工具
## 删除的死代码脚本
- scripts/i18n_class_c.py (脚本自承'新架构下永远输出 0',纯防御性)
- scripts/full_migrate_i18n.py (其产出违反 CLAUDE.md 1.2 中文 key 铁律,已标 DEPRECATED)
- scripts/__pycache__/ (Python 缓存)

## 删除的旧 per-page lang 文件
- lang/zh-cn/<page>/<file>.js (140 个)
- lang/en-us/<page>/<file>.js (139 个)
- 共 279 个文件,运行时不再加载,0 个 key 被 .vue 调用(经 diagnose_keys.py 验证)

## 删除的备份和迁移表
- lang/_backup/ (git 已跟踪原文件)
- lang/_migration_map.json / lang/_migration-map.json (运行时不用)

## 删除的中间产物 JSON
- docs/i18n-rename-*.json (smart_rename 中间产物,已用完)
- docs/i18n-ambiguous.json / i18n-audit.json / i18n-call-rewrite.log /
  i18n-clean-dead.log / i18n-file-texts.json / i18n-page-titles.json /
  i18n-vue-extract.json (前一会话残留,无引用方)
- docs/i18n-{naming,shadow,strict}-audit.json (脚本会自动重新生成)

## 删除的 modular lang 文件
- lang/zh-cn/*.js / lang/en-us/*.js (20 个模块文件,内容是上一会话产生的死代码)
- lang/zh-cn/index.js / lang/en-us/index.js (聚合入口)
- lang/DEPRECATED.md (已不再相关)

## 删除的不成熟脚本
- scripts/check_perpage.py (诊断用,已完成)
- scripts/diagnose_keys.py (诊断用,已完成)
- scripts/smart_rename_i18n.py (v1-v3 都 bug,未修完)

## 现状
- lang/ 现在只有 zh-cn.js + en-us.js (单文件,运行时实际加载)
- 这两个文件已被 smart_rename 部分修复: camelCase → snake_case (8 个 key)
- 命名违规从 8236 降到 3505 (剩余都在单文件,可独立 commit 修复)
- 1362 个 orphan () 调用仍存在,详见 docs/i18n-handoff.md
2026-06-25 10:48:15 +08:00

1036 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view data-component-name="diy-category" :class="['category-page-wrap', 'category-template-' + value.template]"
:style="{ height: 'calc(100vh - ' + tabBarHeight + ')' }">
<!-- #ifdef MP-WEIXIN -->
<!-- <block v-if="value.template == 4">
<view class="search-box" v-if="value.search" @tap.stop="$util.redirectTo('/pages_tool/goods/search')" :style="navbarInnerStyle">
<view class="search-content">
<input type="text" class="uni-input font-size-tag" maxlength="50" :placeholder="$lang('common.button.search')" confirm-type="search" @tap.stop="onClickSearch()" disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
</view>
<view :style="navbarInnerStyle" v-if="!value.search">{{ $lang("diy.diy-category.l12.t0") }}</view>
</block> -->
<block v-if="value.template != 4">
<!-- <view :style="navbarInnerStyle">{{ $lang("diy.diy-category.l12.t0") }}</view> -->
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()"
:style="wxSearchHeight">
<view class="search-content">
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('common.button.search')"
confirm-type="search" @tap.stop="onClickSearch()"
disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
@tap.stop.prevent="changeListStyle()"></view>
</view>
</block>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="search-box" v-if="value.search" @tap.stop="onClickSearch()">
<view class="search-content">
<input type="text" class="uni-input" maxlength="50" :placeholder="$lang('common.button.search')" confirm-type="search"
@tap.stop="onClickSearch()" disabled="true" />
<text class="iconfont icon-sousuo3"></text>
</view>
<view class="iconfont" :class="{ 'icon-apps': !isList, 'icon-list': isList }"
@tap.stop.prevent="changeListStyle()"></view>
</view>
<!-- #endif -->
<view class="template-four wx" v-if="value.template == 4">
<scroll-view scroll-x="true" class="template-four-wrap" :scroll-with-animation="true"
:scroll-into-view="'category-one-' + oneCategorySelect" enable-flex="true">
<view class="category-item" :id="'category-one-' + index" v-for="(item, index) in templateFourData"
:key="index" :class="{ select: oneCategorySelect == index }" @tap.stop="templateFourOneFn(index)">
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
<image :src="$util.img(item.image)" mode="aspectFill" show-menu-by-longpress/>
</view>
<view :class="['text', { 'color-base-bg': oneCategorySelect == index }]">{{ item.category_name }}
</view>
</view>
</scroll-view>
<view class="category-item-all" @tap.stop="$refs.templateFourPopup.open()">
<view class="category-item-all-wrap">
<text class="text">{{ $lang("diy.diy-category.l54.t0") }}</text>
<image class="img" :src="$util.img('/public/uniapp/category/unfold.png')" mode="aspectFill" show-menu-by-longpress></image>
</view>
</view>
<uni-popup type="top" ref="templateFourPopup" :top="uniPopupTop">
<view class="template-four-popup">
<scroll-view scroll-y="true" class="template-four-scroll" enable-flex="true">
<view class="item" :class="{ selected: oneCategorySelect == index }"
@tap.stop="templateFourOneFn(index)" v-for="(item, index) in templateFourData" :key="index">
<view class="image-warp" :class="[{ 'color-base-border': oneCategorySelect == index }]">
<image :src="$util.img(item.image)" mode="aspectFill" show-menu-by-longpress></image>
</view>
<view :class="['text', { 'color-base-bg': oneCategorySelect == index }]">{{
item.category_name }}</view>
</view>
</scroll-view>
<view class="pack-up" @tap.stop="$refs.templateFourPopup.close()">
<text>{{ $lang("diy.diy-category.l71.t0") }}</text>
<text class="iconfont icon-iconangledown-copy"></text>
</view>
</view>
</uni-popup>
</view>
<view class="content-box" v-if="categoryTree">
<block v-if="categoryTree.length">
<scroll-view scroll-y="true" class="tree-wrap">
<view class="category-item-wrap">
<view class="category-item" v-for="(item, index) in categoryTree" :key="index" :class="[
{ select: select == index },
{ 'border-bottom': value.template == 4 && select + 1 === index },
{ 'border-top': value.template == 4 && select - 1 === index }
]" @tap.stop="switchOneCategory(index)">
<view class="">{{ item.category_name }}</view>
</view>
</view>
</scroll-view>
<view class="right-flex-wrap">
<scroll-view scroll-y="true" class="content-wrap" v-if="value.template == 1 || loadType == 'all'"
ref="contentWrap" :scroll-into-view="categoryId" :scroll-with-animation="true"
@scroll="listenScroll" @touchstart="touchStart" :refresher-enabled="true"
refresher-default-style="none" :refresher-triggered="triggered" @refresherrefresh="onRefresh"
@refresherrestore="onRestore">
<view class="child-category" v-for="(item, index) in categoryTree" :key="index"
:id="'category-' + index">
<diy-category-item :category="item" :value="value" ref="categoryItem" :index="index"
:select="select" :oneCategorySelect="oneCategorySelect" :isList="isList"
@tologin="toLogin" @selectsku="selectSku($event, index)" @addCart="addCartPoint"
@loadfinish="getHeightArea"></diy-category-item>
</view>
<view class="end-tips" ref="endTips" :style="{ opacity: endTips }">{{ $lang("diy.diy-category-item.l163.t0") }}</view>
</scroll-view>
<view class="content-wrap"
v-if="(value.template == 2 || value.template == 3 || value.template == 4) && loadType == 'part'">
<view class="child-category-wrap" v-for="(item, index) in categoryTree" :key="index"
:id="'category-' + index" :style="{ display: select == index ? 'block' : 'none' }">
<diy-category-item :category="item" :value="value" ref="categoryItem" :index="index"
:last="index == categoryTree.length - 1 ? true : false" :select="select"
:oneCategorySelect="oneCategorySelect" :isList="isList" @tologin="toLogin"
@selectsku="selectSku($event, index)" @addCart="addCartPoint"
@switch="switchOneCategory"></diy-category-item>
</view>
</view>
</view>
</block>
<view class="category-empty" v-else>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" show-menu-by-longpress></image>
<view class="tips">{{ $lang("diy.diy-category.l123.t0") }}</view>
</view>
</view>
<view class="category-empty" v-else>
<image :src="$util.img('public/uniapp/category/empty.png')" mode="widthFix" show-menu-by-longpress></image>
<view class="tips">{{ $lang("diy.diy-category.l123.t0") }}</view>
</view>
<!-- <view class="cart-box" v-if="(value.template == 2 || value.template == 4) && value.quickBuy && storeToken && categoryTree && categoryTree.length">
<view class="left-wrap">
<view class="cart-icon" ref="cartIcon" :animation="cartAnimation" @tap.stop="$util.redirectTo('/pages_goods/cart')">
<text class="iconfont icon-ziyuan1"></text>
<view class="num" v-if="cartNumber">{{ cartNumber < 99 ? cartNumber : '99+' }}</view>
</view>
<view class="price">
<text class="title">{{ $lang("diy.diy-category.l138.t0") }}</text>
<text class="unit font-size-tag price-font">¥</text>
<text class="money font-size-toolbar price-font">{{ cartTotalMoney[0] }}</text>
<text class="unit font-size-tag price-font">.{{ cartTotalMoney[1] ? cartTotalMoney[1] : '00' }}</text>
</view>
</view>
<view class="right-wrap"><button type="primary" class="settlement-btn" @tap.stop="settlement">{{ $lang("diy.diy-category.l144.t0") }}</button>
</view>
</view> -->
<view class="cart-point" :style="{ left: item.left + 'px', top: item.top + 'px' }" :key="index"
v-for="(item, index) in carIconList"></view>
<ns-goods-sku-category ref="skuSelect" @refresh="refreshData" @addCart="addCartPoint"></ns-goods-sku-category>
</view>
</template>
<script>
// 获取系统状态栏的高度
let systemInfo = uni.getSystemInfoSync();
let menuButtonInfo = {};
// 如果是小程序,获取右上角胶囊的尺寸信息,避免导航栏右侧内容与胶囊重叠(支付宝小程序非本API,尚未兼容)
// #ifdef MP-WEIXIN || MP-BAIDU || MP-TOUTIAO || MP-QQ
menuButtonInfo = uni.getMenuButtonBoundingClientRect();
// #endif
import DiyMinx from './minx.js'
var contentWrapHeight, query, cartPosition;
// 商品分类
export default {
name: 'diy-category',
props: {
value: {
type: Object,
default: () => {
return {};
}
}
},
mixins: [DiyMinx],
data() {
return {
oneCategorySelect: 0,
select: 0,
categoryId: 'category-0',
categoryTree: null,
scrollLock: false,
triggered: true,
heightArea: [],
isSub: false,
carIconList: {},
endTips: 0,
cartAnimation: {},
loadType: '',
templateFourData: [],
isList: false,
lang: uni.getStorageSync("lang")//en-us 英文
};
},
created() {
this.getCategoryTree();
this.loadType = this.value.goodsLevel == 1 && this.value.loadType == 'all' ? 'all' : 'part';
},
mounted() {
query = uni.createSelectorQuery().in(this);
query
.select('.content-wrap')
.boundingClientRect(data => {
if (data) contentWrapHeight = data.height;
})
.exec();
setTimeout(() => {
query
.select('.end-tips')
.boundingClientRect(data => {
if (data && data.top > contentWrapHeight) this.endTips = 1;
})
.exec();
query
.select('.cart-icon')
.boundingClientRect(data => {
if (data) cartPosition = data;
})
.exec();
if (this.value.template == 1) this.getHeightArea(-1);
}, 500);
},
watch: {
// 组件刷新监听
componentRefresh: function (nval) { }
},
computed: {
cartTotalMoney() {
let money = parseFloat(this.cartMoney).toFixed(2);
return money.split('.');
},
// 转换字符数值为真正的数值
navbarHeight() {
// #ifdef APP-PLUS || H5
return 44;
// #endif
// #ifdef MP
// 小程序特别处理,让导航栏高度 = 胶囊高度 + 两倍胶囊顶部与状态栏底部的距离之差(相当于同时获得了导航栏底部与胶囊底部的距离)
// 此方法有缺陷,暂不用(会导致少了几个px),采用直接固定值的方式
// return menuButtonInfo.height + (menuButtonInfo.top - this.navbarHeight) * 2;//导航高度
// let height = systemInfo.platform == 'ios' ? 44 : 48;
let height = menuButtonInfo.top;
// height += systemInfo.navbarHeight;
return height;
// #endif
},
// 导航栏内部盒子的样式
navbarInnerStyle() {
let style = '';
// 导航栏宽度,如果在小程序下,导航栏宽度为胶囊的左边到屏幕左边的距离
// style += 'height:' + this.navbarHeight + 'px;';
// // 如果是各家小程序,导航栏内部的宽度需要减少右边胶囊的宽度
// #ifdef MP
if (this.value.template == 4 && this.value.search) {
style += 'height:' + menuButtonInfo.height + 'px;';
let rightButtonWidth = menuButtonInfo.width ? menuButtonInfo.width * 2 + 'rpx' : '70rpx';
style += 'padding-right:calc(' + rightButtonWidth + ' + 30rpx);';
style += 'padding-top:' + this.navbarHeight + 'px;';
}
// #endif
if (this.value.template != 4 || (this.value.template == 4 && !this.value.search)) {
style += 'height:' + menuButtonInfo.height * 2 + 'rpx;';
style += 'padding-top:' + this.navbarHeight + 'px;';
style += 'text-align: center;';
style += 'line-height:' + menuButtonInfo.height * 2 + 'rpx;';
style += 'font-size: 14px;';
style += 'padding-bottom: 10rpx;';
}
return style;
},
wxSearchHeight() {
let style = '';
// #ifdef MP
style += 'height: 64rpx;';
// #endif
return style;
},
uniPopupTop() {
let top = 0;
// #ifdef MP
top = this.navbarHeight + menuButtonInfo.height + 'px';
// #endif
// #ifdef H5
top = '100rpx';
// #endif
return top;
}
},
methods: {
/**
* 页面显示
*/
pageShow() {
this.$store.dispatch('getCartNumber');
if (!this.heightArea.length) this.getHeightArea(-1);
},
/**
* 获取高度区间
*/
getHeightArea(index) {
let heightArea = [];
query
.selectAll('.content-wrap .child-category')
.boundingClientRect(data => {
if (data && data.length) {
data.forEach((item, index) => {
if (index == 0) heightArea.push([0, item.height]);
else heightArea.push([heightArea[index - 1][1], heightArea[index - 1][1] +
item.height
]);
});
}
})
.exec();
this.heightArea = heightArea;
if (index != -1 && index < this.categoryTree.length - 1) this.$refs.categoryItem[index + 1].getGoodsList();
},
/**
* 获取全部分类
*/
getCategoryTree() {
this.$api.sendRequest({
url: '/api/goodscategory/tree',
data: {
level: 3
},
success: res => {
if (res.code == 0) {
this.categoryTree = res.data;
if (this.value.template == 4) {
this.templateFourData = JSON.parse(JSON.stringify(this.categoryTree));
this.categoryTree = this.templateFourData[0].child_list;
}
//切换英文标题
if (this.lang == 'en-us') {
this.categoryTree.map(item => {
item?.child_list?.map(items => {
items.category_name = items.en_category_name;
return items;
})
item.category_name = item.en_category_name;
return item;
});
}
}
}
});
},
/**
* 切换一级分类
* @param {Object} index
*/
switchOneCategory(index) {
if (index >= this.categoryTree.length) return;
this.select = index;
this.categoryId = 'category-' + index;
// 阻止切换分类之后滚动事件也立即执行
this.scrollLock = true;
},
touchStart() {
this.scrollLock = false;
},
/**
* 监听滚动
* @param {Object} event
*/
listenScroll(event) {
if (this.scrollLock) return;
let scrollTop = event.detail.scrollTop;
if (this.heightArea.length) {
for (let i = 0; i < this.heightArea.length; i++) {
if (scrollTop >= this.heightArea[i][0] && scrollTop <= this.heightArea[i][1]) {
this.select = i;
break;
}
}
if (this.value.template != 1 && this.value.loadType == 'all' && this.heightArea[this.select][1] -
scrollTop - contentWrapHeight < 300) {
this.$refs.categoryItem[this.select].getGoodsList();
}
}
},
onRefresh() {
this.triggered = false;
},
onRestore() {
this.triggered = 'restore'; // 需要重置
},
toLogin() {
this.$emit('tologin');
},
/**
* sku选择
* @param {Object} data
* @param {Object} index
*/
selectSku(data, index) {
this.$api.sendRequest({
url: '/api/goodssku/getInfoForCategory',
data: {
sku_id: data.sku_id
},
success: res => {
if (res.code >= 0) {
let item = res.data;
item.unit = item.unit || $lang('common.ns-goods-sku.ns-goods-sku-index.l150.t0');
if (item.sku_images) item.sku_images = item.sku_images.split(',');
else item.sku_images = [];
// 多规格时合并主图
if (item.goods_spec_format && item.goods_image) {
item.goods_image = item.goods_image.split(',');
item.sku_images = item.goods_image.concat(item.sku_images);
}
// 当前商品SKU规格
if (item.sku_spec_format) item.sku_spec_format = JSON.parse(item.sku_spec_format);
// 商品SKU格式
if (item.goods_spec_format) item.goods_spec_format = JSON.parse(item.goods_spec_format);
// 限时折扣
if (item.promotion_type == 1) {
item.discountTimeMachine = this.$util.countDown(item.end_time - res.timestamp);
}
if (item.promotion_type == 1 && item.discountTimeMachine) {
if (item.member_price > 0 && Number(item.member_price) <= Number(item.discount_price)) {
item.show_price = item.member_price;
} else {
item.show_price = item.discount_price;
}
} else if (item.member_price > 0) {
item.show_price = item.member_price;
} else {
item.show_price = item.price;
}
this.$refs.skuSelect.show(item);
}
}
});
},
settlement() {
if (!this.cartIds.length || this.isSub) return;
this.isSub = true;
uni.removeStorageSync('delivery');
uni.setStorage({
key: 'orderCreateData',
data: {
cart_ids: this.cartIds.toString()
},
success: () => {
this.$util.redirectTo('/pages_order/payment');
this.isSub = false;
}
});
},
/**
* 添加点
* @param {Object} left
* @param {Object} top
*/
addCartPoint(left, top) {
if (this.value.template != 2 && !this.value.quickBuy) return;
let key = new Date().getTime();
this.$set(this.carIconList, key, {
left: left,
top: top,
index: 0,
bezierPos: this.$util.bezier([{
x: left,
y: top
}, {
x: left - 200,
y: left - 120
},
{
x: cartPosition.left + 10,
y: cartPosition.top
}
], 6).bezier_points,
timer: null
});
this.startAnimation(key);
},
/**
* 执行动画
* @param {Object} key
*/
startAnimation(key) {
let bezierPos = this.carIconList[key].bezierPos,
index = this.carIconList[key].index;
this.carIconList[key].timer = setInterval(() => {
if (index < 6) {
this.carIconList[key].left = bezierPos[index].x;
this.carIconList[key].top = bezierPos[index].y;
index++;
} else {
clearInterval(this.carIconList[key].timer);
delete this.carIconList[key];
this.$forceUpdate();
// 购物车图标
setTimeout(() => {
this.$store.commit('setCartChange');
}, 100);
let animation = uni.createAnimation({
duration: 200,
timingFunction: 'ease'
});
animation.scale(1.2).step();
this.cartAnimation = animation.export();
setTimeout(() => {
animation.scale(1).step();
this.cartAnimation = animation.export();
}, 300);
}
}, 50);
},
// 风格四头部切换
templateFourOneFn(index) {
this.categoryTree = this.templateFourData[index].child_list || [];
this.oneCategorySelect = index;
this.select = 0;
},
// 操作多规格商品弹框后,刷新商品数据
refreshData() {
this.$refs.categoryItem[this.select].loadGoodsCartNum(true);
},
changeListStyle() {
this.isList = !this.isList;
},
onClickSearch() {
this.$util.redirectTo('/pages_tool/goods/search');
}
}
};
</script>
<style lang="scss" scoped>
.category-page-wrap {
width: 100vw;
// height: calc(100vh - var(--tab-bar-height, 0));
display: flex;
flex-direction: column;
background-color: #fff;
}
.content-box {
flex: 1;
height: 0;
display: flex;
.tree-wrap {
width: 170rpx;
height: 100%;
background-color: #f5f5f5;
}
.right-flex-wrap {
flex: 1;
width: 0;
height: 100%;
background: #f4f6fa;
display: flex;
flex-direction: column;
transform: translateX(0px);
.content-wrap {
display: flex;
flex: 1;
height: 0;
width: 100%;
}
.child-category-wrap {
width: 100%;
height: 100%;
}
}
}
.tree-wrap .category-item-wrap {
height: auto;
background-color: #fff;
}
.tree-wrap .category-item {
line-height: 1.5;
padding: 26rpx 28rpx;
box-sizing: border-box;
position: relative;
background-color: #f5f5f5;
view {
color: #222222;
width: 100%;
white-space: break-word;
overflow: hidden;
text-align: center;
font-size: 10px;
}
&.border-top {
border-bottom-right-radius: 12rpx;
}
&.border-bottom {
border-top-right-radius: 12rpx;
}
&.select {
background: #fff;
view {
color: #333;
font-weight: bold;
font-size: $font-size-base;
}
&::before {
content: ' ';
width: 8rpx;
height: 34rpx;
background: var(--base-color);
display: block;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
}
}
.search-box {
position: relative;
padding: 20rpx 30rpx;
display: flex;
align-items: center;
background: #fff;
.search-content {
position: relative;
/* #ifndef MP-WEIXIN */
height: 64rpx;
/* #endif */
/* #ifdef MP-WEIXIN */
height: 100%;
/* #endif */
border-radius: 40rpx;
flex: 1;
background-color: #f5f5f5;
input {
box-sizing: border-box;
display: block;
height: 100%;
width: 100%;
padding: 0 20rpx 0 40rpx;
background: #f5f5f5;
color: #333;
border-radius: 40rpx;
}
.iconfont {
position: absolute;
top: 50%;
right: 10rpx;
transform: translateY(-50%);
font-size: $font-size-toolbar;
z-index: 10;
color: #89899a;
width: 80rpx;
text-align: center;
}
}
// 切换列表图标
.iconfont {
font-size: 36rpx;
margin: 0 0rpx 0 20rpx;
}
}
.cart-box {
height: 100rpx;
width: 100%;
background: #fff;
border-top: 1px solid #f5f5f5;
box-sizing: border-box;
padding: 0 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
.left-wrap {
display: flex;
align-items: center;
}
.cart-icon {
width: 70rpx;
height: 70rpx;
position: relative;
.iconfont {
color: var(--btn-text-color);
width: inherit;
height: inherit;
background-color: $base-color;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.num {
position: absolute;
top: 0;
right: 0;
transform: translate(60%, 0);
display: inline-block;
box-sizing: border-box;
color: #fff;
line-height: 1.2;
text-align: center;
font-size: 24rpx;
padding: 0 6rpx;
min-width: 30rpx;
border-radius: 16rpx;
background-color: var(--price-color);
border: 2rpx solid #fff;
}
}
.price {
margin-left: 30rpx;
.title {
color: #333;
}
.money,
.unit {
font-weight: bold;
color: var(--price-color);
}
}
.settlement-btn {
margin: 0 0 0 20rpx;
width: 200rpx;
font-weight: bold;
border-radius: 50rpx;
height: 70rpx;
line-height: 70rpx;
}
}
.cart-point {
width: 26rpx;
height: 26rpx;
position: fixed;
z-index: 1000;
background: #f00;
border-radius: 50%;
transition: all 0.05s;
}
.category-empty {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
image {
width: 380rpx;
}
.tips {
font-size: 26rpx;
font-weight: 500;
color: #999;
margin-top: 50rpx;
}
}
.end-tips {
text-align: center;
color: #999;
font-size: 24rpx;
padding: 20rpx 0;
opacity: 0;
}
// 风格四
.category-template-4 {
.search-box {
.search-content input {
background-color: #f1f1f1;
}
}
.cart-box {
position: relative;
z-index: 2;
}
::v-deep .template-four {
position: relative;
z-index: 1;
.template-four-wrap {
position: relative;
z-index: 1;
padding-left: 20rpx;
padding-right: 80rpx;
padding-bottom: 10rpx;
display: flex;
height: 172rpx;
align-items: baseline;
box-sizing: border-box;
box-shadow: 0 4rpx 4rpx rgba(123, 123, 123, 0.1);
}
.template-four-popup {
display: flex;
flex-direction: column;
overflow: hidden;
.title {
line-height: 1;
margin-bottom: 20rpx;
font-weight: bold;
}
.template-four-scroll {
display: flex;
flex-wrap: wrap;
align-items: baseline;
align-content: baseline;
padding: 20rpx;
white-space: nowrap;
height: 380rpx;
box-sizing: border-box;
.uni-scroll-view-content {
flex-wrap: wrap;
align-items: baseline;
align-content: baseline;
}
.item {
display: flex;
flex-direction: column;
align-items: center;
padding: 4rpx 0;
color: #666;
margin-right: 16rpx;
border-radius: 40rpx;
margin-bottom: 10rpx;
width: calc((100% - 64rpx) / 5);
&:nth-child(5n + 5) {
margin-right: 0;
}
.image-warp {
margin-bottom: 6rpx;
padding: 4rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 42rpx;
border: 4rpx solid transparent;
}
image {
width: 84rpx;
height: 84rpx;
border-radius: 32rpx;
}
.text {
padding: 2rpx 16rpx;
border-radius: 40rpx;
font-size: $font-size-tag;
}
&.selected {
.text {
background-color: $base-color;
color: var(--btn-text-color);
}
}
}
}
.pack-up {
font-size: $font-size-tag;
color: #888888;
height: 74rpx;
display: flex;
align-items: center;
justify-content: center;
border-top: 2rpx solid #f2f2f2;
.iconfont {
font-size: 40rpx;
margin-left: -4rpx;
}
}
}
.category-item-all {
position: absolute;
bottom: 0;
z-index: 1;
right: 0;
top: 0;
width: 72rpx;
line-height: 1;
background-color: #fff;
.category-item-all-wrap {
position: absolute;
bottom: 0;
right: 0;
top: 0;
left: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 2;
}
.text {
writing-mode: tb-rl;
margin-bottom: 6rpx;
letter-spacing: 4rpx;
font-size: $font-size-tag;
font-weight: bold;
}
.img {
width: 20rpx;
height: 20rpx;
}
&::after {
content: '';
// box-shadow: -4rpx 10rpx 20rpx rgba(0, 0, 0, 0.1);
position: absolute;
left: 0;
width: 10rpx;
// height: 100rpx;
top: 20%;
bottom: 20%;
// transform: translateY(-50%);
// background-color: #F0F5FF;
}
}
.uni-scroll-view-content {
display: flex;
}
.category-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 130rpx;
flex-shrink: 0;
margin-right: 20rpx;
padding: 4rpx 0;
&:last-of-type {
margin-right: 0;
}
.image-warp {
margin-bottom: 6rpx;
padding: 4rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 42rpx;
border: 4rpx solid transparent;
}
image {
width: 84rpx;
height: 84rpx;
border-radius: 32rpx;
}
.text {
font-size: $font-size-tag;
}
}
.select {
.text {
padding: 8rpx 16rpx;
border-radius: 40rpx;
color: #fff;
font-size: $font-size-tag;
line-height: 1;
}
}
}
.content-wrap .categoty-goods-wrap .goods-list {
margin-top: 30rpx;
}
.tree-wrap .category-item.select::before {
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
}
</style>