通过微信开发者工具 商城模板 创建新小程序
This commit is contained in:
		@@ -0,0 +1,95 @@
 | 
			
		||||
# Sidebar 侧边导航
 | 
			
		||||
 | 
			
		||||
### 引入
 | 
			
		||||
 | 
			
		||||
全局引入,在miniprogram根目录下的`app.json`中配置,局部引入,在需要引入的页面或组件的`index.json`中配置。
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
// app.json 或 index.json
 | 
			
		||||
"usingComponents": {
 | 
			
		||||
  "wr-sidebar": "path/to/components/goods-category/wr-sidebar/index",
 | 
			
		||||
  "wr-sidebar-item": "path/to/component/goods-category/wr-sidebar/wr-sidebar-item/index"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 代码演示
 | 
			
		||||
 | 
			
		||||
### 基础用法
 | 
			
		||||
 | 
			
		||||
通过在`wr-sidebar`上设置`activeKey`属性来控制选中项
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<wr-sidebar active-key="{{ activeKey }}" bind:change="onChange">
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" />
 | 
			
		||||
</wr-sidebar>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
``` javascript
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    activeKey: 0
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onChange(event) {
 | 
			
		||||
    wx.showToast({
 | 
			
		||||
      icon: 'none',
 | 
			
		||||
      title: `切换至第${event.detail}项`
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 提示气泡(暂未实现)
 | 
			
		||||
 | 
			
		||||
设置`dot`属性后,会在右上角展示一个小红点。设置`info`属性后,会在右上角展示相应的徽标
 | 
			
		||||
 | 
			
		||||
```html
 | 
			
		||||
<wr-sidebar active-key="{{ activeKey }}">
 | 
			
		||||
  <wr-sidebar-item title="标签名称" dot />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" info="5" />
 | 
			
		||||
  <wr-sidebar-item title="标签名称" info="99+" />
 | 
			
		||||
</wr-sidebar>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## API
 | 
			
		||||
 | 
			
		||||
### Sidebar Props
 | 
			
		||||
 | 
			
		||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
 | 
			
		||||
|-----------|-----------|-----------|-------------|-------------|
 | 
			
		||||
| activeKey | 选中项的索引 | *string \| number* | `0` | - |
 | 
			
		||||
 | 
			
		||||
### Sidebar Event
 | 
			
		||||
 | 
			
		||||
| 事件名 | 说明 | 参数 |
 | 
			
		||||
|------|------|------|
 | 
			
		||||
| change | 切换选项时触发 | 当前选中选项的索引 |
 | 
			
		||||
 | 
			
		||||
### Sidebar 外部样式类
 | 
			
		||||
 | 
			
		||||
| 类名 | 说明 |
 | 
			
		||||
|-----------|-----------|
 | 
			
		||||
| custom-class | 根节点样式类 |
 | 
			
		||||
 | 
			
		||||
### SidebarItem Props
 | 
			
		||||
 | 
			
		||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
 | 
			
		||||
|-----------|-----------|-----------|-------------|-------------|
 | 
			
		||||
| title | 内容 | *string* | `''` | - |
 | 
			
		||||
| disabled | 是否禁用 | | *boolean* | `false` | - |
 | 
			
		||||
| dot | 是否显示右上角小红点 | *boolean* | `false` | - |
 | 
			
		||||
| info | 提示消息 | *string \| number* | `''` | - |
 | 
			
		||||
 | 
			
		||||
### SidebarItem Event
 | 
			
		||||
 | 
			
		||||
| 事件名 | 说明 | 参数 |
 | 
			
		||||
|------|------|------|
 | 
			
		||||
| click | 点击徽章时触发 | 当前徽章的索引 |
 | 
			
		||||
 | 
			
		||||
### SidebarItem 外部样式类
 | 
			
		||||
 | 
			
		||||
| 类名 | 说明 |
 | 
			
		||||
|-----------|-----------|
 | 
			
		||||
| custom-class | 根节点样式类 |
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
Component({
 | 
			
		||||
  relations: {
 | 
			
		||||
    '../../c-sidebar/index': {
 | 
			
		||||
      type: 'ancestor',
 | 
			
		||||
      linked(target) {
 | 
			
		||||
        this.parent = target;
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
  properties: {
 | 
			
		||||
    title: String,
 | 
			
		||||
    disabled: Boolean,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    topRightRadius: false,
 | 
			
		||||
    bottomRightRadius: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(selected) {
 | 
			
		||||
      return this.setData({ selected });
 | 
			
		||||
    },
 | 
			
		||||
    onClick() {
 | 
			
		||||
      const { parent } = this;
 | 
			
		||||
 | 
			
		||||
      if (!parent || this.properties.disabled) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const index = parent.children.indexOf(this);
 | 
			
		||||
 | 
			
		||||
      parent.setActive(index).then(() => {
 | 
			
		||||
        this.triggerEvent('click', index);
 | 
			
		||||
        parent.triggerEvent('change', { index });
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setTopRightRadius(val) {
 | 
			
		||||
      return this.setData({
 | 
			
		||||
        topRightRadius: val,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setBottomRightRadius(val) {
 | 
			
		||||
      return this.setData({
 | 
			
		||||
        bottomRightRadius: val,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
<view class="c-sidebar-item-container">
 | 
			
		||||
  <view
 | 
			
		||||
    class="c-sidebar-item {{ selected ? 'active' : '' }} {{ disabled ? 'disabled' : '' }} {{topRightRadius ? 'top-right-radius' : ''}} {{bottomRightRadius ? 'bottom-right-radius' : ''}} custom-class"
 | 
			
		||||
    hover-class="c-sidebar-item--hover"
 | 
			
		||||
    hover-stay-time="70"
 | 
			
		||||
    bind:tap="onClick"
 | 
			
		||||
  >
 | 
			
		||||
    <view class="c-sidebar-item__text text-overflow"> {{ title }} </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,60 @@
 | 
			
		||||
.c-sidebar-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
  padding: 20rpx 0;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  background: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active::before {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 6rpx;
 | 
			
		||||
  height: 48rpx;
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translate(0, -50%);
 | 
			
		||||
  border-radius: 64rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item__text {
 | 
			
		||||
  width: 136rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
  padding: 8rpx 0;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item.active .c-sidebar-item__text {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
  border-radius: 36rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.text-overflow {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.top-right-radius {
 | 
			
		||||
  border-top-right-radius: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-right-radius {
 | 
			
		||||
  border-bottom-right-radius: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.c-sidebar-item-container {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,106 @@
 | 
			
		||||
Component({
 | 
			
		||||
  relations: {
 | 
			
		||||
    './c-sidebar-item/index': {
 | 
			
		||||
      type: 'descendant',
 | 
			
		||||
      linked(target) {
 | 
			
		||||
        this.children.push(target);
 | 
			
		||||
        this.setActive(this.properties.activeKey, true);
 | 
			
		||||
      },
 | 
			
		||||
      unlinked(target) {
 | 
			
		||||
        this.children = this.children.filter((item) => item !== target);
 | 
			
		||||
        this.setActive(this.properties.activeKey, true);
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    activeKey: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  observers: {
 | 
			
		||||
    activeKey(newVal) {
 | 
			
		||||
      this.setActive(newVal);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  created() {
 | 
			
		||||
    this.children = [];
 | 
			
		||||
    this.currentActive = -1;
 | 
			
		||||
    this.topRightRadiusItemIndexs = [];
 | 
			
		||||
    this.bottomRightRadiusItemIndexs = [];
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(activeKey, isChildrenChange) {
 | 
			
		||||
      const {
 | 
			
		||||
        children,
 | 
			
		||||
        currentActive,
 | 
			
		||||
        topRightRadiusItemIndexs: preTopRightRadiusItemIndexs,
 | 
			
		||||
        bottomRightRadiusItemIndexs: preBottomRightRadiusItemIndexs,
 | 
			
		||||
      } = this;
 | 
			
		||||
 | 
			
		||||
      if (!children.length) {
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (activeKey === currentActive && !isChildrenChange) {
 | 
			
		||||
        return Promise.resolve();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.currentActive = activeKey;
 | 
			
		||||
      this.topRightRadiusItemIndexs = this.getTopRightRadiusItemIndexs(
 | 
			
		||||
        activeKey,
 | 
			
		||||
        children,
 | 
			
		||||
      );
 | 
			
		||||
      this.bottomRightRadiusItemIndexs = this.getBottomRightRadiusItemIndexs(
 | 
			
		||||
        activeKey,
 | 
			
		||||
        children,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      const stack = []; // 任务列表,存放调用子组件的setActive后返回的一堆promise
 | 
			
		||||
 | 
			
		||||
      // 将旧的选中项改为false
 | 
			
		||||
      if (currentActive !== activeKey && children[currentActive]) {
 | 
			
		||||
        stack.push(children[currentActive].setActive(false));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // 将新的选中项改为true
 | 
			
		||||
      if (children[activeKey]) {
 | 
			
		||||
        stack.push(children[activeKey].setActive(true));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      preTopRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setTopRightRadius(false));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      preBottomRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setBottomRightRadius(false));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.topRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setTopRightRadius(true));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.bottomRightRadiusItemIndexs.forEach((item) => {
 | 
			
		||||
        stack.push(children[item].setBottomRightRadius(true));
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return Promise.all(stack);
 | 
			
		||||
    },
 | 
			
		||||
    getTopRightRadiusItemIndexs(activeKey, children) {
 | 
			
		||||
      const { length } = children;
 | 
			
		||||
      if (activeKey !== 0 && activeKey < length - 1) return [0, activeKey + 1];
 | 
			
		||||
      if (activeKey !== 0) return [0];
 | 
			
		||||
      if (activeKey < length - 1) return [activeKey + 1];
 | 
			
		||||
      return [];
 | 
			
		||||
    },
 | 
			
		||||
    getBottomRightRadiusItemIndexs(activeKey) {
 | 
			
		||||
      if (activeKey !== 0) return [activeKey - 1];
 | 
			
		||||
      return [];
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
<scroll-view class="c-sidebar custom-class" scroll-y>
 | 
			
		||||
  <slot />
 | 
			
		||||
</scroll-view>
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
.c-sidebar {
 | 
			
		||||
  width: 176rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
.c-sidebar::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,37 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    tabList: Array,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    unfolded: false,
 | 
			
		||||
    boardMaxHeight: null,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    wx.createSelectorQuery()
 | 
			
		||||
      .in(this)
 | 
			
		||||
      .select('.c-tabbar-more')
 | 
			
		||||
      .boundingClientRect((rect) => {
 | 
			
		||||
        this.setData({ boardMaxHeight: rect.height });
 | 
			
		||||
      })
 | 
			
		||||
      .exec();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    changeFold() {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        unfolded: !this.data.unfolded,
 | 
			
		||||
      });
 | 
			
		||||
      const { unfolded } = this.data;
 | 
			
		||||
      this.triggerEvent('change', { unfolded });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onSelect(event) {
 | 
			
		||||
      const activeKey = event.currentTarget.dataset.index;
 | 
			
		||||
      this.triggerEvent('select', activeKey);
 | 
			
		||||
      this.changeFold();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,25 @@
 | 
			
		||||
<view class="c-tabbar-more">
 | 
			
		||||
  <view class="c-tabbar-more__btn" bind:tap="changeFold">
 | 
			
		||||
    <view class="wr {{unfolded ? 'wr-arrow-up':'wr-arrow-down'}}"></view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="t-tabbar-more__boardwrapper" wx:if="{{ unfolded }}">
 | 
			
		||||
    <view class="t-tabbar-more__mask"></view>
 | 
			
		||||
    <scroll-view
 | 
			
		||||
      class="c-tabbar-more__board"
 | 
			
		||||
      style="{{ boardMaxHeight ? 'height:' + boardMaxHeight + 'px;' : '' }}"
 | 
			
		||||
      scroll-y
 | 
			
		||||
    >
 | 
			
		||||
      <view class="c-tabbar-more__boardinner">
 | 
			
		||||
        <view
 | 
			
		||||
          class="c-tabbar-more__item text-overflow"
 | 
			
		||||
          wx:for="{{ tabList }}"
 | 
			
		||||
          wx:key="index"
 | 
			
		||||
          data-index="{{ index }}"
 | 
			
		||||
          bind:tap="onSelect"
 | 
			
		||||
        >
 | 
			
		||||
          {{ item.name }}
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </scroll-view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
.c-tabbar-more {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: calc(100% - var(--tabbar-height, 100rpx));
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: var(--tabbar-height, 100rpx);
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__btn {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: calc(0rpx - var(--tabbar-height, 100rpx));
 | 
			
		||||
  right: 0;
 | 
			
		||||
  width: 80rpx;
 | 
			
		||||
  height: var(--tabbar-height, 100rpx);
 | 
			
		||||
  line-height: var(--tabbar-height, 100rpx);
 | 
			
		||||
  background-color: var(--tabbar-background-color, white);
 | 
			
		||||
  box-shadow: -20rpx 0 20rpx -10rpx var(--tabbar-background-color, white);
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__btn .market {
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
.t-tabbar-more__boardwrapper {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.t-tabbar-more__mask {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__board {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  max-height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__boardinner {
 | 
			
		||||
  padding: 20rpx 0 20rpx 20rpx;
 | 
			
		||||
  background-color: var(--tabbar-background-color, white);
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row wrap;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-more__item {
 | 
			
		||||
  margin: 0 20rpx 20rpx 0;
 | 
			
		||||
  flex: 0 0 calc((100% - 60rpx) / 3);
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  padding: 0 10rpx;
 | 
			
		||||
  border-radius: 30rpx;
 | 
			
		||||
  height: 60rpx;
 | 
			
		||||
  line-height: 60rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
  color: #5d5d5d;
 | 
			
		||||
  background-color: #eee;
 | 
			
		||||
}
 | 
			
		||||
.text-overflow {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    activeKey: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    tabList: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
    showMore: Boolean, // 是否需要下拉功能
 | 
			
		||||
  },
 | 
			
		||||
  observers: {
 | 
			
		||||
    activeKey(newVal) {
 | 
			
		||||
      if (this.properties.tabList && newVal) {
 | 
			
		||||
        this.setActive(newVal).catch((e) => {
 | 
			
		||||
          console.error(e);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    currentActive: -1,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    this.setActive(this.properties.activeKey).catch((e) => {
 | 
			
		||||
      console.error(e);
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    setActive(activeKey) {
 | 
			
		||||
      if (
 | 
			
		||||
        !this.properties.tabList[activeKey] ||
 | 
			
		||||
        this.properties.tabList[activeKey].disabled
 | 
			
		||||
      ) {
 | 
			
		||||
        return Promise.reject('数据异常或不可操作');
 | 
			
		||||
      }
 | 
			
		||||
      return new Promise((resolve) => {
 | 
			
		||||
        this.setData(
 | 
			
		||||
          {
 | 
			
		||||
            currentActive: activeKey,
 | 
			
		||||
          },
 | 
			
		||||
          () => resolve(),
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    onClick(event) {
 | 
			
		||||
      let activeKey;
 | 
			
		||||
      if (event.type === 'select') {
 | 
			
		||||
        activeKey = event.detail;
 | 
			
		||||
      } else {
 | 
			
		||||
        activeKey = event.currentTarget.dataset.index;
 | 
			
		||||
      }
 | 
			
		||||
      this.setActive(activeKey)
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          const { currentActive } = this.data;
 | 
			
		||||
          this.triggerEvent('change', { index: currentActive });
 | 
			
		||||
        })
 | 
			
		||||
        .catch((e) => {
 | 
			
		||||
          console.error(e);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "c-tabbar-more": "./c-tabbar-more/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
<view class="c-tabbar custom-class">
 | 
			
		||||
  <scroll-view
 | 
			
		||||
    wx:if="{{ tabList.length > 0 }}"
 | 
			
		||||
    class="c-tabbar__scroll"
 | 
			
		||||
    scroll-x="true"
 | 
			
		||||
    scroll-into-view="{{ 'id-' + currentActive }}"
 | 
			
		||||
  >
 | 
			
		||||
    <view
 | 
			
		||||
      class="c-tabbar__inner {{showMore && tabList.length > 4 ? 'c-tabbar__inner_more' : ''}}"
 | 
			
		||||
    >
 | 
			
		||||
      <view
 | 
			
		||||
        wx:for="{{ tabList }}"
 | 
			
		||||
        wx:key="index"
 | 
			
		||||
        id="{{ 'id-' + index }}"
 | 
			
		||||
        class="c-tabbar-item {{ currentActive === index ? 'active' : '' }} {{ item.disabled ? 'disabled' : '' }}"
 | 
			
		||||
        bind:tap="onClick"
 | 
			
		||||
        data-index="{{index}}"
 | 
			
		||||
      >
 | 
			
		||||
        <view class="c-tabbar-item__text"> {{ item.name }} </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </scroll-view>
 | 
			
		||||
  <c-tabbar-more
 | 
			
		||||
    wx:if="{{ showMore && tabList.length > 4 }}"
 | 
			
		||||
    tabList="{{tabList}}"
 | 
			
		||||
    bindselect="onClick"
 | 
			
		||||
  />
 | 
			
		||||
  <slot />
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,53 @@
 | 
			
		||||
.c-tabbar {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  --tabbar-height: 100rpx;
 | 
			
		||||
  --tabbar-fontsize: 28rpx;
 | 
			
		||||
  --tabbar-background-color: white;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__inner {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row nowrap;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__scroll {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__scroll::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  display: block;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  bottom: -1px;
 | 
			
		||||
  height: 1px;
 | 
			
		||||
  background-color: #eee;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar__inner.c-tabbar__inner_more::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  display: block;
 | 
			
		||||
  width: 100rpx;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  flex: none;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item {
 | 
			
		||||
  flex: none;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  color: #282828;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  padding: 0 20rpx;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item.active:not(.disabled) {
 | 
			
		||||
  color: #0071ce;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item.disabled {
 | 
			
		||||
  color: #ccc;
 | 
			
		||||
}
 | 
			
		||||
.c-tabbar-item__text {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  line-height: 100rpx;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,75 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['custom-class'],
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    category: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
    },
 | 
			
		||||
    initActive: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
      observer(newVal, oldVal) {
 | 
			
		||||
        if (newVal[0] !== oldVal[0]) {
 | 
			
		||||
          this.setActiveKey(newVal[0], 0);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    isSlotRight: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    level: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 3,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data: {
 | 
			
		||||
    activeKey: 0,
 | 
			
		||||
    subActiveKey: 0,
 | 
			
		||||
  },
 | 
			
		||||
  attached() {
 | 
			
		||||
    if (this.properties.initActive && this.properties.initActive.length > 0) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        activeKey: this.properties.initActive[0],
 | 
			
		||||
        subActiveKey: this.properties.initActive[1] || 0,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    onParentChange(event) {
 | 
			
		||||
      this.setActiveKey(event.detail.index, 0).then(() => {
 | 
			
		||||
        this.triggerEvent('change', [
 | 
			
		||||
          this.data.activeKey,
 | 
			
		||||
          this.data.subActiveKey,
 | 
			
		||||
        ]);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    onChildChange(event) {
 | 
			
		||||
      this.setActiveKey(this.data.activeKey, event.detail.index).then(() => {
 | 
			
		||||
        this.triggerEvent('change', [
 | 
			
		||||
          this.data.activeKey,
 | 
			
		||||
          this.data.subActiveKey,
 | 
			
		||||
        ]);
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    changCategory(event) {
 | 
			
		||||
      const { item } = event.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('changeCategory', {
 | 
			
		||||
        item,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    setActiveKey(key, subKey) {
 | 
			
		||||
      return new Promise((resolve) => {
 | 
			
		||||
        this.setData(
 | 
			
		||||
          {
 | 
			
		||||
            activeKey: key,
 | 
			
		||||
            subActiveKey: subKey,
 | 
			
		||||
          },
 | 
			
		||||
          () => {
 | 
			
		||||
            resolve();
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "c-tabbar": "./components/c-tabbar/index",
 | 
			
		||||
    "c-sidebar": "./components/c-sidebar/index",
 | 
			
		||||
    "c-sidebar-item": "./components/c-sidebar/c-sidebar-item/index",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
<view class="goods-category custom-class">
 | 
			
		||||
	<c-sidebar custom-class="custom-sidebar" bindchange="onParentChange" activeKey="{{activeKey}}">
 | 
			
		||||
		<c-sidebar-item
 | 
			
		||||
		  wx:for="{{ category }}"
 | 
			
		||||
		  wx:key="index"
 | 
			
		||||
		  title="{{ item.name }}"
 | 
			
		||||
		  disabled="{{ item.disabled }}"
 | 
			
		||||
		/>
 | 
			
		||||
	</c-sidebar>
 | 
			
		||||
	<view class="goods-category__right">
 | 
			
		||||
		<c-tabbar
 | 
			
		||||
		  wx:if="{{isSlotRight}}"
 | 
			
		||||
		  activeKey="{{subActiveKey}}"
 | 
			
		||||
		  bindchange="onChildChange"
 | 
			
		||||
		  showMore
 | 
			
		||||
		>
 | 
			
		||||
			<slot/>
 | 
			
		||||
		</c-tabbar>
 | 
			
		||||
		<view wx:if="{{!isSlotRight}}" class="goods-category-normal">
 | 
			
		||||
			<view class="goods-category-normal-item" wx:if="{{category[activeKey].children && category[activeKey].children.length > 0}}">
 | 
			
		||||
				<block wx:for="{{category[activeKey].children}}" wx:key="index" wx:if="{{level === 3 && item.children && item.children.length > 0}}">
 | 
			
		||||
					<view class="flex goods-category-normal-item-title">
 | 
			
		||||
						{{item.name}}
 | 
			
		||||
					</view>
 | 
			
		||||
					<view class="goods-category-normal-item-container">
 | 
			
		||||
						<view
 | 
			
		||||
						  class="goods-category-normal-item-container-item"
 | 
			
		||||
						  wx:for="{{item.children}}"
 | 
			
		||||
						  wx:for-index="subIndex"
 | 
			
		||||
						  wx:key="subIndex"
 | 
			
		||||
						  wx:for-item="subItem"
 | 
			
		||||
						  bindtap="changCategory"
 | 
			
		||||
						  data-item="{{subItem}}"
 | 
			
		||||
						>
 | 
			
		||||
							<t-image src="{{subItem.thumbnail}}" t-class="image" />
 | 
			
		||||
							<view class="flex goods-category-normal-item-container-item-title">
 | 
			
		||||
								{{subItem.name}}
 | 
			
		||||
							</view>
 | 
			
		||||
						</view>
 | 
			
		||||
					</view>
 | 
			
		||||
				</block>
 | 
			
		||||
				<view class="goods-category-normal-item-second-container" wx:if="{{level === 2}}">
 | 
			
		||||
					<block wx:for="{{category[activeKey].children}}" wx:key="index">
 | 
			
		||||
						<view
 | 
			
		||||
						  class="goods-category-normal-item-second-container-item"
 | 
			
		||||
						  wx:for-key="index"
 | 
			
		||||
						  bindtap="changCategory"
 | 
			
		||||
						  data-item="{{item}}"
 | 
			
		||||
						>
 | 
			
		||||
							<t-image src="{{item.thumbnail}}" t-class="image" />
 | 
			
		||||
							<view class="flex goods-category-normal-item-container-item-title">
 | 
			
		||||
								{{item.name}}
 | 
			
		||||
							</view>
 | 
			
		||||
						</view>
 | 
			
		||||
					</block>
 | 
			
		||||
				</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,102 @@
 | 
			
		||||
.goods-category {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category__right {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: scroll;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal {
 | 
			
		||||
  margin: 28rpx 34rpx 0rpx 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  padding-top: 28rpx;
 | 
			
		||||
  margin-top: -24rpx;
 | 
			
		||||
  margin-bottom: 30rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item {
 | 
			
		||||
  height: 196rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  width: 33.3%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item .image {
 | 
			
		||||
  width: 144rpx;
 | 
			
		||||
  height: 144rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-container-item-title {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category .custom-sidebar {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar {
 | 
			
		||||
  width: 180rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.custom-sidebar::-webkit-scrollbar {
 | 
			
		||||
  width: 0;
 | 
			
		||||
  height: 0;
 | 
			
		||||
  color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  margin-top: 8rpx;
 | 
			
		||||
  margin-bottom: 30rpx;
 | 
			
		||||
  display: grid;
 | 
			
		||||
  grid-template-columns: 33.33% 33.33% 33.33%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item {
 | 
			
		||||
  height: 200rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item .image {
 | 
			
		||||
  width: 144rpx;
 | 
			
		||||
  height: 144rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-category-normal-item-second-container-item-title {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								mini-program/pages/goods/category/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								mini-program/pages/goods/category/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
import { getCategoryList } from '../../../services/good/fetchCategoryList';
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    list: [],
 | 
			
		||||
  },
 | 
			
		||||
  async init() {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await getCategoryList();
 | 
			
		||||
      this.setData({
 | 
			
		||||
        list: result,
 | 
			
		||||
      });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error('err:', error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.getTabBar().init();
 | 
			
		||||
  },
 | 
			
		||||
  onChange() {
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: '/pages/goods/list/index',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										6
									
								
								mini-program/pages/goods/category/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mini-program/pages/goods/category/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "分类",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "goods-category": "./components/goods-category/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								mini-program/pages/goods/category/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mini-program/pages/goods/category/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
<view class="wrap">
 | 
			
		||||
  <goods-category
 | 
			
		||||
    level="{{3}}"
 | 
			
		||||
    custom-class="goods-category-class"
 | 
			
		||||
    category="{{list}}"
 | 
			
		||||
    bind:changeCategory="onChange"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
							
								
								
									
										23
									
								
								mini-program/pages/goods/category/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mini-program/pages/goods/category/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
.tabbar-position {
 | 
			
		||||
  position: fixed !important;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.wrap {
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.goods-category-class {
 | 
			
		||||
  background-color: #f6f6f6 !important;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
}
 | 
			
		||||
.goods-category-class .goods-category-normal-item-container-item {
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
page {
 | 
			
		||||
  min-height: none;
 | 
			
		||||
  padding-bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.3 KiB  | 
@@ -0,0 +1,36 @@
 | 
			
		||||
// pages/goods/comments/components/comments-card/images-videos/index.js
 | 
			
		||||
Component({
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的属性列表
 | 
			
		||||
   */
 | 
			
		||||
  properties: {
 | 
			
		||||
    resources: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的初始数据
 | 
			
		||||
   */
 | 
			
		||||
  data: {
 | 
			
		||||
    classType: 'single',
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  observers: {
 | 
			
		||||
    resources: function (newVal) {
 | 
			
		||||
      if (newVal.length <= 1) {
 | 
			
		||||
        this.setData({ classType: 'single' });
 | 
			
		||||
      } else if (newVal.length === 2) {
 | 
			
		||||
        this.setData({ classType: 'double' });
 | 
			
		||||
      } else {
 | 
			
		||||
        this.setData({ classType: 'multiple' });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 组件的方法列表
 | 
			
		||||
   */
 | 
			
		||||
  methods: {},
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "my-video": "../my-video/index",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<view class="images-videos-container container-{{classType}}">
 | 
			
		||||
	<view
 | 
			
		||||
	  class="resource-container resource-container-{{classType}}"
 | 
			
		||||
	  wx:for="{{resources}}"
 | 
			
		||||
	  wx:for-item="resource"
 | 
			
		||||
	  wx:key="*this"
 | 
			
		||||
	>
 | 
			
		||||
		<t-image wx:if="{{resource.type === 'image'}}" t-class="resource-item-{{classType}}" src="{{resource.src}}" />
 | 
			
		||||
		<my-video wx:else videoSrc="{{resource.src}} " my-video="resource-item-{{classType}}">
 | 
			
		||||
			<t-image t-class="resource-item resource-item-{{classType}}" slot="cover-img" src="{{resource.coverSrc}}" />
 | 
			
		||||
			<image class="play-icon" slot="play-icon" src="./assets/play.png" />
 | 
			
		||||
		</my-video>
 | 
			
		||||
	</view>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,68 @@
 | 
			
		||||
.resource-item-single {
 | 
			
		||||
  width: 360rpx;
 | 
			
		||||
  height: 360rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-item-double {
 | 
			
		||||
  width: 334rpx;
 | 
			
		||||
  height: 334rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-item-multiple {
 | 
			
		||||
  width: 218rpx;
 | 
			
		||||
  height: 218rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-single {
 | 
			
		||||
  padding-left: 0;
 | 
			
		||||
  padding-top: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-double {
 | 
			
		||||
  padding-left: 18rpx;
 | 
			
		||||
  padding-top: 18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container-multiple {
 | 
			
		||||
  padding-left: 16rpx;
 | 
			
		||||
  padding-top: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-single {
 | 
			
		||||
  margin-left: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-double {
 | 
			
		||||
  margin-left: -18rpx;
 | 
			
		||||
  margin-top: -18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container-multiple {
 | 
			
		||||
  margin-left: -16rpx;
 | 
			
		||||
  margin-top: -16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.resource-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.play-icon {
 | 
			
		||||
  width: 96rpx;
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.images-videos-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.image {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.cover-img-container {
 | 
			
		||||
  background-color: white;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['my-video', 'my-cover-img', 'my-play-icon'],
 | 
			
		||||
  properties: {
 | 
			
		||||
    videoSrc: { type: String },
 | 
			
		||||
  },
 | 
			
		||||
  data: {
 | 
			
		||||
    isShow: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true, // 在组件定义时的选项中启用多slot支持
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  attached() {
 | 
			
		||||
    this.videoContext = wx.createVideoContext('myVideo', this);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  fullScreen: false,
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 点击封面自定义播放按钮时触发
 | 
			
		||||
    bindplay(e) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShow: false,
 | 
			
		||||
      });
 | 
			
		||||
      this.videoContext.play();
 | 
			
		||||
      this.triggerEvent('play', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    bindplayByVideo(e) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        isShow: false,
 | 
			
		||||
      });
 | 
			
		||||
      this.triggerEvent('play', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 监听播放到末尾时触发
 | 
			
		||||
    bindended(e) {
 | 
			
		||||
      if (!this.fullScreen) {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          isShow: true,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      this.triggerEvent('ended', e);
 | 
			
		||||
    },
 | 
			
		||||
    // 监听暂停播放时触发
 | 
			
		||||
    bindpause(e) {
 | 
			
		||||
      this.triggerEvent('pause', e);
 | 
			
		||||
    },
 | 
			
		||||
    bindfullscreenchange(e) {
 | 
			
		||||
      const fullScreen = e?.detail?.fullScreen;
 | 
			
		||||
      this.fullScreen = fullScreen;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
<video
 | 
			
		||||
  id="myVideo"
 | 
			
		||||
  src="{{videoSrc}}"
 | 
			
		||||
  enable-danmu
 | 
			
		||||
  controls
 | 
			
		||||
  show-fullscreen-btn
 | 
			
		||||
  show-center-play-btn="{{false}}"
 | 
			
		||||
  auto-pause-if-navigate
 | 
			
		||||
  auto-pause-if-open-native
 | 
			
		||||
  show-play-btn
 | 
			
		||||
  object-fit="contain"
 | 
			
		||||
  bindpause="bindpause"
 | 
			
		||||
  bindended="bindended"
 | 
			
		||||
  bindplay="bindplayByVideo"
 | 
			
		||||
  class="video my-video"
 | 
			
		||||
  bindfullscreenchange="bindfullscreenchange"
 | 
			
		||||
>
 | 
			
		||||
  <view class="video_cover" wx:if="{{isShow}}">
 | 
			
		||||
    <view class="my-cover-img">
 | 
			
		||||
      <slot name="cover-img" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="video_play_icon my-play-icon" bindtap="bindplay">
 | 
			
		||||
      <slot name="play-icon" />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</video>
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
.video .video_cover {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video .video_play_icon {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50%;
 | 
			
		||||
  top: 50%;
 | 
			
		||||
  transform: translate(-50%, -50%);
 | 
			
		||||
  z-index: 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video .video_txt {
 | 
			
		||||
  margin: 10rpx auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.video {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,51 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['wr-class'],
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true,
 | 
			
		||||
  },
 | 
			
		||||
  properties: {
 | 
			
		||||
    goodsDetailInfo: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    sellerReply: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    userHeadUrl: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    userName: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentContent: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentScore: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    commentTime: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    commentResources: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    showMoreStatus: false,
 | 
			
		||||
    showContent: false,
 | 
			
		||||
    hideText: false,
 | 
			
		||||
    eleHeight: null,
 | 
			
		||||
    overText: false,
 | 
			
		||||
    isDisabled: true,
 | 
			
		||||
    startColors: ['#FFC51C', '#DDDDDD'],
 | 
			
		||||
  },
 | 
			
		||||
  methods: {},
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-rate": "tdesign-miniprogram/rate/rate",
 | 
			
		||||
    "images-videos": "./components/images-videos",
 | 
			
		||||
    "t-image": "/components/webp-image/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,27 @@
 | 
			
		||||
<view class="comments-card-item wr-class">
 | 
			
		||||
  <view class="comments-card-item-container">
 | 
			
		||||
    <view class="comments-title">
 | 
			
		||||
      <view class="comments-card-item-userImg">
 | 
			
		||||
        <t-image t-class="userImg" src="{{userHeadUrl}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="userName">{{userName}}</view>
 | 
			
		||||
      <text class="commentTime">{{commentTime}}</text>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-info">
 | 
			
		||||
      <view class="rate">
 | 
			
		||||
        <t-rate value="{{commentScore}}" size="14" gap="2" color="{{['#ffc51c', '#ddd']}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-info-text" wx:if="{{goodsDetailInfo}}">{{goodsDetailInfo}}</view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-item-container-content">
 | 
			
		||||
      <view class="content-text" hidden="{{showContent}}"> {{commentContent}} </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-item-container-image" wx:if="{{commentResources.length > 0}}">
 | 
			
		||||
      <images-videos resources="{{commentResources}}" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="comments-card-reply" wx:if="{{sellerReply}}">
 | 
			
		||||
      <text class="prefix">店家回复:</text>
 | 
			
		||||
      <text class="content">{{sellerReply}}</text>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
@@ -0,0 +1,172 @@
 | 
			
		||||
@import '../../../../../style/theme.wxss';
 | 
			
		||||
 | 
			
		||||
.comments-card-item {
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item::after {
 | 
			
		||||
  content: '';
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  bottom: 0rpx;
 | 
			
		||||
  width: 686rpx;
 | 
			
		||||
  height: 2rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-userImg {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-userImg .userImg {
 | 
			
		||||
  width: 64rpx;
 | 
			
		||||
  height: 64rpx;
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-name {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-name .userName {
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-date {
 | 
			
		||||
  font-size: 22rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  margin-top: 4rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content {
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .content-text {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .hide-text {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  -webkit-line-clamp: 5;
 | 
			
		||||
  text-align: justify;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-content .showMore {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 112rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  background: linear-gradient(
 | 
			
		||||
    to right,
 | 
			
		||||
    rgba(255, 255, 255, 0.2) 0,
 | 
			
		||||
    rgba(255, 255, 255, 0.45) 20%,
 | 
			
		||||
    rgba(255, 255, 255, 0.7) 25%,
 | 
			
		||||
    rgba(255, 255, 255, 0.9) 30%,
 | 
			
		||||
    rgba(255, 255, 255, 0.95) 35%,
 | 
			
		||||
    #ffffff 50%,
 | 
			
		||||
    #fff 100%
 | 
			
		||||
  );
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #fa550f;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  margin-top: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg3 {
 | 
			
		||||
  width: 196rpx;
 | 
			
		||||
  height: 196rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg2 {
 | 
			
		||||
  width: 300rpx;
 | 
			
		||||
  height: 300rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container-image .commentImg1 {
 | 
			
		||||
  width: 404rpx;
 | 
			
		||||
  height: 404rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-title .userName {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-title .commentTime {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 18rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info .rate {
 | 
			
		||||
  margin-right: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-info .goods-info-text {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
 | 
			
		||||
  color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  padding: 24rpx 16rpx;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply .prefix {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-card-item-container .comments-card-reply .content {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										86
									
								
								mini-program/pages/goods/comments/create/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								mini-program/pages/goods/comments/create/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// import { getCommentDetail } from '../../../../services/good/comments/fetchCommentDetail';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    serviceRateValue: 1,
 | 
			
		||||
    goodRateValue: 1,
 | 
			
		||||
    conveyRateValue: 1,
 | 
			
		||||
    isAnonymous: false,
 | 
			
		||||
    uploadFiles: [],
 | 
			
		||||
    gridConfig: {
 | 
			
		||||
      width: 218,
 | 
			
		||||
      height: 218,
 | 
			
		||||
      column: 3,
 | 
			
		||||
    },
 | 
			
		||||
    isAllowedSubmit: false,
 | 
			
		||||
    imgUrl: '',
 | 
			
		||||
    title: '',
 | 
			
		||||
    goodsDetail: '',
 | 
			
		||||
    imageProps: {
 | 
			
		||||
      mode: 'aspectFit',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      imgUrl: options.imgUrl,
 | 
			
		||||
      title: options.title,
 | 
			
		||||
      goodsDetail: options.specs,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onRateChange(e) {
 | 
			
		||||
    const { value } = e?.detail;
 | 
			
		||||
    const item = e?.currentTarget?.dataset?.item;
 | 
			
		||||
    this.setData({ [item]: value }, () => {
 | 
			
		||||
      this.updateButtonStatus();
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onAnonymousChange(e) {
 | 
			
		||||
    const status = !!e?.detail?.checked;
 | 
			
		||||
    this.setData({ isAnonymous: status });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleSuccess(e) {
 | 
			
		||||
    const { files } = e.detail;
 | 
			
		||||
 | 
			
		||||
    this.setData({
 | 
			
		||||
      uploadFiles: files,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleRemove(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { uploadFiles } = this.data;
 | 
			
		||||
    uploadFiles.splice(index, 1);
 | 
			
		||||
    this.setData({
 | 
			
		||||
      uploadFiles,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onTextAreaChange(e) {
 | 
			
		||||
    const value = e?.detail?.value;
 | 
			
		||||
    this.textAreaValue = value;
 | 
			
		||||
    this.updateButtonStatus();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  updateButtonStatus() {
 | 
			
		||||
    const { serviceRateValue, goodRateValue, conveyRateValue, isAllowedSubmit } = this.data;
 | 
			
		||||
    const { textAreaValue } = this;
 | 
			
		||||
    const temp = serviceRateValue && goodRateValue && conveyRateValue && textAreaValue;
 | 
			
		||||
    if (temp !== isAllowedSubmit) this.setData({ isAllowedSubmit: temp });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onSubmitBtnClick() {
 | 
			
		||||
    const { isAllowedSubmit } = this.data;
 | 
			
		||||
    if (!isAllowedSubmit) return;
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '评价提交成功',
 | 
			
		||||
      icon: 'check-circle',
 | 
			
		||||
    });
 | 
			
		||||
    wx.navigateBack();
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										13
									
								
								mini-program/pages/goods/comments/create/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								mini-program/pages/goods/comments/create/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "评价商品",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-image": "/components/webp-image/index",
 | 
			
		||||
    "t-rate": "tdesign-miniprogram/rate/rate",
 | 
			
		||||
    "t-textarea": "tdesign-miniprogram/textarea/textarea",
 | 
			
		||||
    "t-checkbox": "tdesign-miniprogram/checkbox/checkbox",
 | 
			
		||||
    "t-button": "tdesign-miniprogram/button/button",
 | 
			
		||||
    "t-upload": "tdesign-miniprogram/upload/upload",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										90
									
								
								mini-program/pages/goods/comments/create/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								mini-program/pages/goods/comments/create/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
<view class="page-container">
 | 
			
		||||
  <view class="comment-card">
 | 
			
		||||
    <view class="goods-info-container">
 | 
			
		||||
      <view class="goods-image-container">
 | 
			
		||||
        <t-image t-class="goods-image" src="{{imgUrl}}" />
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-title-container">
 | 
			
		||||
        <view class="goods-title">{{title}}</view>
 | 
			
		||||
        <view class="goods-detail">{{goodsDetail}}</view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="rate-container">
 | 
			
		||||
      <text class="rate-title">商品评价</text>
 | 
			
		||||
      <view class="rate">
 | 
			
		||||
        <t-rate
 | 
			
		||||
          value="{{goodRateValue}}"
 | 
			
		||||
          bind:change="onRateChange"
 | 
			
		||||
          size="26"
 | 
			
		||||
          gap="6"
 | 
			
		||||
          color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
          data-item="goodRateValue"
 | 
			
		||||
        />
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="textarea-container">
 | 
			
		||||
      <t-textarea
 | 
			
		||||
        t-class="textarea"
 | 
			
		||||
        maxlength="{{500}}"
 | 
			
		||||
        indicator
 | 
			
		||||
        placeholder="对商品满意吗?评论一下"
 | 
			
		||||
        bind:change="onTextAreaChange"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="upload-container">
 | 
			
		||||
      <t-upload
 | 
			
		||||
        media-type="{{['image','video']}}"
 | 
			
		||||
        files="{{uploadFiles}}"
 | 
			
		||||
        bind:remove="handleRemove"
 | 
			
		||||
        bind:success="handleSuccess"
 | 
			
		||||
        gridConfig="{{gridConfig}}"
 | 
			
		||||
        imageProps="{{imageProps}}"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
 | 
			
		||||
    <view class="anonymous-box">
 | 
			
		||||
      <t-checkbox bind:change="onAnonymousChange" checked="{{isAnonymous}}" color="#FA4126" />
 | 
			
		||||
      <view class="name">匿名评价</view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="comment-card convey-card">
 | 
			
		||||
  <view class="convey-comment-title">物流服务评价</view>
 | 
			
		||||
  <view class="rate-container">
 | 
			
		||||
    <text class="rate-title">物流评价</text>
 | 
			
		||||
    <view class="rate">
 | 
			
		||||
      <t-rate
 | 
			
		||||
        value="{{conveyRateValue}}"
 | 
			
		||||
        bind:change="onRateChange"
 | 
			
		||||
        variant="filled"
 | 
			
		||||
        size="26"
 | 
			
		||||
        gap="6"
 | 
			
		||||
        color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
        data-item="conveyRateValue"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="rate-container">
 | 
			
		||||
    <text class="rate-title">服务评价</text>
 | 
			
		||||
    <view class="rate">
 | 
			
		||||
      <t-rate
 | 
			
		||||
        value="{{serviceRateValue}}"
 | 
			
		||||
        bind:change="onRateChange"
 | 
			
		||||
        size="26"
 | 
			
		||||
        gap="6"
 | 
			
		||||
        color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
        data-item="serviceRateValue"
 | 
			
		||||
      />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="submit-button-container">
 | 
			
		||||
  <t-button
 | 
			
		||||
    content="提交"
 | 
			
		||||
    block
 | 
			
		||||
    shape="round"
 | 
			
		||||
    t-class="submit-button{{isAllowedSubmit ? '' : '-disabled'}}"
 | 
			
		||||
    bind:tap="onSubmitBtnClick"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										168
									
								
								mini-program/pages/goods/comments/create/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								mini-program/pages/goods/comments/create/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .comment-card {
 | 
			
		||||
  padding: 24rpx 32rpx 28rpx;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-image {
 | 
			
		||||
  width: 112rpx;
 | 
			
		||||
  height: 112rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-title-container {
 | 
			
		||||
  padding-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .goods-info-container .goods-detail {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .rate-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 22rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .rate-container .rate-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  margin-right: 12rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .textarea-container {
 | 
			
		||||
  margin-top: 22rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .textarea-container .textarea {
 | 
			
		||||
  height: 294rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  border-radius: 16rpx;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__bordered {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .anonymous-box {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding-top: 52rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .anonymous-box .name {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  padding-left: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox {
 | 
			
		||||
  padding: 0rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__content {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-card .convey-comment-title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.convey-card {
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 140rpx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.convey-card .rate-container .rate-title {
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-checkbox__icon-left {
 | 
			
		||||
  margin-right: 0rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container {
 | 
			
		||||
  padding: 12rpx 32rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  z-index: 99;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container .submit-button {
 | 
			
		||||
  --td-button-default-color: #fff;
 | 
			
		||||
  --td-button-default-bg-color: #fa4126;
 | 
			
		||||
  --td-button-default-border-color: #fa4126;
 | 
			
		||||
  --td-button-default-active-bg-color: #fa42269c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.submit-button-container .submit-button-disabled {
 | 
			
		||||
  --td-button-default-color: #fff;
 | 
			
		||||
  --td-button-default-bg-color: #ccc;
 | 
			
		||||
  --td-button-default-border-color: #ccc;
 | 
			
		||||
  --td-button-default-active-bg-color: rgba(204, 204, 204, 0.789);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .upload-container {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-upload__wrapper {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .submmit-bar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  z-index: 12;
 | 
			
		||||
  padding: 12rpx 32rpx;
 | 
			
		||||
  padding-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  height: 112rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .submmit-bar-button {
 | 
			
		||||
  border-radius: 48rpx !important;
 | 
			
		||||
  padding: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.page-container .t-upload__close-btn {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.4);
 | 
			
		||||
  border-bottom-left-radius: 8rpx;
 | 
			
		||||
  width: 36rpx;
 | 
			
		||||
  height: 36rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.upload-container .upload-addcontent-slot {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								mini-program/pages/goods/comments/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								mini-program/pages/goods/comments/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
import { fetchComments } from '../../../services/comments/fetchComments';
 | 
			
		||||
import { fetchCommentsCount } from '../../../services/comments/fetchCommentsCount';
 | 
			
		||||
import dayjs from 'dayjs';
 | 
			
		||||
const layoutMap = {
 | 
			
		||||
  0: 'vertical',
 | 
			
		||||
};
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    pageLoading: false,
 | 
			
		||||
    commentList: [],
 | 
			
		||||
    pageNum: 1,
 | 
			
		||||
    myPageNum: 1,
 | 
			
		||||
    pageSize: 10,
 | 
			
		||||
    total: 0,
 | 
			
		||||
    myTotal: 0,
 | 
			
		||||
    hasLoaded: false,
 | 
			
		||||
    layoutText: layoutMap[0],
 | 
			
		||||
    loadMoreStatus: 0,
 | 
			
		||||
    myLoadStatus: 0,
 | 
			
		||||
    spuId: '1060004',
 | 
			
		||||
    commentLevel: '',
 | 
			
		||||
    hasImage: '',
 | 
			
		||||
    commentType: '',
 | 
			
		||||
    totalCount: 0,
 | 
			
		||||
    countObj: {
 | 
			
		||||
      badCount: '0',
 | 
			
		||||
      commentCount: '0',
 | 
			
		||||
      goodCount: '0',
 | 
			
		||||
      middleCount: '0',
 | 
			
		||||
      hasImageCount: '0',
 | 
			
		||||
      uidCount: '0',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.getCount(options);
 | 
			
		||||
    this.getComments(options);
 | 
			
		||||
  },
 | 
			
		||||
  async getCount(options) {
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await fetchCommentsCount(
 | 
			
		||||
        {
 | 
			
		||||
          spuId: options.spuId,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          method: 'POST',
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      this.setData({
 | 
			
		||||
        countObj: result,
 | 
			
		||||
      });
 | 
			
		||||
      // const { data, code = '' } = result;
 | 
			
		||||
      // if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
      //     wx.setNavigationBarTitle({
 | 
			
		||||
      //     title: `全部评价(${data.commentCount})`,
 | 
			
		||||
      //     });
 | 
			
		||||
      //     this.setData({
 | 
			
		||||
      //     countObj: data,
 | 
			
		||||
      //     });
 | 
			
		||||
      // } else {
 | 
			
		||||
      //     wx.showToast({
 | 
			
		||||
      //     title: '查询失败,请稍候重试',
 | 
			
		||||
      //     });
 | 
			
		||||
      // }
 | 
			
		||||
    } catch (error) {}
 | 
			
		||||
  },
 | 
			
		||||
  generalQueryData(reset) {
 | 
			
		||||
    const { hasImage, pageNum, pageSize, spuId, commentLevel } = this.data;
 | 
			
		||||
    const params = {
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
      pageSize: 30,
 | 
			
		||||
      queryParameter: {
 | 
			
		||||
        spuId,
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    if (
 | 
			
		||||
      Number(commentLevel) === 3 ||
 | 
			
		||||
      Number(commentLevel) === 2 ||
 | 
			
		||||
      Number(commentLevel) === 1
 | 
			
		||||
    ) {
 | 
			
		||||
      params.queryParameter.commentLevel = Number(commentLevel);
 | 
			
		||||
    }
 | 
			
		||||
    if (hasImage && hasImage === '1') {
 | 
			
		||||
      params.queryParameter.hasImage = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      delete params.queryParameter.hasImage;
 | 
			
		||||
    }
 | 
			
		||||
    // 重置请求
 | 
			
		||||
    if (reset) return params;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...params,
 | 
			
		||||
      pageNum: pageNum + 1,
 | 
			
		||||
      pageSize,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  async init(reset = true) {
 | 
			
		||||
    const { loadMoreStatus, commentList = [] } = this.data;
 | 
			
		||||
    const params = this.generalQueryData(reset);
 | 
			
		||||
 | 
			
		||||
    // 在加载中或者无更多数据,直接返回
 | 
			
		||||
    if (loadMoreStatus !== 0) return;
 | 
			
		||||
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 1,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await fetchComments(params, {
 | 
			
		||||
        method: 'POST',
 | 
			
		||||
      });
 | 
			
		||||
      const code = 'SUCCESS';
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { pageList, totalCount = 0 } = data;
 | 
			
		||||
        pageList.forEach((item) => {
 | 
			
		||||
          // eslint-disable-next-line no-param-reassign
 | 
			
		||||
          item.commentTime = dayjs(Number(item.commentTime)).format(
 | 
			
		||||
            'YYYY/MM/DD HH:mm',
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (Number(totalCount) === 0 && reset) {
 | 
			
		||||
          this.setData({
 | 
			
		||||
            commentList: [],
 | 
			
		||||
            hasLoaded: true,
 | 
			
		||||
            total: totalCount,
 | 
			
		||||
            loadMoreStatus: 2,
 | 
			
		||||
          });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        const _commentList = reset ? pageList : commentList.concat(pageList);
 | 
			
		||||
        const _loadMoreStatus =
 | 
			
		||||
          _commentList.length === Number(totalCount) ? 2 : 0;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          commentList: _commentList,
 | 
			
		||||
          pageNum: params.pageNum || 1,
 | 
			
		||||
          totalCount: Number(totalCount),
 | 
			
		||||
          loadMoreStatus: _loadMoreStatus,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        wx.showToast({
 | 
			
		||||
          title: '查询失败,请稍候重试',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {}
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasLoaded: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
  getScoreArray(score) {
 | 
			
		||||
    var array = [];
 | 
			
		||||
    for (let i = 0; i < 5; i++) {
 | 
			
		||||
      if (i < score) {
 | 
			
		||||
        array.push(2);
 | 
			
		||||
      } else {
 | 
			
		||||
        array.push(0);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return array;
 | 
			
		||||
  },
 | 
			
		||||
  getComments(options) {
 | 
			
		||||
    const { commentLevel = -1, spuId, hasImage = '' } = options;
 | 
			
		||||
    if (commentLevel !== -1) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        commentLevel: commentLevel,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasImage: hasImage,
 | 
			
		||||
      commentType: hasImage ? '4' : '',
 | 
			
		||||
      spuId: spuId,
 | 
			
		||||
    });
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
  changeTag(e) {
 | 
			
		||||
    var { commenttype } = e.currentTarget.dataset;
 | 
			
		||||
    var { commentType } = this.data;
 | 
			
		||||
    if (commentType === commenttype) return;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 0,
 | 
			
		||||
      commentList: [],
 | 
			
		||||
      total: 0,
 | 
			
		||||
      myTotal: 0,
 | 
			
		||||
      myPageNum: 1,
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
    });
 | 
			
		||||
    if (commenttype === '' || commenttype === '5') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '',
 | 
			
		||||
        commentLevel: '',
 | 
			
		||||
      });
 | 
			
		||||
    } else if (commenttype === '4') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '1',
 | 
			
		||||
        commentLevel: '',
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        hasImage: '',
 | 
			
		||||
        commentLevel: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    if (commenttype === '5') {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        myLoadStatus: 1,
 | 
			
		||||
        commentType: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
      this.getMyCommentsList();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        myLoadStatus: 0,
 | 
			
		||||
        commentType: commenttype,
 | 
			
		||||
      });
 | 
			
		||||
      this.init(true);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    const { total = 0, commentList } = this.data;
 | 
			
		||||
    if (commentList.length === total) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loadMoreStatus: 2,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.init(false);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										8
									
								
								mini-program/pages/goods/comments/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mini-program/pages/goods/comments/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "全部评价",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-tag": "tdesign-miniprogram/tag/tag",
 | 
			
		||||
    "comments-card": "./components/comments-card/index",
 | 
			
		||||
    "t-load-more": "/components/load-more/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								mini-program/pages/goods/comments/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								mini-program/pages/goods/comments/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
<view class="comments-header">
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '' ? 'comments-header-active' : ''}}" data-commentType="" bindtap="changeTag">
 | 
			
		||||
		全部({{countObj.commentCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag
 | 
			
		||||
	  t-class="comments-header-tag {{commentType === '5' ? 'comments-header-active' : ''}}"
 | 
			
		||||
	  wx:if="{{countObj.uidCount !== '0'}}"
 | 
			
		||||
	  data-commentType="5"
 | 
			
		||||
	  bindtap="changeTag"
 | 
			
		||||
	>
 | 
			
		||||
		自己({{countObj.uidCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '4' ? 'comments-header-active' : ''}}" data-commentType="4" bindtap="changeTag">
 | 
			
		||||
		带图({{countObj.hasImageCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '3' ? 'comments-header-active' : ''}}" data-commentType="3" bindtap="changeTag">
 | 
			
		||||
		好评({{countObj.goodCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '2' ? 'comments-header-active' : ''}}" data-commentType="2" bindtap="changeTag">
 | 
			
		||||
		中评({{countObj.middleCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
	<t-tag t-class="comments-header-tag {{commentType === '1' ? 'comments-header-active' : ''}}" data-commentType="1" bindtap="changeTag">
 | 
			
		||||
		差评({{countObj.badCount}})
 | 
			
		||||
	</t-tag>
 | 
			
		||||
</view>
 | 
			
		||||
<view class="comments-card-list">
 | 
			
		||||
	<block wx:for="{{commentList}}" wx:key="index">
 | 
			
		||||
		<comments-card
 | 
			
		||||
		  commentScore="{{item.commentScore}}"
 | 
			
		||||
		  userName="{{item.userName}}"
 | 
			
		||||
		  commentResources="{{item.commentResources || []}}"
 | 
			
		||||
		  commentContent="{{item.commentContent}}"
 | 
			
		||||
		  isAnonymity="{{item.isAnonymity}}"
 | 
			
		||||
		  commentTime="{{item.commentTime}}"
 | 
			
		||||
		  isAutoComment="{{item.isAutoComment}}"
 | 
			
		||||
		  userHeadUrl="{{item.userHeadUrl}}"
 | 
			
		||||
		  specInfo="{{item.specInfo}}"
 | 
			
		||||
		  sellerReply="{{item.sellerReply || ''}}"
 | 
			
		||||
		  goodsDetailInfo="{{item.goodsDetailInfo || ''}}"
 | 
			
		||||
		/>
 | 
			
		||||
	</block>
 | 
			
		||||
	<t-load-more
 | 
			
		||||
	  t-class="no-more"
 | 
			
		||||
	  status="{{loadMoreStatus}}"
 | 
			
		||||
	  no-more-text="没有更多了"
 | 
			
		||||
	  color="#BBBBBB"
 | 
			
		||||
	  failedColor="#FA550F"
 | 
			
		||||
	/>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								mini-program/pages/goods/comments/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								mini-program/pages/goods/comments/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/* 层级定义
 | 
			
		||||
@z-index-0: 1;
 | 
			
		||||
@z-index-1: 100;
 | 
			
		||||
@z-index-2: 200;
 | 
			
		||||
@z-index-5: 500;
 | 
			
		||||
@z-index-component: 1000; // 通用组件级别
 | 
			
		||||
@z-index-dropdown: @z-index-component;
 | 
			
		||||
@z-index-sticky: @z-index-component + 20;
 | 
			
		||||
@z-index-fixed: @z-index-component + 30;
 | 
			
		||||
@z-index-modal-backdrop:@z-index-component + 40;
 | 
			
		||||
@z-index-modal:@z-index-component + 50;
 | 
			
		||||
@z-index-popover:@z-index-component + 60;
 | 
			
		||||
@z-index-tooltip:@z-index-component + 70;
 | 
			
		||||
*/
 | 
			
		||||
/* var() css变量适配*/
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #FFFFFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
  padding: 32rpx 32rpx 0rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  margin-top: -24rpx;
 | 
			
		||||
  margin-left: -24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header-tag {
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
  height: 56rpx !important;
 | 
			
		||||
  font-size: 24rpx !important;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  background-color: #F5F5F5 !important;
 | 
			
		||||
  border-radius: 8rpx !important;
 | 
			
		||||
  border: 1px solid #F5F5F5 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-header-active {
 | 
			
		||||
  background-color: #FFECE9 !important;
 | 
			
		||||
  color: #FA4126 !important;
 | 
			
		||||
  border: 1px solid #FA4126 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.no-more {
 | 
			
		||||
  padding-left: 20rpx;
 | 
			
		||||
  padding-right: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								mini-program/pages/goods/details/components/buy-bar/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								mini-program/pages/goods/details/components/buy-bar/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
Component({
 | 
			
		||||
  externalClasses: ['wr-sold-out', 'wr-class'],
 | 
			
		||||
 | 
			
		||||
  options: { multipleSlots: true },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    soldout: {
 | 
			
		||||
      // 商品是否下架
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    jumpArray: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
    },
 | 
			
		||||
    isStock: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: true,
 | 
			
		||||
    }, // 是否有库存
 | 
			
		||||
    isSlotButton: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    }, // 是否开启按钮插槽
 | 
			
		||||
    shopCartNum: {
 | 
			
		||||
      type: Number, // 购物车气泡数量
 | 
			
		||||
    },
 | 
			
		||||
    buttonType: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 0,
 | 
			
		||||
    },
 | 
			
		||||
    minDiscountPrice: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    minSalePrice: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    fillPrice: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    toAddCart() {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('toAddCart');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toBuyNow(e) {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('toBuyNow', e);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toNav(e) {
 | 
			
		||||
      const { url } = e.currentTarget.dataset;
 | 
			
		||||
      return this.triggerEvent('toNav', {
 | 
			
		||||
        e,
 | 
			
		||||
        url,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
    "component": true,
 | 
			
		||||
    "usingComponents": {
 | 
			
		||||
        "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
<view class="flex soldout flex-center wr-sold-out" wx:if="{{soldout ||  !isStock}}">
 | 
			
		||||
	{{soldout ? '商品已下架' : '商品已售馨'}}
 | 
			
		||||
</view>
 | 
			
		||||
<view class="footer-cont flex flex-between wr-class">
 | 
			
		||||
	<view class="flex flex-between bottom-operate-left" wx:if="{{jumpArray.length > 0}}">
 | 
			
		||||
		<view
 | 
			
		||||
		  wx:for="{{jumpArray}}"
 | 
			
		||||
		  wx:key="index"
 | 
			
		||||
		  class="icon-warp operate-wrap"
 | 
			
		||||
		  bindtap="toNav"
 | 
			
		||||
		  data-ele="foot_navigation"
 | 
			
		||||
		  data-index="{{index}}"
 | 
			
		||||
		  data-url="{{item.url}}"
 | 
			
		||||
		>
 | 
			
		||||
			<view>
 | 
			
		||||
				<text wx:if="{{shopCartNum > 0 && item.showCartNum}}" class="tag-cart-num">
 | 
			
		||||
					{{shopCartNum > 99 ? '99+' : shopCartNum}}
 | 
			
		||||
				</text>
 | 
			
		||||
				<t-icon prefix="wr" name="{{item.iconName}}" size="40rpx" />
 | 
			
		||||
				<view class="operate-text">{{item.title}}</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</view>
 | 
			
		||||
	<block wx:if="{{buttonType === 1}}">
 | 
			
		||||
		<view class="flex buy-buttons">
 | 
			
		||||
			<view class="bar-separately {{soldout || !isStock ? 'bar-addCart-disabled' : ''}}" bindtap="toAddCart">
 | 
			
		||||
				加入购物车
 | 
			
		||||
			</view>
 | 
			
		||||
			<view class="bar-buy {{soldout || !isStock ? 'bar-buyNow-disabled' : ''}}" bindtap="toBuyNow">
 | 
			
		||||
				立即购买
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
	</block>
 | 
			
		||||
	<block wx:if="{{isSlotButton}}">
 | 
			
		||||
		<slot name="buyButton" />
 | 
			
		||||
	</block>
 | 
			
		||||
</view>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										107
									
								
								mini-program/pages/goods/details/components/buy-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								mini-program/pages/goods/details/components/buy-bar/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
			
		||||
.footer-cont {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  padding: 16rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.icon-warp {
 | 
			
		||||
  width: 110rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.operate-wrap {
 | 
			
		||||
  position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-operate-left {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bottom-operate-left .icon-warp {
 | 
			
		||||
  width: 50%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.tag-cart-num {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 50rpx;
 | 
			
		||||
  right: auto;
 | 
			
		||||
  top: 6rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  line-height: 24rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  z-index: 99;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  min-width: 28rpx;
 | 
			
		||||
  border-radius: 14rpx;
 | 
			
		||||
  background-color: #fa550f !important;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  padding: 2rpx 6rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.operate-text {
 | 
			
		||||
  color: #666;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.soldout {
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  background: rgba(170, 170, 170, 1);
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.addCart-disabled,
 | 
			
		||||
.bar-addCart-disabled {
 | 
			
		||||
  background: rgba(221, 221, 221, 1) !important;
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.buyNow-disabled,
 | 
			
		||||
.bar-buyNow-disabled {
 | 
			
		||||
  background: rgba(198, 198, 198, 1) !important;
 | 
			
		||||
  color: #fff !important;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-separately,
 | 
			
		||||
.bar-buy {
 | 
			
		||||
  width: 254rpx;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-separately {
 | 
			
		||||
  background: #ffece9;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  border-radius: 40rpx 0 0 40rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.bar-buy {
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  border-radius: 0rpx 40rpx 40rpx 0rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  display: -webkit-flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-center {
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  -webkit-justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  -webkit-align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-between {
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  -webkit-justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,339 @@
 | 
			
		||||
/* eslint-disable no-param-reassign */
 | 
			
		||||
/* eslint-disable no-nested-ternary */
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true,
 | 
			
		||||
    addGlobalClass: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    src: {
 | 
			
		||||
      type: String,
 | 
			
		||||
    },
 | 
			
		||||
    title: String,
 | 
			
		||||
    show: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    limitBuyInfo: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '',
 | 
			
		||||
    },
 | 
			
		||||
    isStock: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: true,
 | 
			
		||||
    },
 | 
			
		||||
    limitMaxCount: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 999,
 | 
			
		||||
    },
 | 
			
		||||
    limitMinCount: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 1,
 | 
			
		||||
    },
 | 
			
		||||
    skuList: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
      observer(skuList) {
 | 
			
		||||
        if (skuList && skuList.length > 0) {
 | 
			
		||||
          if (this.initStatus) {
 | 
			
		||||
            this.initData();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    specList: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      value: [],
 | 
			
		||||
      observer(specList) {
 | 
			
		||||
        if (specList && specList.length > 0) {
 | 
			
		||||
          this.initData();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    outOperateStatus: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    hasAuth: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      value: false,
 | 
			
		||||
    },
 | 
			
		||||
    count: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      value: 1,
 | 
			
		||||
      observer(count) {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          buyNum: count,
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  initStatus: false,
 | 
			
		||||
  selectedSku: {},
 | 
			
		||||
  selectSpecObj: {},
 | 
			
		||||
 | 
			
		||||
  data: {
 | 
			
		||||
    buyNum: 1,
 | 
			
		||||
    isAllSelectedSku: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    initData() {
 | 
			
		||||
      const { skuList } = this.properties;
 | 
			
		||||
      const { specList } = this.properties;
 | 
			
		||||
      specList.forEach((item) => {
 | 
			
		||||
        if (item.specValueList.length > 0) {
 | 
			
		||||
          item.specValueList.forEach((subItem) => {
 | 
			
		||||
            const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList);
 | 
			
		||||
            subItem.hasStockObj = obj;
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      const selectedSku = {};
 | 
			
		||||
      specList.forEach((item) => {
 | 
			
		||||
        selectedSku[item.specId] = '';
 | 
			
		||||
      });
 | 
			
		||||
      this.setData({
 | 
			
		||||
        specList,
 | 
			
		||||
      });
 | 
			
		||||
      this.selectSpecObj = {};
 | 
			
		||||
      this.selectedSku = {};
 | 
			
		||||
      this.initStatus = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    checkSkuStockQuantity(specValueId, skuList) {
 | 
			
		||||
      let hasStock = false;
 | 
			
		||||
      const array = [];
 | 
			
		||||
      skuList.forEach((item) => {
 | 
			
		||||
        (item.specInfo || []).forEach((subItem) => {
 | 
			
		||||
          if (subItem.specValueId === specValueId && item.quantity > 0) {
 | 
			
		||||
            const subArray = [];
 | 
			
		||||
            (item.specInfo || []).forEach((specItem) => {
 | 
			
		||||
              subArray.push(specItem.specValueId);
 | 
			
		||||
            });
 | 
			
		||||
            array.push(subArray);
 | 
			
		||||
            hasStock = true;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      return {
 | 
			
		||||
        hasStock,
 | 
			
		||||
        specsArray: array,
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    chooseSpecValueId(specValueId, specId) {
 | 
			
		||||
      const { selectSpecObj } = this;
 | 
			
		||||
      const { skuList, specList } = this.properties;
 | 
			
		||||
      if (selectSpecObj[specId]) {
 | 
			
		||||
        selectSpecObj[specId] = [];
 | 
			
		||||
        this.selectSpecObj = selectSpecObj;
 | 
			
		||||
      } else {
 | 
			
		||||
        selectSpecObj[specId] = [];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const itemAllSpecArray = [];
 | 
			
		||||
      const itemUnSelectArray = [];
 | 
			
		||||
      const itemSelectArray = [];
 | 
			
		||||
      specList.forEach((item) => {
 | 
			
		||||
        if (item.specId === specId) {
 | 
			
		||||
          const subSpecValueItem = item.specValueList.find((subItem) => subItem.specValueId === specValueId);
 | 
			
		||||
          let specSelectStatus = false;
 | 
			
		||||
          item.specValueList.forEach((n) => {
 | 
			
		||||
            itemAllSpecArray.push(n.hasStockObj.specsArray);
 | 
			
		||||
            if (n.isSelected) {
 | 
			
		||||
              specSelectStatus = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (n.hasStockObj.hasStock) {
 | 
			
		||||
              itemSelectArray.push(n.specValueId);
 | 
			
		||||
            } else {
 | 
			
		||||
              itemUnSelectArray.push(n.specValueId);
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
          if (specSelectStatus) {
 | 
			
		||||
            selectSpecObj[specId] = this.flatten(subSpecValueItem?.hasStockObj.specsArray.concat(itemSelectArray));
 | 
			
		||||
          } else {
 | 
			
		||||
            const subSet = function (arr1, arr2) {
 | 
			
		||||
              const set2 = new Set(arr2);
 | 
			
		||||
              const subset = [];
 | 
			
		||||
              arr1.forEach((val) => {
 | 
			
		||||
                if (!set2.has(val)) {
 | 
			
		||||
                  subset.push(val);
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
              return subset;
 | 
			
		||||
            };
 | 
			
		||||
            selectSpecObj[specId] = subSet(this.flatten(itemAllSpecArray), this.flatten(itemUnSelectArray));
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          // 未点击规格的逻辑
 | 
			
		||||
          const itemSelectArray = [];
 | 
			
		||||
          let specSelectStatus = false;
 | 
			
		||||
          item.specValueList.map(
 | 
			
		||||
            // 找到有库存的规格数组
 | 
			
		||||
            (n) => {
 | 
			
		||||
              itemSelectArray.push(n.hasStockObj.specsArray);
 | 
			
		||||
              if (n.isSelected) {
 | 
			
		||||
                specSelectStatus = true;
 | 
			
		||||
              }
 | 
			
		||||
              n.hasStockObj.hasStock = true;
 | 
			
		||||
              return n;
 | 
			
		||||
            },
 | 
			
		||||
          );
 | 
			
		||||
          if (specSelectStatus) {
 | 
			
		||||
            selectSpecObj[item.specId] = this.flatten(itemSelectArray);
 | 
			
		||||
          } else {
 | 
			
		||||
            delete selectSpecObj[item.specId];
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        this.selectSpecObj = selectSpecObj;
 | 
			
		||||
      });
 | 
			
		||||
      const combatArray = Object.values(selectSpecObj);
 | 
			
		||||
      if (combatArray.length > 0) {
 | 
			
		||||
        const showArray = combatArray.reduce((x, y) => this.getIntersection(x, y));
 | 
			
		||||
        const lastResult = Array.from(new Set(showArray));
 | 
			
		||||
        specList.forEach((item) => {
 | 
			
		||||
          item.specValueList.forEach((subItem) => {
 | 
			
		||||
            if (lastResult.includes(subItem.specValueId)) {
 | 
			
		||||
              subItem.hasStockObj.hasStock = true;
 | 
			
		||||
            } else {
 | 
			
		||||
              subItem.hasStockObj.hasStock = false;
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        specList.forEach((item) => {
 | 
			
		||||
          if (item.specValueList.length > 0) {
 | 
			
		||||
            item.specValueList.forEach((subItem) => {
 | 
			
		||||
              const obj = this.checkSkuStockQuantity(subItem.specValueId, skuList);
 | 
			
		||||
              subItem.hasStockObj = obj;
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      this.setData({
 | 
			
		||||
        specList,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    flatten(input) {
 | 
			
		||||
      const stack = [...input];
 | 
			
		||||
      const res = [];
 | 
			
		||||
      while (stack.length) {
 | 
			
		||||
        const next = stack.pop();
 | 
			
		||||
        if (Array.isArray(next)) {
 | 
			
		||||
          stack.push(...next);
 | 
			
		||||
        } else {
 | 
			
		||||
          res.push(next);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return res.reverse();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getIntersection(array, nextArray) {
 | 
			
		||||
      return array.filter((item) => nextArray.includes(item));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toChooseItem(e) {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      const { id } = e.currentTarget.dataset;
 | 
			
		||||
      const specId = e.currentTarget.dataset.specid;
 | 
			
		||||
      const hasStock = e.currentTarget.dataset.hasstock;
 | 
			
		||||
      if (!hasStock) {
 | 
			
		||||
        Toast({
 | 
			
		||||
          context: this,
 | 
			
		||||
          selector: '#t-toast',
 | 
			
		||||
          message: '该规格已售罄',
 | 
			
		||||
          icon: '',
 | 
			
		||||
          duration: 1000,
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      let { selectedSku } = this;
 | 
			
		||||
      const { specList } = this.properties;
 | 
			
		||||
      selectedSku =
 | 
			
		||||
        selectedSku[specId] === id ? { ...this.selectedSku, [specId]: '' } : { ...this.selectedSku, [specId]: id };
 | 
			
		||||
      specList.forEach((item) => {
 | 
			
		||||
        item.specValueList.forEach((valuesItem) => {
 | 
			
		||||
          if (item.specId === specId) {
 | 
			
		||||
            valuesItem.isSelected = valuesItem.specValueId === selectedSku[specId];
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      this.chooseSpecValueId(id, specId);
 | 
			
		||||
      const isAllSelectedSku = this.isAllSelected(specList, selectedSku);
 | 
			
		||||
      if (!isAllSelectedSku) {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          selectSkuSellsPrice: 0,
 | 
			
		||||
          selectSkuImg: '',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      this.setData({
 | 
			
		||||
        specList,
 | 
			
		||||
        isAllSelectedSku,
 | 
			
		||||
      });
 | 
			
		||||
      this.selectedSku = selectedSku;
 | 
			
		||||
      this.triggerEvent('change', {
 | 
			
		||||
        specList,
 | 
			
		||||
        selectedSku,
 | 
			
		||||
        isAllSelectedSku,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 判断是否所有的sku都已经选中
 | 
			
		||||
    isAllSelected(skuTree, selectedSku) {
 | 
			
		||||
      const selected = Object.keys(selectedSku).filter((skuKeyStr) => selectedSku[skuKeyStr] !== '');
 | 
			
		||||
      return skuTree.length === selected.length;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handlePopupHide() {
 | 
			
		||||
      this.triggerEvent('closeSpecsPopup', {
 | 
			
		||||
        show: false,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    specsConfirm() {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('specsConfirm');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addCart() {
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('addCart');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    buyNow() {
 | 
			
		||||
      const { isAllSelectedSku } = this.data;
 | 
			
		||||
      const { isStock } = this.properties;
 | 
			
		||||
      if (!isStock) return;
 | 
			
		||||
      this.triggerEvent('buyNow', {
 | 
			
		||||
        isAllSelectedSku,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // 总处理
 | 
			
		||||
    setBuyNum(buyNum) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        buyNum,
 | 
			
		||||
      });
 | 
			
		||||
      this.triggerEvent('changeNum', {
 | 
			
		||||
        buyNum,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleBuyNumChange(e) {
 | 
			
		||||
      const { value } = e.detail;
 | 
			
		||||
      this.setData({
 | 
			
		||||
        buyNum: value,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "component": true,
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-popup": "tdesign-miniprogram/popup/popup",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-image": "/components/webp-image/index",
 | 
			
		||||
    "t-stepper": "tdesign-miniprogram/stepper/stepper",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,84 @@
 | 
			
		||||
<t-popup visible="{{show}}" placement="bottom" bind:visible-change="handlePopupHide">
 | 
			
		||||
  <view class="popup-container">
 | 
			
		||||
    <view class="popup-close" bindtap="handlePopupHide">
 | 
			
		||||
      <t-icon name="close" size="36rpx" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="popup-sku-header">
 | 
			
		||||
      <t-image t-class="popup-sku-header__img" src="{{src}}" />
 | 
			
		||||
      <view class="popup-sku-header__goods-info">
 | 
			
		||||
        <view class="popup-sku__goods-name">{{title}}</view>
 | 
			
		||||
        <view class="goods-price-container">
 | 
			
		||||
          <slot name="goods-price" />
 | 
			
		||||
        </view>
 | 
			
		||||
        <!-- 已选规格 -->
 | 
			
		||||
        <view class="popup-sku__selected-spec">
 | 
			
		||||
          <view>选择:</view>
 | 
			
		||||
          <view wx:for="{{specList}}" wx:key="specId">
 | 
			
		||||
            <view
 | 
			
		||||
              class="popup-sku__selected-item"
 | 
			
		||||
              wx:for="{{item.specValueList}}"
 | 
			
		||||
              wx:for-item="selectedItem"
 | 
			
		||||
              wx:if="{{selectedItem.isSelected}}"
 | 
			
		||||
              wx:key="specValueId"
 | 
			
		||||
            >
 | 
			
		||||
              {{selectedItem.specValue}}
 | 
			
		||||
            </view>
 | 
			
		||||
          </view>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="popup-sku-body">
 | 
			
		||||
      <view class="popup-sku-group-container">
 | 
			
		||||
        <view class="popup-sku-row" wx:for="{{specList}}" wx:key="specId">
 | 
			
		||||
          <view class="popup-sku-row__title">{{item.title}}</view>
 | 
			
		||||
          <block
 | 
			
		||||
            wx:for="{{item.specValueList}}"
 | 
			
		||||
            wx:for-item="valuesItem"
 | 
			
		||||
            wx:for-index="valuesIndex"
 | 
			
		||||
            wx:key="specValueId"
 | 
			
		||||
          >
 | 
			
		||||
            <view
 | 
			
		||||
              class="popup-sku-row__item {{valuesItem.isSelected ? 'popup-sku-row__item--active' : ''}} {{!valuesItem.hasStockObj.hasStock || !isStock ? 'disabled-sku-selected' : ''}}"
 | 
			
		||||
              data-specid="{{item.specId}}"
 | 
			
		||||
              data-id="{{valuesItem.specValueId}}"
 | 
			
		||||
              data-val="{{valuesItem.specValue}}"
 | 
			
		||||
              data-hasStock="{{valuesItem.hasStockObj.hasStock}}"
 | 
			
		||||
              bindtap="toChooseItem"
 | 
			
		||||
            >
 | 
			
		||||
              {{valuesItem.specValue}}
 | 
			
		||||
            </view>
 | 
			
		||||
          </block>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="popup-sku-stepper-stock">
 | 
			
		||||
        <view class="popup-sku-stepper-container">
 | 
			
		||||
          <view class="popup-sku__stepper-title">
 | 
			
		||||
            购买数量
 | 
			
		||||
            <view class="limit-text" wx:if="{{limitBuyInfo}}"> ({{limitBuyInfo}}) </view>
 | 
			
		||||
          </view>
 | 
			
		||||
          <t-stepper value="{{buyNum}}" min="{{1}}" max="{{2}}" theme="filled" bind:change="handleBuyNumChange" />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view wx:if="{{outOperateStatus}}" class="single-confirm-btn {{!isStock ? 'disabled' : ''}}" bindtap="specsConfirm">
 | 
			
		||||
      确定
 | 
			
		||||
    </view>
 | 
			
		||||
    <view
 | 
			
		||||
      class="popup-sku-actions flex flex-between {{!isStock ? 'popup-sku-disabled' : ''}}"
 | 
			
		||||
      wx:if="{{!outOperateStatus}}"
 | 
			
		||||
    >
 | 
			
		||||
      <view class="sku-operate">
 | 
			
		||||
        <view class="selected-sku-btn sku-operate-addCart {{!isStock ? 'disabled' : ''}}" bindtap="addCart">
 | 
			
		||||
          加入购物车
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="sku-operate">
 | 
			
		||||
        <view class="selected-sku-btn sku-operate-buyNow  {{!isStock ? 'disabled' : ''}}" bindtap="buyNow">
 | 
			
		||||
          立即购买
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <slot name="bottomSlot" />
 | 
			
		||||
  </view>
 | 
			
		||||
</t-popup>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
@@ -0,0 +1,300 @@
 | 
			
		||||
.popup-container {
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 100;
 | 
			
		||||
  border-radius: 16rpx 16rpx 0 0;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-container .popup-close {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 30rpx;
 | 
			
		||||
  top: 30rpx;
 | 
			
		||||
  z-index: 9;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  padding: 30rpx 28rpx 0 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__img {
 | 
			
		||||
  width: 176rpx;
 | 
			
		||||
  height: 176rpx;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  background: #d8d8d8;
 | 
			
		||||
  margin-right: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 500rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__goods-name {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-line-clamp: 2;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  width: 430rpx;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__selected-spec {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header
 | 
			
		||||
  .popup-sku-header__goods-info
 | 
			
		||||
  .popup-sku__selected-spec
 | 
			
		||||
  .popup-sku__selected-item {
 | 
			
		||||
  margin-right: 10rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body {
 | 
			
		||||
  margin: 0 30rpx 40rpx;
 | 
			
		||||
  max-height: 600rpx;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body .popup-sku-group-container .popup-sku-row {
 | 
			
		||||
  padding: 32rpx 0;
 | 
			
		||||
  border-bottom: 1rpx solid #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-group-container
 | 
			
		||||
  .popup-sku-row
 | 
			
		||||
  .popup-sku-row__title {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body .popup-sku-group-container .popup-sku-row .popup-sku-row__item {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  min-width: 128rpx;
 | 
			
		||||
  height: 56rpx;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  border: 2rpx solid #f5f5f5;
 | 
			
		||||
  margin: 19rpx 26rpx 0 0;
 | 
			
		||||
  padding: 0 16rpx;
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-group-container
 | 
			
		||||
  .popup-sku-row
 | 
			
		||||
  .popup-sku-row__item.popup-sku-row__item--active {
 | 
			
		||||
  border: 2rpx solid #fa4126;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  background: rgba(255, 95, 21, 0.04);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-group-container
 | 
			
		||||
  .popup-sku-row
 | 
			
		||||
  .disabled-sku-selected {
 | 
			
		||||
  background: #f5f5f5 !important;
 | 
			
		||||
  color: #cccccc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body .popup-sku-stepper-stock .popup-sku-stepper-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  margin: 40rpx 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-sku__stepper-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-sku__stepper-title
 | 
			
		||||
  .limit-text {
 | 
			
		||||
  margin-left: 10rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row nowrap;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  font-size: 28px;
 | 
			
		||||
  height: 48rpx;
 | 
			
		||||
  line-height: 62rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .input-btn,
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .input-num-wrap {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  background-color: #f5f5f5;
 | 
			
		||||
  border-radius: 4rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .input-num-wrap {
 | 
			
		||||
  color: #282828;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  max-width: 76rpx;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .input-num-wrap
 | 
			
		||||
  .input-num {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  width: auto;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .input-btn {
 | 
			
		||||
  width: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .popup-stepper__minus {
 | 
			
		||||
  margin-right: 4rpx;
 | 
			
		||||
  border-radius: 4rpx;
 | 
			
		||||
  color: #9a979b;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .popup-stepper__plus {
 | 
			
		||||
  margin-left: 4rpx;
 | 
			
		||||
  border-radius: 4rpx;
 | 
			
		||||
  color: #9a979b;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .popup-stepper__plus::after {
 | 
			
		||||
  width: 24rpx;
 | 
			
		||||
  height: 3rpx;
 | 
			
		||||
  background-color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-body
 | 
			
		||||
  .popup-sku-stepper-stock
 | 
			
		||||
  .popup-sku-stepper-container
 | 
			
		||||
  .popup-stepper
 | 
			
		||||
  .popup-stepper__plus::before {
 | 
			
		||||
  width: 3rpx;
 | 
			
		||||
  height: 24rpx;
 | 
			
		||||
  background-color: #999999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 80rpx;
 | 
			
		||||
  padding: 0 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate {
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  width: 50%;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  border-radius: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate .sku-operate-addCart {
 | 
			
		||||
  background-color: #ffece9;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  border-radius: 48rpx 0 0 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate .sku-operate-addCart.disabled {
 | 
			
		||||
  background: rgb(221, 221, 221);
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate .sku-operate-buyNow {
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
  border-radius: 0 48rpx 48rpx 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate .sku-operate-buyNow.disabled {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background: rgb(198, 198, 198);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-actions .sku-operate .selected-sku-btn {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-container .single-confirm-btn {
 | 
			
		||||
  border-radius: 48rpx;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  margin: 0 32rpx;
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  line-height: 88rpx;
 | 
			
		||||
  background-color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-container .single-confirm-btn.disabled {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: #dddddd;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
Component({
 | 
			
		||||
  options: {
 | 
			
		||||
    multipleSlots: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  properties: {
 | 
			
		||||
    list: Array,
 | 
			
		||||
    title: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      value: '促销说明',
 | 
			
		||||
    },
 | 
			
		||||
    show: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // data: {
 | 
			
		||||
  //   list: [],
 | 
			
		||||
  // },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    change(e) {
 | 
			
		||||
      const { index } = e.currentTarget.dataset;
 | 
			
		||||
      this.triggerEvent('promotionChange', {
 | 
			
		||||
        index,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    closePromotionPopup() {
 | 
			
		||||
      this.triggerEvent('closePromotionPopup', {
 | 
			
		||||
        show: false,
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "component": true,
 | 
			
		||||
    "usingComponents": {
 | 
			
		||||
        "t-popup": "tdesign-miniprogram/popup/popup",
 | 
			
		||||
        "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
<t-popup visible="{{show}}" placement="bottom" bind:visible-change="closePromotionPopup">
 | 
			
		||||
	<view class="promotion-popup-container">
 | 
			
		||||
		<view class="promotion-popup-close" bindtap="closePromotionPopup">
 | 
			
		||||
			<t-icon name="close" size="36rpx" />
 | 
			
		||||
		</view>
 | 
			
		||||
		<view class="promotion-popup-title">
 | 
			
		||||
			<view class="title">{{title}}</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<view class="promotion-popup-content">
 | 
			
		||||
			<view class="promotion-detail-list">
 | 
			
		||||
				<view
 | 
			
		||||
				  class="list-item"
 | 
			
		||||
				  wx:for="{{list}}"
 | 
			
		||||
				  wx:key="index"
 | 
			
		||||
				  bindtap="change"
 | 
			
		||||
				  data-index="{{index}}"
 | 
			
		||||
				>
 | 
			
		||||
					<view class="tag">{{item.tag}}</view>
 | 
			
		||||
					<view class="content">
 | 
			
		||||
						<text class="list-content">{{item.label ? item.label : ''}}</text>
 | 
			
		||||
					</view>
 | 
			
		||||
					<t-icon
 | 
			
		||||
					  class="collect-btn"
 | 
			
		||||
					  name="chevron-right"
 | 
			
		||||
					  size="40rpx"
 | 
			
		||||
					  color="#bbb"
 | 
			
		||||
					/>
 | 
			
		||||
				</view>
 | 
			
		||||
			</view>
 | 
			
		||||
		</view>
 | 
			
		||||
		<slot name="promotion-bottom" />
 | 
			
		||||
	</view>
 | 
			
		||||
</t-popup>
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,131 @@
 | 
			
		||||
.promotion-popup-container {
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  z-index: 100;
 | 
			
		||||
  border-radius: 16rpx 16rpx 0 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-close {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  right: 30rpx;
 | 
			
		||||
  top: 30rpx;
 | 
			
		||||
  z-index: 9;
 | 
			
		||||
  color: rgba(153, 153, 153, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-close .market {
 | 
			
		||||
  font-size: 25rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-title {
 | 
			
		||||
  height: 100rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-title {
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-content {
 | 
			
		||||
  min-height: 400rpx;
 | 
			
		||||
  max-height: 600rpx;
 | 
			
		||||
  padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container .promotion-popup-content .promotion-detail-list {
 | 
			
		||||
  margin: 0 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item:last-child {
 | 
			
		||||
  margin-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
  border-bottom: 0;
 | 
			
		||||
  padding-bottom: calc(28rpx + env(safe-area-inset-bottom));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  padding: 10rpx 0 28rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item
 | 
			
		||||
  .tag {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  padding: 2rpx 12rpx;
 | 
			
		||||
  background-color: #ffece9;
 | 
			
		||||
  margin-right: 16rpx;
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  border-radius: 54rpx;
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 2rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item
 | 
			
		||||
  .content {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item
 | 
			
		||||
  .content
 | 
			
		||||
  .list-content {
 | 
			
		||||
  width: 440rpx;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item
 | 
			
		||||
  .collect-btn {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  margin-left: 20rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.promotion-popup-container
 | 
			
		||||
  .promotion-popup-content
 | 
			
		||||
  .promotion-detail-list
 | 
			
		||||
  .list-item
 | 
			
		||||
  .collect-btn
 | 
			
		||||
  .linkText {
 | 
			
		||||
  margin-right: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										443
									
								
								mini-program/pages/goods/details/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										443
									
								
								mini-program/pages/goods/details/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,443 @@
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
import { fetchGood } from '../../../services/good/fetchGood';
 | 
			
		||||
import { fetchActivityList } from '../../../services/activity/fetchActivityList';
 | 
			
		||||
import {
 | 
			
		||||
  getGoodsDetailsCommentList,
 | 
			
		||||
  getGoodsDetailsCommentsCount,
 | 
			
		||||
} from '../../../services/good/fetchGoodsDetailsComments';
 | 
			
		||||
 | 
			
		||||
import { cdnBase } from '../../../config/index';
 | 
			
		||||
 | 
			
		||||
const imgPrefix = `${cdnBase}/`;
 | 
			
		||||
 | 
			
		||||
const recLeftImg = `${imgPrefix}common/rec-left.png`;
 | 
			
		||||
const recRightImg = `${imgPrefix}common/rec-right.png`;
 | 
			
		||||
const obj2Params = (obj = {}, encode = false) => {
 | 
			
		||||
  const result = [];
 | 
			
		||||
  Object.keys(obj).forEach((key) =>
 | 
			
		||||
    result.push(`${key}=${encode ? encodeURIComponent(obj[key]) : obj[key]}`),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  return result.join('&');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    commentsList: [],
 | 
			
		||||
    commentsStatistics: {
 | 
			
		||||
      badCount: 0,
 | 
			
		||||
      commentCount: 0,
 | 
			
		||||
      goodCount: 0,
 | 
			
		||||
      goodRate: 0,
 | 
			
		||||
      hasImageCount: 0,
 | 
			
		||||
      middleCount: 0,
 | 
			
		||||
    },
 | 
			
		||||
    isShowPromotionPop: false,
 | 
			
		||||
    activityList: [],
 | 
			
		||||
    recLeftImg,
 | 
			
		||||
    recRightImg,
 | 
			
		||||
    details: {},
 | 
			
		||||
    goodsTabArray: [
 | 
			
		||||
      {
 | 
			
		||||
        name: '商品',
 | 
			
		||||
        value: '', // 空字符串代表置顶
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        name: '详情',
 | 
			
		||||
        value: 'goods-page',
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    storeLogo: `${imgPrefix}common/store-logo.png`,
 | 
			
		||||
    storeName: '云mall标准版旗舰店',
 | 
			
		||||
    jumpArray: [
 | 
			
		||||
      {
 | 
			
		||||
        title: '首页',
 | 
			
		||||
        url: '/pages/home/home',
 | 
			
		||||
        iconName: 'home',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: '购物车',
 | 
			
		||||
        url: '/pages/cart/index',
 | 
			
		||||
        iconName: 'cart',
 | 
			
		||||
        showCartNum: true,
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    isStock: true,
 | 
			
		||||
    cartNum: 0,
 | 
			
		||||
    soldout: false,
 | 
			
		||||
    buttonType: 1,
 | 
			
		||||
    buyNum: 1,
 | 
			
		||||
    selectedAttrStr: '',
 | 
			
		||||
    skuArray: [],
 | 
			
		||||
    primaryImage: '',
 | 
			
		||||
    specImg: '',
 | 
			
		||||
    isSpuSelectPopupShow: false,
 | 
			
		||||
    isAllSelectedSku: false,
 | 
			
		||||
    buyType: 0,
 | 
			
		||||
    outOperateStatus: false, // 是否外层加入购物车
 | 
			
		||||
    operateType: 0,
 | 
			
		||||
    selectSkuSellsPrice: 0,
 | 
			
		||||
    maxLinePrice: 0,
 | 
			
		||||
    minSalePrice: 0,
 | 
			
		||||
    maxSalePrice: 0,
 | 
			
		||||
    list: [],
 | 
			
		||||
    spuId: '',
 | 
			
		||||
    navigation: { type: 'fraction' },
 | 
			
		||||
    current: 0,
 | 
			
		||||
    autoplay: true,
 | 
			
		||||
    duration: 500,
 | 
			
		||||
    interval: 5000,
 | 
			
		||||
    soldNum: 0, // 已售数量
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handlePopupHide() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      isSpuSelectPopupShow: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showSkuSelectPopup(type) {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      buyType: type || 0,
 | 
			
		||||
      outOperateStatus: type >= 1,
 | 
			
		||||
      isSpuSelectPopupShow: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  buyItNow() {
 | 
			
		||||
    this.showSkuSelectPopup(1);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  toAddCart() {
 | 
			
		||||
    this.showSkuSelectPopup(2);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  toNav(e) {
 | 
			
		||||
    const { url } = e.detail;
 | 
			
		||||
    wx.switchTab({
 | 
			
		||||
      url: url,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showCurImg(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { images } = this.data.details;
 | 
			
		||||
    wx.previewImage({
 | 
			
		||||
      current: images[index],
 | 
			
		||||
      urls: images, // 需要预览的图片http链接列表
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onPageScroll({ scrollTop }) {
 | 
			
		||||
    const goodsTab = this.selectComponent('#goodsTab');
 | 
			
		||||
    goodsTab && goodsTab.onScroll(scrollTop);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  chooseSpecItem(e) {
 | 
			
		||||
    const { specList } = this.data.details;
 | 
			
		||||
    const { selectedSku, isAllSelectedSku } = e.detail;
 | 
			
		||||
    if (!isAllSelectedSku) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        selectSkuSellsPrice: 0,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      isAllSelectedSku,
 | 
			
		||||
    });
 | 
			
		||||
    this.getSkuItem(specList, selectedSku);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getSkuItem(specList, selectedSku) {
 | 
			
		||||
    const { skuArray, primaryImage } = this.data;
 | 
			
		||||
    const selectedSkuValues = this.getSelectedSkuValues(specList, selectedSku);
 | 
			
		||||
    let selectedAttrStr = ` 件  `;
 | 
			
		||||
    selectedSkuValues.forEach((item) => {
 | 
			
		||||
      selectedAttrStr += `,${item.specValue}  `;
 | 
			
		||||
    });
 | 
			
		||||
    // eslint-disable-next-line array-callback-return
 | 
			
		||||
    const skuItem = skuArray.filter((item) => {
 | 
			
		||||
      let status = true;
 | 
			
		||||
      (item.specInfo || []).forEach((subItem) => {
 | 
			
		||||
        if (
 | 
			
		||||
          !selectedSku[subItem.specId] ||
 | 
			
		||||
          selectedSku[subItem.specId] !== subItem.specValueId
 | 
			
		||||
        ) {
 | 
			
		||||
          status = false;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      if (status) return item;
 | 
			
		||||
    });
 | 
			
		||||
    this.selectSpecsName(selectedSkuValues.length > 0 ? selectedAttrStr : '');
 | 
			
		||||
    if (skuItem) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        selectItem: skuItem,
 | 
			
		||||
        selectSkuSellsPrice: skuItem.price || 0,
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        selectItem: null,
 | 
			
		||||
        selectSkuSellsPrice: 0,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      specImg: skuItem && skuItem.skuImage ? skuItem.skuImage : primaryImage,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 获取已选择的sku名称
 | 
			
		||||
  getSelectedSkuValues(skuTree, selectedSku) {
 | 
			
		||||
    const normalizedTree = this.normalizeSkuTree(skuTree);
 | 
			
		||||
    return Object.keys(selectedSku).reduce((selectedValues, skuKeyStr) => {
 | 
			
		||||
      const skuValues = normalizedTree[skuKeyStr];
 | 
			
		||||
      const skuValueId = selectedSku[skuKeyStr];
 | 
			
		||||
      if (skuValueId !== '') {
 | 
			
		||||
        const skuValue = skuValues.filter((value) => {
 | 
			
		||||
          return value.specValueId === skuValueId;
 | 
			
		||||
        })[0];
 | 
			
		||||
        skuValue && selectedValues.push(skuValue);
 | 
			
		||||
      }
 | 
			
		||||
      return selectedValues;
 | 
			
		||||
    }, []);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  normalizeSkuTree(skuTree) {
 | 
			
		||||
    const normalizedTree = {};
 | 
			
		||||
    skuTree.forEach((treeItem) => {
 | 
			
		||||
      normalizedTree[treeItem.specId] = treeItem.specValueList;
 | 
			
		||||
    });
 | 
			
		||||
    return normalizedTree;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  selectSpecsName(selectSpecsName) {
 | 
			
		||||
    if (selectSpecsName) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        selectedAttrStr: selectSpecsName,
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        selectedAttrStr: '',
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  addCart() {
 | 
			
		||||
    const { isAllSelectedSku } = this.data;
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: isAllSelectedSku ? '点击加入购物车' : '请选择规格',
 | 
			
		||||
      icon: '',
 | 
			
		||||
      duration: 1000,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  gotoBuy(type) {
 | 
			
		||||
    const { isAllSelectedSku, buyNum } = this.data;
 | 
			
		||||
    if (!isAllSelectedSku) {
 | 
			
		||||
      Toast({
 | 
			
		||||
        context: this,
 | 
			
		||||
        selector: '#t-toast',
 | 
			
		||||
        message: '请选择规格',
 | 
			
		||||
        icon: '',
 | 
			
		||||
        duration: 1000,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.handlePopupHide();
 | 
			
		||||
    const query = {
 | 
			
		||||
      quantity: buyNum,
 | 
			
		||||
      storeId: '1',
 | 
			
		||||
      spuId: this.data.spuId,
 | 
			
		||||
      goodsName: this.data.details.title,
 | 
			
		||||
      skuId:
 | 
			
		||||
        type === 1 ? this.data.skuList[0].skuId : this.data.selectItem.skuId,
 | 
			
		||||
      available: this.data.details.available,
 | 
			
		||||
      price: this.data.details.minSalePrice,
 | 
			
		||||
      specInfo: this.data.details.specList?.map((item) => ({
 | 
			
		||||
        specTitle: item.title,
 | 
			
		||||
        specValue: item.specValueList[0].specValue,
 | 
			
		||||
      })),
 | 
			
		||||
      primaryImage: this.data.details.primaryImage,
 | 
			
		||||
      spuId: this.data.details.spuId,
 | 
			
		||||
      thumb: this.data.details.primaryImage,
 | 
			
		||||
      title: this.data.details.title,
 | 
			
		||||
    };
 | 
			
		||||
    let urlQueryStr = obj2Params({
 | 
			
		||||
      goodsRequestList: JSON.stringify([query]),
 | 
			
		||||
    });
 | 
			
		||||
    urlQueryStr = urlQueryStr ? `?${urlQueryStr}` : '';
 | 
			
		||||
    const path = `/pages/order/order-confirm/index${urlQueryStr}`;
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: path,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  specsConfirm() {
 | 
			
		||||
    const { buyType } = this.data;
 | 
			
		||||
    if (buyType === 1) {
 | 
			
		||||
      this.gotoBuy();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.addCart();
 | 
			
		||||
    }
 | 
			
		||||
    // this.handlePopupHide();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  changeNum(e) {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      buyNum: e.detail.buyNum,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  closePromotionPopup() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      isShowPromotionPop: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  promotionChange(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/promotion-detail/index?promotion_id=${index}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showPromotionPopup() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      isShowPromotionPop: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getDetail(spuId) {
 | 
			
		||||
    Promise.all([fetchGood(spuId), fetchActivityList()]).then((res) => {
 | 
			
		||||
      const [details, activityList] = res;
 | 
			
		||||
      const skuArray = [];
 | 
			
		||||
      const {
 | 
			
		||||
        skuList,
 | 
			
		||||
        primaryImage,
 | 
			
		||||
        isPutOnSale,
 | 
			
		||||
        minSalePrice,
 | 
			
		||||
        maxSalePrice,
 | 
			
		||||
        maxLinePrice,
 | 
			
		||||
        soldNum,
 | 
			
		||||
      } = details;
 | 
			
		||||
      skuList.forEach((item) => {
 | 
			
		||||
        skuArray.push({
 | 
			
		||||
          skuId: item.skuId,
 | 
			
		||||
          quantity: item.stockInfo ? item.stockInfo.stockQuantity : 0,
 | 
			
		||||
          specInfo: item.specInfo,
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      const promotionArray = [];
 | 
			
		||||
      activityList.forEach((item) => {
 | 
			
		||||
        promotionArray.push({
 | 
			
		||||
          tag: item.promotionSubCode === 'MYJ' ? '满减' : '满折',
 | 
			
		||||
          label: '满100元减99.9元',
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      this.setData({
 | 
			
		||||
        details,
 | 
			
		||||
        activityList,
 | 
			
		||||
        isStock: details.spuStockQuantity > 0,
 | 
			
		||||
        maxSalePrice: maxSalePrice ? parseInt(maxSalePrice) : 0,
 | 
			
		||||
        maxLinePrice: maxLinePrice ? parseInt(maxLinePrice) : 0,
 | 
			
		||||
        minSalePrice: minSalePrice ? parseInt(minSalePrice) : 0,
 | 
			
		||||
        list: promotionArray,
 | 
			
		||||
        skuArray: skuArray,
 | 
			
		||||
        primaryImage,
 | 
			
		||||
        soldout: isPutOnSale === 0,
 | 
			
		||||
        soldNum,
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  async getCommentsList() {
 | 
			
		||||
    try {
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      const data = await getGoodsDetailsCommentList();
 | 
			
		||||
      const { homePageComments } = data;
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const nextState = {
 | 
			
		||||
          commentsList: homePageComments.map((item) => {
 | 
			
		||||
            return {
 | 
			
		||||
              goodsSpu: item.spuId,
 | 
			
		||||
              userName: item.userName || '',
 | 
			
		||||
              commentScore: item.commentScore,
 | 
			
		||||
              commentContent: item.commentContent || '用户未填写评价',
 | 
			
		||||
              userHeadUrl: item.isAnonymity
 | 
			
		||||
                ? this.anonymityAvatar
 | 
			
		||||
                : item.userHeadUrl || this.anonymityAvatar,
 | 
			
		||||
            };
 | 
			
		||||
          }),
 | 
			
		||||
        };
 | 
			
		||||
        this.setData(nextState);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error('comments error:', error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onShareAppMessage() {
 | 
			
		||||
    // 自定义的返回信息
 | 
			
		||||
    const { selectedAttrStr } = this.data;
 | 
			
		||||
    let shareSubTitle = '';
 | 
			
		||||
    if (selectedAttrStr.indexOf('件') > -1) {
 | 
			
		||||
      const count = selectedAttrStr.indexOf('件');
 | 
			
		||||
      shareSubTitle = selectedAttrStr.slice(count + 1, selectedAttrStr.length);
 | 
			
		||||
    }
 | 
			
		||||
    const customInfo = {
 | 
			
		||||
      imageUrl: this.data.details.primaryImage,
 | 
			
		||||
      title: this.data.details.title + shareSubTitle,
 | 
			
		||||
      path: `/pages/goods/details/index?spuId=${this.data.spuId}`,
 | 
			
		||||
    };
 | 
			
		||||
    return customInfo;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /** 获取评价统计 */
 | 
			
		||||
  async getCommentsStatistics() {
 | 
			
		||||
    try {
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      const data = await getGoodsDetailsCommentsCount();
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const {
 | 
			
		||||
          badCount,
 | 
			
		||||
          commentCount,
 | 
			
		||||
          goodCount,
 | 
			
		||||
          goodRate,
 | 
			
		||||
          hasImageCount,
 | 
			
		||||
          middleCount,
 | 
			
		||||
        } = data;
 | 
			
		||||
        const nextState = {
 | 
			
		||||
          commentsStatistics: {
 | 
			
		||||
            badCount: parseInt(`${badCount}`),
 | 
			
		||||
            commentCount: parseInt(`${commentCount}`),
 | 
			
		||||
            goodCount: parseInt(`${goodCount}`),
 | 
			
		||||
            /** 后端返回百分比后数据但没有限制位数 */
 | 
			
		||||
            goodRate: Math.floor(goodRate * 10) / 10,
 | 
			
		||||
            hasImageCount: parseInt(`${hasImageCount}`),
 | 
			
		||||
            middleCount: parseInt(`${middleCount}`),
 | 
			
		||||
          },
 | 
			
		||||
        };
 | 
			
		||||
        this.setData(nextState);
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error('comments statiistics error:', error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  /** 跳转到评价列表 */
 | 
			
		||||
  navToCommentsListPage() {
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/goods/comments/index?spuId=${this.data.spuId}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad(query) {
 | 
			
		||||
    const { spuId } = query;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      spuId: spuId,
 | 
			
		||||
    });
 | 
			
		||||
    this.getDetail(spuId);
 | 
			
		||||
    this.getCommentsList(spuId);
 | 
			
		||||
    this.getCommentsStatistics(spuId);
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										18
									
								
								mini-program/pages/goods/details/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								mini-program/pages/goods/details/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "商品详情",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-image": "/components/webp-image/index",
 | 
			
		||||
    "t-tag": "tdesign-miniprogram/tag/tag",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "t-rate": "tdesign-miniprogram/rate/rate",
 | 
			
		||||
    "t-swiper": "tdesign-miniprogram/swiper/swiper",
 | 
			
		||||
    "t-swiper-nav": "tdesign-miniprogram/swiper-nav/swiper-nav",
 | 
			
		||||
    "t-button": "tdesign-miniprogram/button/button",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-popup": "tdesign-miniprogram/popup/popup",
 | 
			
		||||
    "price": "/components/price/index",
 | 
			
		||||
    "buy-bar": "./components/buy-bar/index",
 | 
			
		||||
    "promotion-popup": "./components/promotion-popup/index",
 | 
			
		||||
    "goods-specs-popup": "./components/goods-specs-popup/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								mini-program/pages/goods/details/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								mini-program/pages/goods/details/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
<view class="goods-detail-page">
 | 
			
		||||
  <view class="goods-head">
 | 
			
		||||
    <t-swiper
 | 
			
		||||
      wx:if="{{details.images.length > 0}}"
 | 
			
		||||
      height="750rpx"
 | 
			
		||||
      current="{{current}}"
 | 
			
		||||
      autoplay="{{autoplay}}"
 | 
			
		||||
      duration="{{duration}}"
 | 
			
		||||
      interval="{{interval}}"
 | 
			
		||||
      navigation="{{navigation}}"
 | 
			
		||||
      list="{{details.images}}"
 | 
			
		||||
    ></t-swiper>
 | 
			
		||||
    <view class="goods-info">
 | 
			
		||||
      <view class="goods-number">
 | 
			
		||||
        <view class="goods-price">
 | 
			
		||||
          <price
 | 
			
		||||
            wr-class="class-goods-price"
 | 
			
		||||
            symbol-class="class-goods-symbol"
 | 
			
		||||
            price="{{minSalePrice}}"
 | 
			
		||||
            type="lighter"
 | 
			
		||||
          />
 | 
			
		||||
          <view class="goods-price-up">起</view>
 | 
			
		||||
          <price wr-class="class-goods-del" price="{{maxLinePrice}}" type="delthrough" />
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="sold-num">已售{{soldNum}}</view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view wx:if="{{activityList.length > 0}}" class="goods-activity" bindtap="showPromotionPopup">
 | 
			
		||||
        <view class="tags-container">
 | 
			
		||||
          <view wx:for="{{activityList}}" data-promotionId="{{item.promotionId}}" wx:key="index" wx:if="{{index<4}}">
 | 
			
		||||
            <view class="goods-activity-tag">{{item.tag}}</view>
 | 
			
		||||
          </view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="activity-show">
 | 
			
		||||
          <view class="activity-show-text">领劵</view>
 | 
			
		||||
          <t-icon name="chevron-right" size="42rpx" />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-title">
 | 
			
		||||
        <view class="goods-name">{{details.title}}</view>
 | 
			
		||||
        <view class="goods-tag">
 | 
			
		||||
          <t-button open-type="share" t-class="shareBtn" variant="text">
 | 
			
		||||
            <view class="btn-icon">
 | 
			
		||||
              <t-icon name="share" size="40rpx" color="#000" />
 | 
			
		||||
              <view class="share-text">分享</view>
 | 
			
		||||
            </view>
 | 
			
		||||
          </t-button>
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="goods-intro">{{intro}}</view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="spu-select" bindtap="showSkuSelectPopup">
 | 
			
		||||
      <view class="label">已选</view>
 | 
			
		||||
      <view class="content">
 | 
			
		||||
        <view class="{{!selectedAttrStr ? 'tintColor' : ''}}">
 | 
			
		||||
          {{selectedAttrStr ? buyNum : ''}}{{selectedAttrStr || '请选择'}}
 | 
			
		||||
        </view>
 | 
			
		||||
        <t-icon name="chevron-right" size="40rpx" color="#BBBBBB" />
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view wx:if="{{ commentsStatistics.commentCount > 0 }}" class="comments-wrap">
 | 
			
		||||
      <view class="comments-head" bindtap="navToCommentsListPage">
 | 
			
		||||
        <view class="comments-title-wrap">
 | 
			
		||||
          <view class="comments-title-label">商品评价</view>
 | 
			
		||||
          <view class="comments-title-count"> ({{ commentsStatistics.commentCount }}) </view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="comments-rate-wrap">
 | 
			
		||||
          <view class="comments-good-rate">{{commentsStatistics.goodRate}}% 好评</view>
 | 
			
		||||
          <t-icon name="chevron-right" size="40rpx" color="#BBBBBB" />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="comment-item-wrap" wx:for="{{ commentsList }}" wx:for-item="commentItem" wx:key="goodsSpu">
 | 
			
		||||
        <view class="comment-item-head">
 | 
			
		||||
          <t-image src="{{commentItem.userHeadUrl}}" t-class="comment-item-avatar" />
 | 
			
		||||
          <view class="comment-head-right">
 | 
			
		||||
            <view class="comment-username">{{commentItem.userName}}</view>
 | 
			
		||||
            <t-rate
 | 
			
		||||
              value="{{ commentItem.commentScore }}"
 | 
			
		||||
              count="{{5}}"
 | 
			
		||||
              size="12"
 | 
			
		||||
              gap="2"
 | 
			
		||||
              color="{{['#ffc51c', '#ddd']}}"
 | 
			
		||||
            />
 | 
			
		||||
          </view>
 | 
			
		||||
        </view>
 | 
			
		||||
        <view class="comment-item-content"> {{commentItem.commentContent}} </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="desc-content">
 | 
			
		||||
    <view class="desc-content__title" wx:if="{{details.desc.length > 0}}">
 | 
			
		||||
      <t-image t-class="img" src="{{recLeftImg}}" />
 | 
			
		||||
      <span class="desc-content__title--text">详情介绍</span>
 | 
			
		||||
      <t-image t-class="img" src="{{recRightImg}}" />
 | 
			
		||||
    </view>
 | 
			
		||||
    <view wx:if="{{details.desc.length > 0}}" wx:for="{{details.desc}}" wx:key="index">
 | 
			
		||||
      <t-image t-class="desc-content__img" src="{{item}}" mode="widthFix" />
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="goods-bottom-operation">
 | 
			
		||||
    <buy-bar
 | 
			
		||||
      jumpArray="{{jumpArray}}"
 | 
			
		||||
      soldout="{{soldout}}"
 | 
			
		||||
      isStock="{{isStock}}"
 | 
			
		||||
      shopCartNum="{{cartNum}}"
 | 
			
		||||
      buttonType="{{buttonType}}"
 | 
			
		||||
      bind:toAddCart="toAddCart"
 | 
			
		||||
      bind:toNav="toNav"
 | 
			
		||||
      bind:toBuyNow="buyItNow"
 | 
			
		||||
      class="goods-details-card"
 | 
			
		||||
    />
 | 
			
		||||
  </view>
 | 
			
		||||
  <goods-specs-popup
 | 
			
		||||
    id="goodsSpecsPopup"
 | 
			
		||||
    show="{{isSpuSelectPopupShow}}"
 | 
			
		||||
    title="{{details.title || ''}}"
 | 
			
		||||
    src="{{specImg ? specImg : primaryImage}}"
 | 
			
		||||
    specList="{{details.specList || []}}"
 | 
			
		||||
    skuList="{{skuArray}}"
 | 
			
		||||
    limitBuyInfo="{{details.limitInfo[0].text || ''}}"
 | 
			
		||||
    bind:closeSpecsPopup="handlePopupHide"
 | 
			
		||||
    bind:change="chooseSpecItem"
 | 
			
		||||
    bind:changeNum="changeNum"
 | 
			
		||||
    bind:addCart="addCart"
 | 
			
		||||
    bind:buyNow="gotoBuy"
 | 
			
		||||
    bind:specsConfirm="specsConfirm"
 | 
			
		||||
    isStock="{{isStock}}"
 | 
			
		||||
    outOperateStatus="{{outOperateStatus}}"
 | 
			
		||||
  >
 | 
			
		||||
    <view slot="goods-price">
 | 
			
		||||
      <view class="popup-sku__price">
 | 
			
		||||
        <price
 | 
			
		||||
          wx:if="{{!isAllSelectedSku || (!promotionSubCode && isAllSelectedSku)}}"
 | 
			
		||||
          price="{{selectSkuSellsPrice ? selectSkuSellsPrice : minSalePrice }}"
 | 
			
		||||
          wr-class="popup-sku__price-num"
 | 
			
		||||
          symbol-class="popup-sku__price-symbol"
 | 
			
		||||
        />
 | 
			
		||||
        <price
 | 
			
		||||
          wx:if="{{selectSkuSellsPrice === 0 && minSalePrice !== maxSalePrice && !isAllSelectedSku}}"
 | 
			
		||||
          price="{{maxSalePrice}}"
 | 
			
		||||
          wr-class="popup-sku__price-del"
 | 
			
		||||
          type="delthrough"
 | 
			
		||||
        />
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </goods-specs-popup>
 | 
			
		||||
  <promotion-popup
 | 
			
		||||
    list="{{list}}"
 | 
			
		||||
    bind:closePromotionPopup="closePromotionPopup"
 | 
			
		||||
    show="{{isShowPromotionPop}}"
 | 
			
		||||
    bind:promotionChange="promotionChange"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										342
									
								
								mini-program/pages/goods/details/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										342
									
								
								mini-program/pages/goods/details/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,342 @@
 | 
			
		||||
@import '../../../style/global.wxss';
 | 
			
		||||
page {
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info {
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
  padding: 26rpx 0 28rpx 30rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .swipe-img {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 750rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-price {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-price-up {
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  bottom: 4rpx;
 | 
			
		||||
  left: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-price .class-goods-price {
 | 
			
		||||
  font-size: 64rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-family: DIN Alternate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-price .class-goods-symbol {
 | 
			
		||||
  font-size: 36rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-price .class-goods-del {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  left: 16rpx;
 | 
			
		||||
  bottom: 2rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-number {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-number .sold-num {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: flex-end;
 | 
			
		||||
  margin-right: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-activity {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  margin-top: 16rpx;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-activity .tags-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-activity .tags-container .goods-activity-tag {
 | 
			
		||||
  background: #ffece9;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  margin-right: 16rpx;
 | 
			
		||||
  padding: 4rpx 8rpx;
 | 
			
		||||
  border-radius: 4rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-activity .activity-show {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  padding-right: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-activity .activity-show-text {
 | 
			
		||||
  line-height: 42rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-name {
 | 
			
		||||
  width: 600rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  -webkit-line-clamp: 2;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-tag {
 | 
			
		||||
  width: 104rpx;
 | 
			
		||||
  margin-left: 26rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-tag .shareBtn {
 | 
			
		||||
  border-radius: 200rpx 0px 0px 200rpx;
 | 
			
		||||
  width: 100rpx;
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
  border: none;
 | 
			
		||||
  padding-right: 36rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-tag .shareBtn::after {
 | 
			
		||||
  border: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-tag .btn-icon {
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  height: 96rpx;
 | 
			
		||||
  color: #999;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-title .goods-tag .btn-icon .share-text {
 | 
			
		||||
  padding-top: 8rpx;
 | 
			
		||||
  font-size: 20rpx;
 | 
			
		||||
  line-height: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-info .goods-intro {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #888;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  word-break: break-all;
 | 
			
		||||
  padding-right: 30rpx;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  -webkit-line-clamp: 2;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  white-space: normal;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.spu-select {
 | 
			
		||||
  height: 80rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 30rpx;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.spu-select .label {
 | 
			
		||||
  margin-right: 30rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.spu-select .content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex: 1;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.spu-select .content .tintColor {
 | 
			
		||||
  color: #aaa;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .desc-content {
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  padding-bottom: 120rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .desc-content__title {
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 30rpx 20rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .desc-content__title .img {
 | 
			
		||||
  width: 206rpx;
 | 
			
		||||
  height: 10rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .desc-content__title--text {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  margin: 0 32rpx;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .desc-content__img {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-bottom-operation {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  padding-bottom: env(safe-area-inset-bottom);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__price {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: baseline;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  margin-top: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__price .popup-sku__price-num {
 | 
			
		||||
  font-size: 64rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  font-family: DIN Alternate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__price .popup-sku__price-del {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  left: 12rpx;
 | 
			
		||||
  bottom: 2rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__price .popup-sku__price-symbol {
 | 
			
		||||
  font-size: 36rpx;
 | 
			
		||||
  color: #fa4126;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.popup-sku-header .popup-sku-header__goods-info .popup-sku__price .popup-sku__price-max-num {
 | 
			
		||||
  font-size: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-detail-page .goods-head {
 | 
			
		||||
  --td-swiper-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-toast__content {
 | 
			
		||||
  z-index: 12000 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-wrap {
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-wrap .comments-head {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-wrap .comments-head .comments-title-wrap {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-title-label,
 | 
			
		||||
.comments-title-count {
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  font-size: 32rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  line-height: 48rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-rate-wrap {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comments-rate-wrap .comments-good-rate {
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-item-wrap .comment-item-head {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  margin-top: 32rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-item-wrap .comment-item-head .comment-item-avatar {
 | 
			
		||||
  width: 64rpx;
 | 
			
		||||
  height: 64rpx;
 | 
			
		||||
  border-radius: 64rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-item-wrap .comment-item-head .comment-head-right {
 | 
			
		||||
  margin-left: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-head-right .comment-username {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  line-height: 36rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.comment-item-wrap .comment-item-content {
 | 
			
		||||
  margin-top: 20rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  line-height: 40rpx;
 | 
			
		||||
  font-size: 28rpx;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										226
									
								
								mini-program/pages/goods/list/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								mini-program/pages/goods/list/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
			
		||||
import { fetchGoodsList } from '../../../services/good/fetchGoodsList';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
 | 
			
		||||
const initFilters = {
 | 
			
		||||
  overall: 1,
 | 
			
		||||
  sorts: '',
 | 
			
		||||
  layout: 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    goodsList: [],
 | 
			
		||||
    layout: 0,
 | 
			
		||||
    sorts: '',
 | 
			
		||||
    overall: 1,
 | 
			
		||||
    show: false,
 | 
			
		||||
    minVal: '',
 | 
			
		||||
    maxVal: '',
 | 
			
		||||
    filter: initFilters,
 | 
			
		||||
    hasLoaded: false,
 | 
			
		||||
    loadMoreStatus: 0,
 | 
			
		||||
    loading: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  pageNum: 1,
 | 
			
		||||
  pageSize: 30,
 | 
			
		||||
  total: 0,
 | 
			
		||||
 | 
			
		||||
  handleFilterChange(e) {
 | 
			
		||||
    const { layout, overall, sorts } = e.detail;
 | 
			
		||||
    this.pageNum = 1;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      layout,
 | 
			
		||||
      sorts,
 | 
			
		||||
      overall,
 | 
			
		||||
      loadMoreStatus: 0,
 | 
			
		||||
    });
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  generalQueryData(reset = false) {
 | 
			
		||||
    const { filter, keywords, minVal, maxVal } = this.data;
 | 
			
		||||
    const { pageNum, pageSize } = this;
 | 
			
		||||
    const { sorts, overall } = filter;
 | 
			
		||||
    const params = {
 | 
			
		||||
      sort: 0, // 0 综合,1 价格
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
      pageSize: 30,
 | 
			
		||||
      keyword: keywords,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (sorts) {
 | 
			
		||||
      params.sort = 1;
 | 
			
		||||
      params.sortType = sorts === 'desc' ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (overall) {
 | 
			
		||||
      params.sort = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
      params.sort = 1;
 | 
			
		||||
    }
 | 
			
		||||
    params.minPrice = minVal ? minVal * 100 : 0;
 | 
			
		||||
    params.maxPrice = maxVal ? maxVal * 100 : undefined;
 | 
			
		||||
    if (reset) return params;
 | 
			
		||||
    return {
 | 
			
		||||
      ...params,
 | 
			
		||||
      pageNum: pageNum + 1,
 | 
			
		||||
      pageSize,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  async init(reset = true) {
 | 
			
		||||
    const { loadMoreStatus, goodsList = [] } = this.data;
 | 
			
		||||
    const params = this.generalQueryData(reset);
 | 
			
		||||
    if (loadMoreStatus !== 0) return;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 1,
 | 
			
		||||
      loading: true,
 | 
			
		||||
    });
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await fetchGoodsList(params);
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      const data = result;
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { spuList, totalCount = 0 } = data;
 | 
			
		||||
        if (totalCount === 0 && reset) {
 | 
			
		||||
          this.total = totalCount;
 | 
			
		||||
          this.setData({
 | 
			
		||||
            emptyInfo: {
 | 
			
		||||
              tip: '抱歉,未找到相关商品',
 | 
			
		||||
            },
 | 
			
		||||
            hasLoaded: true,
 | 
			
		||||
            loadMoreStatus: 0,
 | 
			
		||||
            loading: false,
 | 
			
		||||
            goodsList: [],
 | 
			
		||||
          });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const _goodsList = reset ? spuList : goodsList.concat(spuList);
 | 
			
		||||
        const _loadMoreStatus = _goodsList.length === totalCount ? 2 : 0;
 | 
			
		||||
        this.pageNum = params.pageNum || 1;
 | 
			
		||||
        this.total = totalCount;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          goodsList: _goodsList,
 | 
			
		||||
          loadMoreStatus: _loadMoreStatus,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          loading: false,
 | 
			
		||||
        });
 | 
			
		||||
        wx.showToast({
 | 
			
		||||
          title: '查询失败,请稍候重试',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loading: false,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasLoaded: true,
 | 
			
		||||
      loading: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.init(true);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    const { goodsList } = this.data;
 | 
			
		||||
    const { total = 0 } = this;
 | 
			
		||||
    if (goodsList.length === total) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loadMoreStatus: 2,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.init(false);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleAddCart() {
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '点击加购',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  tagClickHandle() {
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '点击标签',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  gotoGoodsDetail(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { spuId } = this.data.goodsList[index];
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/goods/details/index?spuId=${spuId}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showFilterPopup() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      show: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showFilterPopupClose() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      show: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onMinValAction(e) {
 | 
			
		||||
    const { value } = e.detail;
 | 
			
		||||
    this.setData({ minVal: value });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onMaxValAction(e) {
 | 
			
		||||
    const { value } = e.detail;
 | 
			
		||||
    this.setData({ maxVal: value });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  reset() {
 | 
			
		||||
    this.setData({ minVal: '', maxVal: '' });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  confirm() {
 | 
			
		||||
    const { minVal, maxVal } = this.data;
 | 
			
		||||
    let message = '';
 | 
			
		||||
    if (minVal && !maxVal) {
 | 
			
		||||
      message = `价格最小是${minVal}`;
 | 
			
		||||
    } else if (!minVal && maxVal) {
 | 
			
		||||
      message = `价格范围是0-${minVal}`;
 | 
			
		||||
    } else if (minVal && maxVal && minVal <= maxVal) {
 | 
			
		||||
      message = `价格范围${minVal}-${this.data.maxVal}`;
 | 
			
		||||
    } else {
 | 
			
		||||
      message = '请输入正确范围';
 | 
			
		||||
    }
 | 
			
		||||
    if (message) {
 | 
			
		||||
      Toast({
 | 
			
		||||
        context: this,
 | 
			
		||||
        selector: '#t-toast',
 | 
			
		||||
        message,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.pageNum = 1;
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        show: false,
 | 
			
		||||
        minVal: '',
 | 
			
		||||
        goodsList: [],
 | 
			
		||||
        loadMoreStatus: 0,
 | 
			
		||||
        maxVal: '',
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        this.init();
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										12
									
								
								mini-program/pages/goods/list/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								mini-program/pages/goods/list/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "商品列表",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-input": "tdesign-miniprogram/input/input",
 | 
			
		||||
    "t-empty": "tdesign-miniprogram/empty/empty",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "goods-list": "/components/goods-list/index",
 | 
			
		||||
    "filter": "/components/filter/index",
 | 
			
		||||
    "filter-popup": "/components/filter-popup/index",
 | 
			
		||||
    "load-more": "/components/load-more/index"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								mini-program/pages/goods/list/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								mini-program/pages/goods/list/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
<view class="goods-list-container">
 | 
			
		||||
  <filter
 | 
			
		||||
    wr-class="filter-container"
 | 
			
		||||
    bind:change="handleFilterChange"
 | 
			
		||||
    layout="{{layout}}"
 | 
			
		||||
    sorts="{{sorts}}"
 | 
			
		||||
    overall="{{overall}}"
 | 
			
		||||
    bind:showFilterPopup="showFilterPopup"
 | 
			
		||||
  >
 | 
			
		||||
    <filter-popup
 | 
			
		||||
      slot="filterPopup"
 | 
			
		||||
      show="{{show}}"
 | 
			
		||||
      bind:showFilterPopupClose="showFilterPopupClose"
 | 
			
		||||
      bind:reset="reset"
 | 
			
		||||
      bind:confirm="confirm"
 | 
			
		||||
    >
 | 
			
		||||
      <view class="price-container" slot="filterSlot">
 | 
			
		||||
        <view class="price-between">价格区间</view>
 | 
			
		||||
        <view class="price-ipts-wrap">
 | 
			
		||||
          <t-input
 | 
			
		||||
            align="center"
 | 
			
		||||
            type="number"
 | 
			
		||||
            t-class="price-ipt"
 | 
			
		||||
            placeholder="最低价"
 | 
			
		||||
            value="{{minVal}}"
 | 
			
		||||
            bindchange="onMinValAction"
 | 
			
		||||
          />
 | 
			
		||||
          <view class="price-divided">-</view>
 | 
			
		||||
          <t-input
 | 
			
		||||
            align="center"
 | 
			
		||||
            type="number"
 | 
			
		||||
            t-class="price-ipt"
 | 
			
		||||
            placeholder="最高价"
 | 
			
		||||
            value="{{maxVal}}"
 | 
			
		||||
            bindchange="onMaxValAction"
 | 
			
		||||
          />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </filter-popup>
 | 
			
		||||
  </filter>
 | 
			
		||||
  <view class="empty-wrap" wx:if="{{goodsList.length === 0 && hasLoaded}}">
 | 
			
		||||
    <t-empty t-class="empty-tips" size="240rpx" description="暂无相关商品" />
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="category-goods-list" wx:if="{{goodsList.length}}">
 | 
			
		||||
    <goods-list
 | 
			
		||||
      wr-class="wr-goods-list"
 | 
			
		||||
      goodsList="{{goodsList}}"
 | 
			
		||||
      bind:click="gotoGoodsDetail"
 | 
			
		||||
      bind:addcart="handleAddCart"
 | 
			
		||||
    />
 | 
			
		||||
  </view>
 | 
			
		||||
  <load-more wx:if="{{goodsList.length > 0}}" status="{{loadMoreStatus}}" no-more-text="没有更多了" />
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										99
									
								
								mini-program/pages/goods/list/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								mini-program/pages/goods/list/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .t-search {
 | 
			
		||||
  padding: 0 30rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .t-class__input-container {
 | 
			
		||||
  height: 64rpx !important;
 | 
			
		||||
  border-radius: 32rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .t-search__left-icon {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .t-search__input {
 | 
			
		||||
  font-size: 28rpx !important;
 | 
			
		||||
  color: rgb(116, 116, 116) !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .category-goods-list {
 | 
			
		||||
  background-color: #f2f2f2;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
  padding: 20rpx 24rpx;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .wr-goods-list {
 | 
			
		||||
  background: #f2f2f2 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .t-image__mask {
 | 
			
		||||
  display: flex !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .empty-wrap {
 | 
			
		||||
  margin-top: 184rpx;
 | 
			
		||||
  margin-bottom: 120rpx;
 | 
			
		||||
  height: 300rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .empty-wrap .empty-tips .empty-content .content-text {
 | 
			
		||||
  margin-top: 40rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-container {
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  max-width: 632rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 30rpx 0 0 30rpx;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-between {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  color: rgba(51, 51, 51, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-ipts-wrap {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-around;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
 | 
			
		||||
  --td-input-bg-color: rgba(245, 245, 245, 1);
 | 
			
		||||
  --td-input-vertical-padding: 4rpx;
 | 
			
		||||
  --td-input-border-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-ipts-wrap .price-divided {
 | 
			
		||||
  width: 16rpx;
 | 
			
		||||
  margin: 0 24rpx;
 | 
			
		||||
  color: #333333;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-ipts-wrap .t-input__wrapper {
 | 
			
		||||
  margin: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-ipts-wrap .t-input__content,
 | 
			
		||||
.goods-list-container .price-ipts-wrap .t-input__placeholder {
 | 
			
		||||
  font-size: 24rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.goods-list-container .price-ipts-wrap .price-ipt {
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										262
									
								
								mini-program/pages/goods/result/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								mini-program/pages/goods/result/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
			
		||||
/* eslint-disable no-param-reassign */
 | 
			
		||||
import { getSearchResult } from '../../../services/good/fetchSearchResult';
 | 
			
		||||
import Toast from 'tdesign-miniprogram/toast/index';
 | 
			
		||||
 | 
			
		||||
const initFilters = {
 | 
			
		||||
  overall: 1,
 | 
			
		||||
  sorts: '',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    goodsList: [],
 | 
			
		||||
    sorts: '',
 | 
			
		||||
    overall: 1,
 | 
			
		||||
    show: false,
 | 
			
		||||
    minVal: '',
 | 
			
		||||
    maxVal: '',
 | 
			
		||||
    minSalePriceFocus: false,
 | 
			
		||||
    maxSalePriceFocus: false,
 | 
			
		||||
    filter: initFilters,
 | 
			
		||||
    hasLoaded: false,
 | 
			
		||||
    keywords: '',
 | 
			
		||||
    loadMoreStatus: 0,
 | 
			
		||||
    loading: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  total: 0,
 | 
			
		||||
  pageNum: 1,
 | 
			
		||||
  pageSize: 30,
 | 
			
		||||
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    const { searchValue = '' } = options || {};
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        keywords: searchValue,
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        this.init(true);
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  generalQueryData(reset = false) {
 | 
			
		||||
    const { filter, keywords, minVal, maxVal } = this.data;
 | 
			
		||||
    const { pageNum, pageSize } = this;
 | 
			
		||||
    const { sorts, overall } = filter;
 | 
			
		||||
    const params = {
 | 
			
		||||
      sort: 0, // 0 综合,1 价格
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
      pageSize: 30,
 | 
			
		||||
      keyword: keywords,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (sorts) {
 | 
			
		||||
      params.sort = 1;
 | 
			
		||||
      params.sortType = sorts === 'desc' ? 1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (overall) {
 | 
			
		||||
      params.sort = 0;
 | 
			
		||||
    } else {
 | 
			
		||||
      params.sort = 1;
 | 
			
		||||
    }
 | 
			
		||||
    params.minPrice = minVal ? minVal * 100 : 0;
 | 
			
		||||
    params.maxPrice = maxVal ? maxVal * 100 : undefined;
 | 
			
		||||
    if (reset) return params;
 | 
			
		||||
    return {
 | 
			
		||||
      ...params,
 | 
			
		||||
      pageNum: pageNum + 1,
 | 
			
		||||
      pageSize,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  async init(reset = true) {
 | 
			
		||||
    const { loadMoreStatus, goodsList = [] } = this.data;
 | 
			
		||||
    const params = this.generalQueryData(reset);
 | 
			
		||||
    if (loadMoreStatus !== 0) return;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      loadMoreStatus: 1,
 | 
			
		||||
      loading: true,
 | 
			
		||||
    });
 | 
			
		||||
    try {
 | 
			
		||||
      const result = await getSearchResult(params);
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      const data = result;
 | 
			
		||||
      if (code.toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { spuList, totalCount = 0 } = data;
 | 
			
		||||
        if (totalCount === 0 && reset) {
 | 
			
		||||
          this.total = totalCount;
 | 
			
		||||
          this.setData({
 | 
			
		||||
            emptyInfo: {
 | 
			
		||||
              tip: '抱歉,未找到相关商品',
 | 
			
		||||
            },
 | 
			
		||||
            hasLoaded: true,
 | 
			
		||||
            loadMoreStatus: 0,
 | 
			
		||||
            loading: false,
 | 
			
		||||
            goodsList: [],
 | 
			
		||||
          });
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const _goodsList = reset ? spuList : goodsList.concat(spuList);
 | 
			
		||||
        _goodsList.forEach((v) => {
 | 
			
		||||
          v.tags = v.spuTagList.map((u) => u.title);
 | 
			
		||||
          v.hideKey = { desc: true };
 | 
			
		||||
        });
 | 
			
		||||
        const _loadMoreStatus = _goodsList.length === totalCount ? 2 : 0;
 | 
			
		||||
        this.pageNum = params.pageNum || 1;
 | 
			
		||||
        this.total = totalCount;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          goodsList: _goodsList,
 | 
			
		||||
          loadMoreStatus: _loadMoreStatus,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        this.setData({
 | 
			
		||||
          loading: false,
 | 
			
		||||
        });
 | 
			
		||||
        wx.showToast({
 | 
			
		||||
          title: '查询失败,请稍候重试',
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loading: false,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.setData({
 | 
			
		||||
      hasLoaded: true,
 | 
			
		||||
      loading: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleCartTap() {
 | 
			
		||||
    wx.switchTab({
 | 
			
		||||
      url: '/pages/cart/index',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleSubmit() {
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        goodsList: [],
 | 
			
		||||
        loadMoreStatus: 0,
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        this.init(true);
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    const { goodsList } = this.data;
 | 
			
		||||
    const { total = 0 } = this;
 | 
			
		||||
    if (goodsList.length === total) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        loadMoreStatus: 2,
 | 
			
		||||
      });
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.init(false);
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleAddCart() {
 | 
			
		||||
    Toast({
 | 
			
		||||
      context: this,
 | 
			
		||||
      selector: '#t-toast',
 | 
			
		||||
      message: '点击加购',
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  gotoGoodsDetail(e) {
 | 
			
		||||
    const { index } = e.detail;
 | 
			
		||||
    const { spuId } = this.data.goodsList[index];
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/goods/details/index?spuId=${spuId}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleFilterChange(e) {
 | 
			
		||||
    const { overall, sorts } = e.detail;
 | 
			
		||||
    const { total } = this;
 | 
			
		||||
    const _filter = {
 | 
			
		||||
      sorts,
 | 
			
		||||
      overall,
 | 
			
		||||
    };
 | 
			
		||||
    this.setData({
 | 
			
		||||
      filter: _filter,
 | 
			
		||||
      sorts,
 | 
			
		||||
      overall,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.pageNum = 1;
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        goodsList: [],
 | 
			
		||||
        loadMoreStatus: 0,
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        total && this.init(true);
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showFilterPopup() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      show: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  showFilterPopupClose() {
 | 
			
		||||
    this.setData({
 | 
			
		||||
      show: false,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onMinValAction(e) {
 | 
			
		||||
    const { value } = e.detail;
 | 
			
		||||
    this.setData({ minVal: value });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onMaxValAction(e) {
 | 
			
		||||
    const { value } = e.detail;
 | 
			
		||||
    this.setData({ maxVal: value });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  reset() {
 | 
			
		||||
    this.setData({ minVal: '', maxVal: '' });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  confirm() {
 | 
			
		||||
    const { minVal, maxVal } = this.data;
 | 
			
		||||
    let message = '';
 | 
			
		||||
    if (minVal && !maxVal) {
 | 
			
		||||
      message = `价格最小是${minVal}`;
 | 
			
		||||
    } else if (!minVal && maxVal) {
 | 
			
		||||
      message = `价格范围是0-${minVal}`;
 | 
			
		||||
    } else if (minVal && maxVal && minVal <= maxVal) {
 | 
			
		||||
      message = `价格范围${minVal}-${this.data.maxVal}`;
 | 
			
		||||
    } else {
 | 
			
		||||
      message = '请输入正确范围';
 | 
			
		||||
    }
 | 
			
		||||
    if (message) {
 | 
			
		||||
      Toast({
 | 
			
		||||
        context: this,
 | 
			
		||||
        selector: '#t-toast',
 | 
			
		||||
        message,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    this.pageNum = 1;
 | 
			
		||||
    this.setData(
 | 
			
		||||
      {
 | 
			
		||||
        show: false,
 | 
			
		||||
        minVal: '',
 | 
			
		||||
        goodsList: [],
 | 
			
		||||
        loadMoreStatus: 0,
 | 
			
		||||
        maxVal: '',
 | 
			
		||||
      },
 | 
			
		||||
      () => {
 | 
			
		||||
        this.init();
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										15
									
								
								mini-program/pages/goods/result/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								mini-program/pages/goods/result/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "搜索",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-search": "tdesign-miniprogram/search/search",
 | 
			
		||||
    "t-input": "tdesign-miniprogram/input/input",
 | 
			
		||||
    "t-empty": "tdesign-miniprogram/empty/empty",
 | 
			
		||||
    "t-toast": "tdesign-miniprogram/toast/toast",
 | 
			
		||||
    "goods-list": "/components/goods-list/index",
 | 
			
		||||
    "filter": "/components/filter/index",
 | 
			
		||||
    "filter-popup": "/components/filter-popup/index",
 | 
			
		||||
    "load-more": "/components/load-more/index",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon"
 | 
			
		||||
  },
 | 
			
		||||
  "onReachBottomDistance": 50
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								mini-program/pages/goods/result/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								mini-program/pages/goods/result/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
<view class="result-container">
 | 
			
		||||
  <t-search
 | 
			
		||||
    t-class="t-search"
 | 
			
		||||
    t-class-input-container="t-class__input-container"
 | 
			
		||||
    t-class-left="t-search__left-icon"
 | 
			
		||||
    t-class-input="t-search__input"
 | 
			
		||||
    value="{{keywords}}"
 | 
			
		||||
    leftIcon=""
 | 
			
		||||
    placeholder="iPhone12pro"
 | 
			
		||||
    bind:submit="handleSubmit"
 | 
			
		||||
  >
 | 
			
		||||
    <t-icon slot="left-icon" prefix="wr" name="search" size="40rpx" color="#bbb" />
 | 
			
		||||
  </t-search>
 | 
			
		||||
  <filter
 | 
			
		||||
    wr-class="filter-container"
 | 
			
		||||
    bind:change="handleFilterChange"
 | 
			
		||||
    layout="{{layout}}"
 | 
			
		||||
    sorts="{{sorts}}"
 | 
			
		||||
    overall="{{overall}}"
 | 
			
		||||
    bind:showFilterPopup="showFilterPopup"
 | 
			
		||||
  >
 | 
			
		||||
    <filter-popup
 | 
			
		||||
      show="{{show}}"
 | 
			
		||||
      slot="filterPopup"
 | 
			
		||||
      bind:showFilterPopupClose="showFilterPopupClose"
 | 
			
		||||
      bind:reset="reset"
 | 
			
		||||
      bind:confirm="confirm"
 | 
			
		||||
    >
 | 
			
		||||
      <view class="price-container" slot="filterSlot">
 | 
			
		||||
        <view class="price-between">价格区间</view>
 | 
			
		||||
        <view class="price-ipts-wrap">
 | 
			
		||||
          <t-input
 | 
			
		||||
            type="number"
 | 
			
		||||
            t-class="price-ipt"
 | 
			
		||||
            t-class-input="t-class-input"
 | 
			
		||||
            placeholder="最低价"
 | 
			
		||||
            value="{{minVal}}"
 | 
			
		||||
            bindchange="onMinValAction"
 | 
			
		||||
          />
 | 
			
		||||
          <view class="price-divided">-</view>
 | 
			
		||||
          <t-input
 | 
			
		||||
            type="number"
 | 
			
		||||
            t-class="price-ipt"
 | 
			
		||||
            t-class-input="t-class-input"
 | 
			
		||||
            placeholder="最高价"
 | 
			
		||||
            value="{{maxVal}}"
 | 
			
		||||
            bindchange="onMaxValAction"
 | 
			
		||||
          />
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </filter-popup>
 | 
			
		||||
  </filter>
 | 
			
		||||
  <view class="empty-wrap" wx:if="{{goodsList.length === 0 && hasLoaded}}">
 | 
			
		||||
    <t-empty t-class="empty-tips" size="240rpx" description="暂无相关商品" />
 | 
			
		||||
  </view>
 | 
			
		||||
  <view class="category-goods-list" wx:if="{{goodsList.length}}">
 | 
			
		||||
    <goods-list
 | 
			
		||||
      wr-class="wr-goods-list"
 | 
			
		||||
      goodsList="{{goodsList}}"
 | 
			
		||||
      bind:click="gotoGoodsDetail"
 | 
			
		||||
      bind:addcart="handleAddCart"
 | 
			
		||||
    />
 | 
			
		||||
  </view>
 | 
			
		||||
  <load-more wx:if="{{goodsList.length > 0}}" status="{{loadMoreStatus}}" no-more-text="没有更多了" />
 | 
			
		||||
</view>
 | 
			
		||||
<t-toast id="t-toast" />
 | 
			
		||||
							
								
								
									
										114
									
								
								mini-program/pages/goods/result/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								mini-program/pages/goods/result/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
page {
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
page view {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-search {
 | 
			
		||||
  padding: 0 30rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-class__input-container {
 | 
			
		||||
  height: 64rpx !important;
 | 
			
		||||
  border-radius: 32rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-search__left-icon {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-search__input {
 | 
			
		||||
  font-size: 28rpx !important;
 | 
			
		||||
  color: #333 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .category-goods-list {
 | 
			
		||||
  background-color: #f2f2f2;
 | 
			
		||||
  overflow-y: scroll;
 | 
			
		||||
  padding: 20rpx 24rpx;
 | 
			
		||||
  -webkit-overflow-scrolling: touch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .wr-goods-list {
 | 
			
		||||
  background: #f2f2f2 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-image__mask {
 | 
			
		||||
  display: flex !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .empty-wrap {
 | 
			
		||||
  margin-top: 184rpx;
 | 
			
		||||
  margin-bottom: 120rpx;
 | 
			
		||||
  height: 300rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .empty-wrap .empty-tips .empty-content .content-text {
 | 
			
		||||
  margin-top: 40rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-container {
 | 
			
		||||
  padding: 32rpx;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  max-width: 632rpx;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  border-radius: 30rpx 0 0 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-between {
 | 
			
		||||
  font-size: 26rpx;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  color: rgba(51, 51, 51, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-ipts-wrap {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  justify-content: space-around;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-ipts-wrap .price-divided {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  width: 22rpx;
 | 
			
		||||
  margin: 0 20rpx;
 | 
			
		||||
  color: #222427;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-ipts-wrap .price-ipt {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  width: 246rpx;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  height: 56rpx;
 | 
			
		||||
  padding: 0 24rpx;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  border-radius: 8rpx;
 | 
			
		||||
  color: #333;
 | 
			
		||||
  background: rgba(245, 245, 245, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-class-input {
 | 
			
		||||
  font-size: 24rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.t-search__clear {
 | 
			
		||||
  font-size: 40rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .price-ipts-wrap .price-ipt::after {
 | 
			
		||||
  border: none !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.result-container .t-input__control {
 | 
			
		||||
  font-size: 24rpx !important;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								mini-program/pages/goods/search/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								mini-program/pages/goods/search/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
import {
 | 
			
		||||
  getSearchHistory,
 | 
			
		||||
  getSearchPopular,
 | 
			
		||||
} from '../../../services/good/fetchSearchHistory';
 | 
			
		||||
 | 
			
		||||
Page({
 | 
			
		||||
  data: {
 | 
			
		||||
    historyWords: [],
 | 
			
		||||
    popularWords: [],
 | 
			
		||||
    searchValue: '',
 | 
			
		||||
    dialog: {
 | 
			
		||||
      title: '确认删除当前历史记录',
 | 
			
		||||
      showCancelButton: true,
 | 
			
		||||
      message: '',
 | 
			
		||||
    },
 | 
			
		||||
    dialogShow: false,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  deleteType: 0,
 | 
			
		||||
  deleteIndex: '',
 | 
			
		||||
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.queryHistory();
 | 
			
		||||
    this.queryPopular();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  async queryHistory() {
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await getSearchHistory();
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      if (String(code).toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { historyWords = [] } = data;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          historyWords,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error(error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  async queryPopular() {
 | 
			
		||||
    try {
 | 
			
		||||
      const data = await getSearchPopular();
 | 
			
		||||
      const code = 'Success';
 | 
			
		||||
      if (String(code).toUpperCase() === 'SUCCESS') {
 | 
			
		||||
        const { popularWords = [] } = data;
 | 
			
		||||
        this.setData({
 | 
			
		||||
          popularWords,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
      console.error(error);
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  confirm() {
 | 
			
		||||
    const { historyWords } = this.data;
 | 
			
		||||
    const { deleteType, deleteIndex } = this;
 | 
			
		||||
    historyWords.splice(deleteIndex, 1);
 | 
			
		||||
    if (deleteType === 0) {
 | 
			
		||||
      this.setData({
 | 
			
		||||
        historyWords,
 | 
			
		||||
        dialogShow: false,
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      this.setData({ historyWords: [], dialogShow: false });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  close() {
 | 
			
		||||
    this.setData({ dialogShow: false });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleClearHistory() {
 | 
			
		||||
    const { dialog } = this.data;
 | 
			
		||||
    this.deleteType = 1;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      dialog: {
 | 
			
		||||
        ...dialog,
 | 
			
		||||
        message: '确认删除所有历史记录',
 | 
			
		||||
      },
 | 
			
		||||
      dialogShow: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  deleteCurr(e) {
 | 
			
		||||
    const { index } = e.currentTarget.dataset;
 | 
			
		||||
    const { dialog } = this.data;
 | 
			
		||||
    this.deleteIndex = index;
 | 
			
		||||
    this.setData({
 | 
			
		||||
      dialog: {
 | 
			
		||||
        ...dialog,
 | 
			
		||||
        message: '确认删除当前历史记录',
 | 
			
		||||
        deleteType: 0,
 | 
			
		||||
      },
 | 
			
		||||
      dialogShow: true,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleHistoryTap(e) {
 | 
			
		||||
    const { historyWords } = this.data;
 | 
			
		||||
    const { dataset } = e.currentTarget;
 | 
			
		||||
    const _searchValue = historyWords[dataset.index || 0] || '';
 | 
			
		||||
    if (_searchValue) {
 | 
			
		||||
      wx.navigateTo({
 | 
			
		||||
        url: `/pages/goods/result/index?searchValue=${_searchValue}`,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  handleSubmit(e) {
 | 
			
		||||
    const { value } = e.detail.value;
 | 
			
		||||
    if (value.length === 0) return;
 | 
			
		||||
    wx.navigateTo({
 | 
			
		||||
      url: `/pages/goods/result/index?searchValue=${value}`,
 | 
			
		||||
    });
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										8
									
								
								mini-program/pages/goods/search/index.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mini-program/pages/goods/search/index.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
{
 | 
			
		||||
  "navigationBarTitleText": "搜索",
 | 
			
		||||
  "usingComponents": {
 | 
			
		||||
    "t-search": "tdesign-miniprogram/search/search",
 | 
			
		||||
    "t-icon": "tdesign-miniprogram/icon/icon",
 | 
			
		||||
    "t-dialog": "tdesign-miniprogram/dialog/dialog"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								mini-program/pages/goods/search/index.wxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								mini-program/pages/goods/search/index.wxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
<view class="search-page">
 | 
			
		||||
  <t-search
 | 
			
		||||
    t-class-input-container="t-class__input-container"
 | 
			
		||||
    t-class-input="t-search__input"
 | 
			
		||||
    value="{{searchValue}}"
 | 
			
		||||
    leftIcon=""
 | 
			
		||||
    placeholder="iPhone12pro"
 | 
			
		||||
    bind:submit="handleSubmit"
 | 
			
		||||
    focus
 | 
			
		||||
  >
 | 
			
		||||
    <t-icon slot="left-icon" prefix="wr" name="search" size="40rpx" color="#bbb" />
 | 
			
		||||
  </t-search>
 | 
			
		||||
  <view class="search-wrap">
 | 
			
		||||
    <view class="history-wrap">
 | 
			
		||||
      <view class="search-header">
 | 
			
		||||
        <text class="search-title">历史搜索</text>
 | 
			
		||||
        <text class="search-clear" bind:tap="handleClearHistory">清除</text>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="search-content">
 | 
			
		||||
        <view
 | 
			
		||||
          class="search-item"
 | 
			
		||||
          hover-class="hover-history-item"
 | 
			
		||||
          wx:for="{{historyWords}}"
 | 
			
		||||
          bind:tap="handleHistoryTap"
 | 
			
		||||
          bindlongpress="deleteCurr"
 | 
			
		||||
          data-index="{{index}}"
 | 
			
		||||
          wx:key="*this"
 | 
			
		||||
        >
 | 
			
		||||
          {{item}}
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
    <view class="popular-wrap">
 | 
			
		||||
      <view class="search-header">
 | 
			
		||||
        <text class="search-title">热门搜索</text>
 | 
			
		||||
      </view>
 | 
			
		||||
      <view class="search-content">
 | 
			
		||||
        <view
 | 
			
		||||
          class="search-item"
 | 
			
		||||
          hover-class="hover-history-item"
 | 
			
		||||
          wx:for="{{popularWords}}"
 | 
			
		||||
          bind:tap="handleHistoryTap"
 | 
			
		||||
          data-index="{{index}}"
 | 
			
		||||
          wx:key="*this"
 | 
			
		||||
        >
 | 
			
		||||
          {{item}}
 | 
			
		||||
        </view>
 | 
			
		||||
      </view>
 | 
			
		||||
    </view>
 | 
			
		||||
  </view>
 | 
			
		||||
  <t-dialog
 | 
			
		||||
    visible="{{dialogShow}}"
 | 
			
		||||
    content="{{dialog.message}}"
 | 
			
		||||
    bindconfirm="confirm"
 | 
			
		||||
    bind:close="close"
 | 
			
		||||
    confirm-btn="确定"
 | 
			
		||||
    cancel-btn="{{dialog.showCancelButton ? '取消' : null}}"
 | 
			
		||||
    t-class-confirm="dialog__button-confirm"
 | 
			
		||||
    t-class-cancel="dialog__button-cancel"
 | 
			
		||||
  />
 | 
			
		||||
</view>
 | 
			
		||||
							
								
								
									
										79
									
								
								mini-program/pages/goods/search/index.wxss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								mini-program/pages/goods/search/index.wxss
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
.search-page {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  padding: 0 30rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .t-class__input-container {
 | 
			
		||||
  height: 64rpx !important;
 | 
			
		||||
  border-radius: 32rpx !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .t-search__input {
 | 
			
		||||
  font-size: 28rpx !important;
 | 
			
		||||
  color: #333 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-wrap {
 | 
			
		||||
  margin-top: 44rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .history-wrap {
 | 
			
		||||
  margin-bottom: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row nowrap;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-title {
 | 
			
		||||
  font-size: 30rpx;
 | 
			
		||||
  font-family: PingFangSC-Semibold, PingFang SC;
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  color: rgba(51, 51, 51, 1);
 | 
			
		||||
  line-height: 42rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-clear {
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  font-family: PingFang SC;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  color: #999999;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-content {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-flow: row wrap;
 | 
			
		||||
  justify-content: flex-start;
 | 
			
		||||
  align-items: flex-start;
 | 
			
		||||
  margin-top: 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .search-item {
 | 
			
		||||
  color: #333333;
 | 
			
		||||
  font-size: 24rpx;
 | 
			
		||||
  line-height: 32rpx;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
  margin-right: 24rpx;
 | 
			
		||||
  margin-bottom: 24rpx;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
  border-radius: 38rpx;
 | 
			
		||||
  padding: 12rpx 24rpx;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-page .hover-history-item {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  top: 3rpx;
 | 
			
		||||
  left: 3rpx;
 | 
			
		||||
  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.1) inset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.add-notes__confirm {
 | 
			
		||||
  color: #fa4126 !important;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user