Browse Source

商品列表

skyblued 3 years ago
parent
commit
961f884043

+ 8 - 0
src/router/routes-common.ts

@@ -91,6 +91,14 @@ export const router = [
     }
   },
   {
+    path: '/goodsList',
+    name: 'goodsList',
+    component: () => import('@/views/shop-mall/goods-list/index'),
+    meta: {
+      title: '商品列表'
+    }
+  },
+  {
     path: '/goodsDetail',
     name: 'goodsDetail',
     component: () => import('@/views/shop-mall/goods-detail'),

+ 15 - 0
src/views/shop-mall/components/tab-list/index.tsx

@@ -9,9 +9,20 @@ import styles from './index.module.less'
 export default defineComponent({
   name: 'tab-list',
   props: {
+    // 商品分类ID
     typeId: {
       type: Number,
       default: 0
+    },
+    // 商品类型ID
+    productAttributeCategoryId: {
+      type: Number,
+      default: 0
+    },
+    // 品牌 ID
+    brandId: {
+      type: Number,
+      default: 0
     }
   },
   data() {
@@ -22,6 +33,8 @@ export default defineComponent({
       finished: false,
       params: {
         productCategoryId: null as any,
+        productAttributeCategoryId: null as any,
+        brandId: null as any,
         pageNum: 1,
         pageSize: 20
       },
@@ -45,6 +58,8 @@ export default defineComponent({
       try {
         let params = this.params
         this.typeId && (params.productCategoryId = this.typeId)
+        this.productAttributeCategoryId && (params.productAttributeCategoryId = this.productAttributeCategoryId)
+        this.brandId && (params.brandId = this.brandId)
         const res = await request.post('/api-mall-portal/product/search', {
           data: {
             ...params

+ 37 - 0
src/views/shop-mall/goods-list/index.module.less

@@ -0,0 +1,37 @@
+.filter-top {
+  height: 37px;
+  font-size: 14px;
+  color: #666666;
+  transition: color cubic-bezier(0.075, 0.82, 0.165, 1);
+  background: #ffffff;
+  :global {
+    .van-col {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  .active {
+    color: #333333;
+    font-weight: 500;
+  }
+  .filterBtn {
+    color: #333333;
+  }
+}
+.filterTagWrap {
+  display: flex;
+  padding: 8px 0 0 14px;
+  flex-wrap: wrap;
+}
+.filterTag {
+  border: 1px solid var(--van-primary);
+  color: var(--van-primary);
+  border-radius: 12px;
+  font-size: 12px;
+  background-color: #f7f8f9;
+  padding: 4px 10px;
+  margin-right: 8px;
+  margin-bottom: 8px;
+  font-weight: 500;
+}

+ 88 - 0
src/views/shop-mall/goods-list/index.tsx

@@ -0,0 +1,88 @@
+import { Popup, Col, Row, Icon, Tag, Sticky } from 'vant'
+import { defineComponent } from 'vue'
+import TabList from '../components/tab-list'
+import styles from './index.module.less'
+import iconFilter from '@/common/images/icon_filter.png'
+import GoodsFilterList from '../modal/goods-filter-list'
+import ColSearch from '@/components/col-search'
+export default defineComponent({
+  name: 'goods-list',
+  data() {
+    return {
+      typeId: 0,
+      filterActive: 0,
+      filterListShow: false
+    }
+  },
+  methods: {
+    onFilter(n: number) {
+      this.filterActive = n
+    },
+    onFilterClick(params: any) {
+      console.log(params)
+    }
+  },
+  render() {
+    const typeId = this.typeId
+    return (
+      <div>
+        <Sticky>
+          <ColSearch />
+          <Row class={styles['filter-top']} align="center">
+            <Col
+              span={6}
+              class={this.filterActive == 0 ? styles.active : ''}
+              onClick={() => this.onFilter(0)}
+            >
+              综合排序
+            </Col>
+            <Col
+              span={6}
+              class={this.filterActive == 1 ? styles.active : ''}
+              onClick={() => this.onFilter(1)}
+            >
+              价格
+            </Col>
+            <Col
+              span={6}
+              class={this.filterActive == 2 ? styles.active : ''}
+              onClick={() => this.onFilter(2)}
+            >
+              销量
+            </Col>
+            <Col
+              span={6}
+              class={styles.filterBtn}
+              onClick={() => (this.filterListShow = true)}
+            >
+              筛选
+              <Icon name={iconFilter} size={18} />
+            </Col>
+          </Row>
+        </Sticky>
+
+        <div class={styles.filterTagWrap}>
+          {[1, 2, 3].map(item => (
+            <Tag class={styles.filterTag} closeable={true}>
+              铜管乐器{item}
+            </Tag>
+          ))}
+        </div>
+
+        <TabList typeId={typeId} />
+
+        <Popup
+          show={this.filterListShow}
+          closeable
+          position="bottom"
+          round
+          onClose={() => {
+            this.filterListShow = false
+          }}
+        >
+          <GoodsFilterList onFilterClick={this.onFilterClick} />
+        </Popup>
+      </div>
+    )
+  }
+})

+ 75 - 0
src/views/shop-mall/modal/goods-filter-list/index.module.less

@@ -0,0 +1,75 @@
+.loading {
+  height: 30px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.titlePopup {
+  padding: 18px;
+  text-align: center;
+  color: #000;
+  font-weight: 500;
+  font-size: 18px;
+}
+
+.title {
+  color: #333333;
+  font-size: 14px;
+  line-height: 20px;
+  padding-left: 16px;
+  font-weight: 500;
+}
+
+.radio-group {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 14px;
+}
+
+.radio {
+  margin-right: 10px;
+  margin-bottom: 8px;
+  :global {
+    .van-radio__icon {
+      display: none;
+    }
+    .van-tag {
+      box-sizing: border-box;
+      font-size: 14px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      border-radius: 16px;
+      padding: 6px 12px;
+      border: 1px solid transparent;
+      height: 32px;
+      line-height: 32px;
+      min-width: 80px;
+    }
+    .van-tag--default {
+      color: #999999;
+    }
+    .van-tag--primary {
+      background-color: #f7f8f9;
+      border: 1px solid var(--van-primary);
+      color: var(--van-primary);
+    }
+    .van-radio__label {
+      margin-left: 0;
+    }
+  }
+}
+
+.filterAction {
+  padding: 11px 16px;
+  display: flex;
+  align-items: center;
+  :global {
+    .van-button {
+      flex: 1;
+      height: 42px;
+      line-height: 42px;
+    }
+  }
+}

+ 137 - 0
src/views/shop-mall/modal/goods-filter-list/index.tsx

@@ -0,0 +1,137 @@
+import request from '@/helpers/request'
+import {
+  Loading,
+  Tag,
+  Cell,
+  RadioGroup,
+  Radio,
+  Divider,
+  Row,
+  Col,
+  Button
+} from 'vant'
+import { defineComponent } from 'vue'
+import styles from './index.module.less'
+const init = () => {
+  return {
+    productCategorySmallVoList: 0,
+    productAttributeCategoryList: 0,
+    brandList: 0
+  }
+}
+export default defineComponent({
+  name: 'goods-filter-list',
+  props: {
+    onFilterClick: {
+      type: Function,
+      default: (item: any) => {}
+    }
+  },
+  data() {
+    return {
+      dataShow: true, // 判断是否有数据
+      loading: false,
+      brandList: [],
+      productAttributeCategoryList: [],
+      productCategorySmallVoList: [],
+      params: init()
+    }
+  },
+  mounted() {
+    this.getFilterList()
+  },
+  methods: {
+    async getFilterList() {
+      this.loading = true
+      try {
+        const res = await request.get(
+          '/api-mall-portal/product/search/condition'
+        )
+        this.dataShow = res.code === 200
+        const {
+          brandList = [],
+          productAttributeCategoryList = [],
+          productCategorySmallVoList = []
+        } = res.data || {}
+
+        this.brandList = brandList
+        this.productAttributeCategoryList = productAttributeCategoryList
+        this.productCategorySmallVoList = productCategorySmallVoList
+      } catch {
+        this.dataShow = false
+      }
+      this.loading = false
+    }
+  },
+  render() {
+    return (
+      <div>
+        {this.loading && (
+          <div class={styles.loading}>
+            <Loading color="var(--van-primary)" />
+          </div>
+        )}
+        <div class={styles.filterWrap}>
+          <div class={styles.titlePopup}>筛选</div>
+          {Object.keys(this.params).map((key: string) => (
+            <Cell
+              border={false}
+              v-slots={{
+                title: () => (
+                  <div>
+                    {key === 'productCategorySmallVoList'
+                      ? '商品分类'
+                      : key === 'brandList'
+                      ? '品牌'
+                      : '商品类型'}
+                  </div>
+                ),
+                label: () => (
+                  <RadioGroup
+                    class={styles['radio-group']}
+                    modelValue={this.params[key]}
+                    onUpdate:modelValue={val => (this.params[key] = val)}
+                  >
+                    {this[key].map((item: any) => {
+                      const isActive = item.id === this.params[key]
+                      const type = isActive ? 'primary' : 'default'
+                      return (
+                        <Radio
+                          class={styles.radio}
+                          name={item.id}
+                          onClick={() => {}}
+                        >
+                          <Tag size="large" type={type}>
+                            {item.name}
+                          </Tag>
+                        </Radio>
+                      )
+                    })}
+                  </RadioGroup>
+                )
+              }}
+            />
+          ))}
+          <Divider style={{ margin: '0' }} />
+          <div class={styles.filterAction}>
+            <Button
+              round
+              style={{ marginRight: '8px' }}
+              onClick={() => (this.params = init())}
+            >
+              重置
+            </Button>
+            <Button
+              round
+              type="primary"
+              style={{ marginLeft: '8px' }}
+              onClick={() => this.onFilterClick(this.params)}
+            >
+              确认
+            </Button>
+          </div>
+        </div>
+      </div>
+    )
+  }
+})