├── .eslintrc.js
├── .github
├── ISSUE_TEMPLATE
│ ├── bug-report.zh-CN.yml
│ └── feature-report.zh-CN.yml
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
└── workflows
│ ├── issue-help-wanted.temp.yml
│ ├── issue-mark-duplicate.temp.yml
│ ├── issue-reply.temp.yml
│ ├── issue-stale-close.temp.yml
│ ├── issue-synchronize.temp.yml
│ ├── pr-spelling.template.yml
│ └── typos-config.toml
├── .gitignore
├── .husky
├── commit-msg
├── pre-commit
└── prepare-commit-msg
├── .npmrc
├── .prettierignore
├── .prettierrc.yml
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── app.js
├── app.json
├── app.wxss
├── commitlint.config.js
├── common
└── updateManager.js
├── components
├── filter-popup
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── filter
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── goods-card
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── goods-list
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── load-more
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── loading-content
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── price
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── swipeout
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
└── webp-image
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ ├── index.wxss
│ └── utils.wxs
├── config
├── eslintCheck.js
└── index.js
├── custom-tab-bar
├── data.js
├── index.js
├── index.json
├── index.wxml
└── index.wxss
├── ext.json
├── jsconfig.json
├── mock.md
├── model
├── activities.js
├── activity.js
├── address.js
├── cart.js
├── category.js
├── comments.js
├── comments
│ └── queryDetail.js
├── coupon.js
├── detailsComments.js
├── good.js
├── goods.js
├── order
│ ├── applyService.js
│ ├── orderConfirm.js
│ ├── orderDetail.js
│ └── orderList.js
├── promotion.js
├── search.js
├── submitComment.js
├── swiper.js
└── usercenter.js
├── package.json
├── pages
├── cart
│ ├── components
│ │ ├── cart-bar
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── cart-empty
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── cart-group
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ ├── index.wxs
│ │ │ ├── index.wxss
│ │ │ └── utils.wxs
│ │ ├── goods-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ └── specs-popup
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── coupon
│ ├── components
│ │ ├── coupon-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── floating-button
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ └── ui-coupon-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ ├── coupon-activity-goods
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── coupon-detail
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── coupon-list
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── goods
│ ├── category
│ │ ├── components
│ │ │ └── goods-category
│ │ │ │ ├── components
│ │ │ │ ├── c-sidebar
│ │ │ │ │ ├── README.md
│ │ │ │ │ ├── c-sidebar-item
│ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ ├── index.json
│ │ │ │ │ │ ├── index.wxml
│ │ │ │ │ │ └── index.wxss
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.json
│ │ │ │ │ ├── index.wxml
│ │ │ │ │ └── index.wxss
│ │ │ │ └── c-tabbar
│ │ │ │ │ ├── c-tabbar-more
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.json
│ │ │ │ │ ├── index.wxml
│ │ │ │ │ └── index.wxss
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.json
│ │ │ │ │ ├── index.wxml
│ │ │ │ │ └── index.wxss
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── comments
│ │ ├── components
│ │ │ └── comments-card
│ │ │ │ ├── components
│ │ │ │ ├── images-videos
│ │ │ │ │ ├── assets
│ │ │ │ │ │ └── play.png
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.json
│ │ │ │ │ ├── index.wxml
│ │ │ │ │ └── index.wxss
│ │ │ │ └── my-video
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── index.json
│ │ │ │ │ ├── index.wxml
│ │ │ │ │ └── index.wxss
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ ├── create
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── details
│ │ ├── components
│ │ │ ├── buy-bar
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ │ ├── goods-specs-popup
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ │ └── promotion-popup
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── list
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── result
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── search
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── home
│ ├── home.js
│ ├── home.json
│ ├── home.wxml
│ ├── home.wxss
│ └── readme
├── order
│ ├── after-service-detail
│ │ ├── api.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── after-service-list
│ │ ├── api.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── apply-service
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── components
│ │ ├── after-service-button-bar
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── customer-service
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── goods-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── noGoods
│ │ │ ├── noGood.wxs
│ │ │ ├── noGoods.js
│ │ │ ├── noGoods.json
│ │ │ ├── noGoods.wxml
│ │ │ └── noGoods.wxss
│ │ ├── order-button-bar
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── order-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ ├── order-goods-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ └── index.wxml
│ │ ├── reason-sheet
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ ├── index.wxss
│ │ │ └── reasonSheet.js
│ │ ├── selectCoupons
│ │ │ ├── mock.js
│ │ │ ├── selectCoupon.wxs
│ │ │ ├── selectCoupons.js
│ │ │ ├── selectCoupons.json
│ │ │ ├── selectCoupons.wxml
│ │ │ └── selectCoupons.wxss
│ │ └── specs-goods-card
│ │ │ ├── index.js
│ │ │ ├── index.json
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ ├── config.js
│ ├── delivery-detail
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── fill-tracking-no
│ │ ├── api.js
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── invoice
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── order-confirm
│ │ ├── components
│ │ │ └── address-card
│ │ │ │ ├── index.js
│ │ │ │ ├── index.json
│ │ │ │ ├── index.wxml
│ │ │ │ └── index.wxss
│ │ ├── getNotes.wxs
│ │ ├── handleInvoice.wxs
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ ├── order.wxs
│ │ └── pay.js
│ ├── order-detail
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── order-list
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── pay-result
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── receipt
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
├── promotion-detail
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
└── usercenter
│ ├── address
│ ├── edit
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── util.js
│ └── list
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── util.js
│ ├── components
│ ├── order-group
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── t-location
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── ui-address-item
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── ui-select-picker
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ └── user-center-card
│ │ ├── index.js
│ │ ├── index.json
│ │ ├── index.wxml
│ │ └── index.wxss
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ ├── index.wxss
│ ├── name-edit
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
│ └── person-info
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── project.config.json
├── services
├── _utils
│ ├── delay.js
│ └── timeout.js
├── activity
│ ├── fetchActivity.js
│ └── fetchActivityList.js
├── address
│ └── fetchAddress.js
├── cart
│ └── cart.js
├── comments
│ ├── fetchComments.js
│ └── fetchCommentsCount.js
├── coupon
│ └── index.js
├── good
│ ├── comments
│ │ └── fetchCommentDetail.js
│ ├── fetchCategoryList.js
│ ├── fetchGood.js
│ ├── fetchGoods.js
│ ├── fetchGoodsDetailsComments.js
│ ├── fetchGoodsList.js
│ ├── fetchSearchHistory.js
│ └── fetchSearchResult.js
├── home
│ └── home.js
├── order
│ ├── applyService.js
│ ├── orderConfirm.js
│ ├── orderDetail.js
│ ├── orderList.js
│ └── orderSubmitComment.js
├── promotion
│ └── detail.js
└── usercenter
│ ├── fetchPerson.js
│ └── fetchUsercenter.js
├── sitemap.json
├── style
├── cart-group.wxss
├── global.wxss
├── goodsList.wxss
├── iconfont.wxss
└── theme.wxss
└── utils
├── addressParse.js
├── getPermission.js
├── mock.js
└── util.js
/.github/ISSUE_TEMPLATE/feature-report.zh-CN.yml:
--------------------------------------------------------------------------------
1 | name: 反馈新功能
2 | description: 通过 github 模板进行新功能反馈。
3 | title: "[组件名称] 描述问题的标题"
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | # 欢迎你的参与
9 | tdesign-miniprogram-starter-retail 的 Issue 列表接受 bug 报告或是新功能请求。也可加入官方社区:
10 |
11 | 在发布一个 Issue 前,请确保:
12 | - 在 [常见问题](https://tdesign.tencent.com/about/faq)、[更新日志](https://github.com/Tencent/tdesign-miniprogram-starter-retail/blob/main/CHANGELOG.md) 和 [旧Issue列表](https://github.com/Tencent/tdesign-miniprogram-starter-retail/issues?q=is%3Aissue) 中搜索过你的问题。(你的问题可能已有人提出,也可能已在最新版本中被修正)
13 | - 如果你发现一个已经关闭的旧 Issue 在最新版本中仍然存在,不要在旧 Issue 下面留言,请建一个新的 issue。
14 |
15 | - type: textarea
16 | id: functionContent
17 | attributes:
18 | label: 这个功能解决了什么问题
19 | description: 请详尽说明这个需求的用例和场景。最重要的是:解释清楚是怎样的用户体验需求催生了这个功能上的需求。我们将考虑添加在现有 API 无法轻松实现的功能。新功能的用例也应当足够常见。
20 | placeholder: 请填写
21 | validations:
22 | required: true
23 |
24 | - type: textarea
25 | id: functionalExpectations
26 | attributes:
27 | label: 你建议的方案是什么
28 | placeholder: 请填写
29 | validations:
30 | required: true
31 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | ### 🤔 这个 PR 的性质是?
8 |
9 | - [ ] 日常 bug 修复
10 | - [ ] 新特性提交
11 | - [ ] 文档改进
12 | - [ ] 演示代码改进
13 | - [ ] 组件样式/交互改进
14 | - [ ] CI/CD 改进
15 | - [ ] 重构
16 | - [ ] 代码风格优化
17 | - [ ] 测试用例
18 | - [ ] 分支合并
19 | - [ ] 其他
20 |
21 | ### 🔗 相关 Issue
22 |
23 |
26 |
27 | ### 💡 需求背景和解决方案
28 |
29 |
34 |
35 | ### 📝 更新日志
36 |
37 |
40 |
41 | - fix(组件名称): 处理问题或特性描述 ...
42 |
43 | - [ ] 本条 PR 不需要纳入 Changelog
44 |
45 | ### ☑️ 请求合并前的自查清单
46 |
47 | ⚠️ 请自检并全部**勾选全部选项**。⚠️
48 |
49 | - [ ] 文档已补充或无须补充
50 | - [ ] 代码演示已提供或无须提供
51 | - [ ] TypeScript 定义已补充或无须补充
52 | - [ ] Changelog 已提供或无须提供
53 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Basic dependabot.yml file with
2 | # minimum configuration for two package managers
3 |
4 | version: 2
5 | updates:
6 | # Enable version updates for npm
7 | - package-ecosystem: "npm"
8 | # Look for `package.json` and `lock` files in the `root` directory
9 | directory: "/"
10 | # Check the npm registry for updates every day (weekdays)
11 | schedule:
12 | interval: "monthly"
13 |
14 | # Enable version updates for Docker
15 | - package-ecosystem: "docker"
16 | # Look for a `Dockerfile` in the `root` directory
17 | directory: "/"
18 | # Check for updates once a week
19 | schedule:
20 | interval: "monthly"
21 |
--------------------------------------------------------------------------------
/.github/workflows/issue-help-wanted.temp.yml:
--------------------------------------------------------------------------------
1 | # force copy from tencent/tdesign
2 | name: Issue Help wanted
3 | on:
4 | issues:
5 | types:
6 | - labeled
7 | jobs:
8 | add-comment:
9 | if: github.event.label.name == 'help wanted'
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | steps:
14 | - name: Add comment
15 | uses: peter-evans/create-or-update-comment@v1
16 | with:
17 | issue-number: ${{ github.event.issue.number }}
18 | body: |
19 | 任何人都可以处理此问题。
20 | **请务必在您的 `pull request` 中引用此问题。** :sparkles:
21 | 感谢你的贡献! :sparkles:
22 | reactions: heart
--------------------------------------------------------------------------------
/.github/workflows/issue-mark-duplicate.temp.yml:
--------------------------------------------------------------------------------
1 | # force copy from tencent/tdesign
2 | # 当在 issue 的 comment 回复类似 `Duplicate of #111` 这样的话,issue 将被自动打上 重复提交标签 并且 cloese
3 | name: Issue Mark Duplicate
4 |
5 | on:
6 | issue_comment:
7 | types: [created, edited]
8 |
9 | jobs:
10 | mark-duplicate:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: mark-duplicate
14 | uses: actions-cool/issues-helper@v2
15 | with:
16 | actions: "mark-duplicate"
17 | token: ${{ secrets.GITHUB_TOKEN }}
18 | duplicate-labels: "duplicate"
19 | close-issue: true
20 |
--------------------------------------------------------------------------------
/.github/workflows/issue-reply.temp.yml:
--------------------------------------------------------------------------------
1 | # force copy from tencent/tdesign
2 | # 当被打上 Need Reproduce 标签时候,自动提示需要重现实例
3 |
4 | name: ISSUE_REPLY
5 |
6 | on:
7 | issues:
8 | types: [labeled]
9 |
10 | jobs:
11 | issue-reply:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Need Reproduce
15 | if: github.event.label.name == 'Need Reproduce'
16 | uses: actions-cool/issues-helper@v2
17 | with:
18 | actions: 'create-comment'
19 | issue-number: ${{ github.event.issue.number }}
20 | body: |
21 | 你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 [此处](https://codesandbox.io/) 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。请确保选择准确的版本。
22 |
--------------------------------------------------------------------------------
/.github/workflows/issue-stale-close.temp.yml:
--------------------------------------------------------------------------------
1 | # force copy from tencent/tdesign
2 | # 国际标准时间+8
3 | name: Close stale issues and PRs
4 | on:
5 | schedule:
6 | - cron: "50 5 * * *"
7 |
8 | jobs:
9 | close-issues:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | pull-requests: write
14 | steps:
15 | - uses: actions/stale@v4
16 | with:
17 | stale-issue-message: "这个 Issue 被标记为了过时 stale ,因为它已经持续 30 天没有任何活动了。删除 stale 标签或评论,否则将在 7 天内关闭。"
18 | stale-pr-message: '这个 PR 已经过时了,因为它已经持续 45 天没有任何活动了。 删除 stale 的标签或评论,否则将在 10 天内关闭。'
19 | close-issue-message: "此 Issue 被自动关闭,因为它自被标记为过时 stale 以来已闲置 7 天。"
20 | close-pr-message: "此 PR 被自动关闭,因为它已经 stable 停滞了 10 天,没有任何活动。"
21 | days-before-stale: 30
22 | days-before-close: 7
23 | days-before-pr-stale: 45
24 | days-before-pr-close: 10
25 | repo-token: ${{ secrets.GITHUB_TOKEN }}
26 | exempt-issue-labels: 'WIP'
27 | exempt-pr-labels: 'WIP'
--------------------------------------------------------------------------------
/.github/workflows/issue-synchronize.temp.yml:
--------------------------------------------------------------------------------
1 | # force copy from tencent/tdesign
2 | name: Issue Add Assigness
3 |
4 | on:
5 | issues:
6 | types: [opened, reopened]
7 |
8 | jobs:
9 | mark-duplicate:
10 | runs-on: ubuntu-latest
11 | steps:
12 | # https://docs.github.com/cn/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#issues
13 | - uses: 94dreamer/create-report@main
14 | with:
15 | wxhook: ${{ secrets.WX_HOOK_URL }}
16 | token: ${{ secrets.GITHUB_TOKEN }}
17 | type: 'issue'
--------------------------------------------------------------------------------
/.github/workflows/pr-spelling.template.yml:
--------------------------------------------------------------------------------
1 | name: pr-spell-check
2 | on: [pull_request]
3 |
4 | jobs:
5 | run:
6 | name: Spell Check with Typos
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - name: Check spelling
11 | uses: crate-ci/typos@master
12 | with:
13 | config: .github/workflows/typos-config.toml
14 |
--------------------------------------------------------------------------------
/.github/workflows/typos-config.toml:
--------------------------------------------------------------------------------
1 | [default.extend-words]
2 | actived = "actived"
3 | formated = "formated"
4 | formate = "formate"
5 | Colum = "Colum"
6 | ba = "ba"
7 | ded = "ded"
8 | Hel = "Hel"
9 | Indexs = "Indexs"
10 | wating = "wating"
11 | Ment = "Ment"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | yarn-error.log
3 | miniprogram/
4 | miniprogram_npm/
5 | miniprogram_dist/
6 | .DS_Store
7 | $node_modules/
8 | .history/
9 | **/dist
10 | components/**/*.lock
11 | components/**/package-lock.json
12 | package-lock.json
13 | yarn.lock
14 | project.private.config.json
15 | .eslintcache
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 | . "$(dirname -- "$0")/_/husky.sh"
3 |
4 | npx --no-install commitlint --edit ""
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.husky/prepare-commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | exec < /dev/tty && npx git-cz --hook || true
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # 去除注释可以使用代理进行安装
2 | # proxy=http://127.0.0.1:1080
3 | # https_proxy=http://127.0.0.1:1080
4 |
5 | # 去除注释可以使用淘宝源
6 | # registry=https://registry.npm.taobao.org
7 |
8 | # 去除注释可以使用腾讯源
9 | #registry=http://mirrors.tencent.com/npm/
10 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | miniprogram_npm
2 | package.json
3 | project.config.json
--------------------------------------------------------------------------------
/.prettierrc.yml:
--------------------------------------------------------------------------------
1 | # 一行最多 100 字符
2 | printWidth: 120
3 | # 使用 2 个空格缩进
4 | tabWidth: 2
5 | # 不使用缩进符,而使用空格
6 | useTabs: false
7 | # 行尾需要分号
8 | semi: true
9 | # 使用单引号
10 | singleQuote: true
11 | # 对象的 key 仅在必要时用引号
12 | quoteProps: as-needed
13 | # jsx 不使用单引号,而使用双引号
14 | jsxSingleQuote: false
15 | # 末尾需要逗号
16 | trailingComma: all
17 | # 大括号内的首尾需要空格
18 | bracketSpacing: true
19 | # jsx 标签的反尖括号需要换行
20 | jsxBracketSameLine: false
21 | # 箭头函数,只有一个参数的时候,不需要括号
22 | arrowParens: always
23 | # 每个文件格式化的范围是文件的全部内容
24 | rangeStart: 0
25 | # 不需要写文件开头的 @prettier
26 | requirePragma: false
27 | # 不需要自动在文件开头插入 @prettier
28 | insertPragma: false
29 | # 使用默认的折行标准
30 | proseWrap: preserve
31 | # 根据显示样式决定 html 要不要折行
32 | htmlWhitespaceSensitivity: css
33 | # 换行符使用 lf
34 | endOfLine: lf
35 | # 后缀文件名特有规则
36 | overrides:
37 | - files: '*.{wxss,less}'
38 | options:
39 | parser: less
40 | - files: '*.json,.*rc'
41 | options:
42 | parser: json
43 | - files: '*.{wxml,html}'
44 | options:
45 | parser: html
46 | htmlWhitespaceSensitivity: strict
47 | - files: '*.wxs'
48 | options:
49 | parser: babel
50 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.defaultFormatter": "esbenp.prettier-vscode",
3 | "eslint.enable": true,
4 | "editor.formatOnSave": true,
5 | "editor.codeActionsOnSave": {
6 | "source.fixAll.tslint": true,
7 | "source.fixAll.eslint": true
8 | },
9 | "[javascript]": {
10 | "editor.formatOnSave": true,
11 | "editor.defaultFormatter": "esbenp.prettier-vscode"
12 | },
13 | "[json]": {
14 | "editor.defaultFormatter": "vscode.json-language-features"
15 | },
16 | "[wxss]": {
17 | "editor.defaultFormatter": "HookyQR.beautify"
18 | },
19 | "wxmlConfig.onSaveFormat": true,
20 | "wxmlConfig.format": {
21 | "brace_style": "collapse",
22 | "indent_inner_html": true,
23 | "indent_scripts": "keep",
24 | "indent_size": 2,
25 | "indent_char": " ",
26 | "unformatted": "['wxs']",
27 | "disable_automatic_closing_labels": false,
28 | "preserve_newlines": true,
29 | "wrap_attributes": "force-expand-multiline",
30 | "wrap_attributes_count": 4,
31 | "wrap_attributes_indent_size": 2
32 | },
33 | "editor.tabSize": 2
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021-present TDesign
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | import updateManager from './common/updateManager';
2 |
3 | App({
4 | onLaunch: function () {},
5 | onShow: function () {
6 | updateManager();
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | @import 'style/iconfont.wxss';
2 |
3 | @import 'style/theme.wxss';
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = { extends: ['@commitlint/config-conventional'] };
2 |
--------------------------------------------------------------------------------
/common/updateManager.js:
--------------------------------------------------------------------------------
1 | export default () => {
2 | if (!wx.canIUse('getUpdateManager')) {
3 | return;
4 | }
5 |
6 | const updateManager = wx.getUpdateManager();
7 |
8 | updateManager.onCheckForUpdate(function (res) {
9 | // 请求完新版本信息的回调
10 | console.log('版本信息', res);
11 | });
12 |
13 | updateManager.onUpdateReady(function () {
14 | wx.showModal({
15 | title: '更新提示',
16 | content: '新版本已经准备好,是否重启应用?',
17 | success(res) {
18 | if (res.confirm) {
19 | // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
20 | updateManager.applyUpdate();
21 | }
22 | },
23 | });
24 | });
25 |
26 | updateManager.onUpdateFailed(function () {
27 | // 新版本下载失败
28 | });
29 | };
30 |
--------------------------------------------------------------------------------
/components/filter-popup/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class'],
3 |
4 | options: {
5 | multipleSlots: true,
6 | },
7 |
8 | properties: {
9 | show: {
10 | type: Boolean,
11 | observer(show) {
12 | this.setData({ visible: show });
13 | },
14 | },
15 | closeBtn: {
16 | type: Boolean,
17 | value: false,
18 | },
19 | },
20 |
21 | data: { visible: false },
22 |
23 | methods: {
24 | reset() {
25 | this.triggerEvent('reset');
26 | },
27 | confirm() {
28 | this.triggerEvent('confirm');
29 | },
30 | close() {
31 | this.triggerEvent('showFilterPopupClose');
32 |
33 | this.setData({ visible: false });
34 | },
35 | },
36 | });
37 |
--------------------------------------------------------------------------------
/components/filter-popup/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup"
5 | }
6 | }
--------------------------------------------------------------------------------
/components/filter-popup/index.wxml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 | 重置
12 |
13 | 确定
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/components/filter-popup/index.wxss:
--------------------------------------------------------------------------------
1 | .content .filter-btns-wrap {
2 | width: 100%;
3 | position: absolute;
4 | bottom: calc(20rpx + env(safe-area-inset-bottom));
5 | display: flex;
6 | flex-direction: row;
7 | border-radius: 10rpx 0 0 10rpx;
8 | padding: 16rpx 32rpx;
9 | border-top: 1rpx solid #e5e5e5;
10 | box-sizing: border-box;
11 | }
12 |
13 | .filter-btn {
14 | flex: 1;
15 | display: flex;
16 | justify-content: center;
17 | align-items: center;
18 | font-size: 28rpx;
19 | font-weight: 500;
20 | height: 80rpx;
21 | }
22 |
23 | .btn-reset {
24 | color: #fa4126;
25 | background: rgba(255, 255, 255, 1);
26 | position: relative;
27 | border: 1rpx solid #fa4126;
28 | border-radius: 84rpx 0 0 84rpx;
29 | }
30 |
31 | .btn-confirm {
32 | border-radius: 0 84rpx 84rpx 0;
33 | border: 1rpx solid #fa4126;
34 | }
35 |
36 | .btn-confirm {
37 | color: #fff;
38 | background: #fa4126;
39 | }
40 |
--------------------------------------------------------------------------------
/components/filter/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon"
5 | }
6 | }
--------------------------------------------------------------------------------
/components/filter/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 综合
6 |
7 |
8 | 价格
9 |
10 |
16 |
22 |
23 |
24 |
25 | 筛选
26 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/components/filter/index.wxss:
--------------------------------------------------------------------------------
1 | .filter-wrap {
2 | width: 100%;
3 | height: 88rpx;
4 | display: flex;
5 | justify-content: space-between;
6 | position: relative;
7 | background: #fff;
8 | }
9 |
10 | .filter-right-content {
11 | height: 100%;
12 | flex-basis: 100rpx;
13 | text-align: center;
14 | line-height: 88rpx;
15 | }
16 |
17 | .filter-left-content {
18 | height: 100%;
19 | display: flex;
20 | flex-grow: 2;
21 | flex-flow: row nowrap;
22 | justify-content: space-between;
23 | }
24 |
25 | .filter-left-content .filter-item {
26 | flex: 1;
27 | height: 100%;
28 | display: flex;
29 | align-items: center;
30 | justify-content: center;
31 | font-size: 26rpx;
32 | line-height: 36rpx;
33 | font-weight: 400;
34 | color: rgba(51, 51, 51, 1);
35 | }
36 |
37 | .filter-left-content .filter-item .filter-price {
38 | display: flex;
39 | flex-direction: column;
40 | margin-left: 6rpx;
41 | justify-content: space-between;
42 | }
43 |
44 | .filter-left-content .filter-item .wr-filter {
45 | margin-left: 8rpx;
46 | }
47 |
48 | .filter-left-content .filter-active-item {
49 | color: #fa550f;
50 | }
51 |
--------------------------------------------------------------------------------
/components/goods-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "price": "/components/price/index",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-image": "/components/webp-image/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/components/goods-list/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class'],
3 |
4 | properties: {
5 | goodsList: {
6 | type: Array,
7 | value: [],
8 | },
9 | id: {
10 | type: String,
11 | value: '',
12 | observer: (id) => {
13 | this.genIndependentID(id);
14 | },
15 | },
16 | thresholds: {
17 | type: Array,
18 | value: [],
19 | },
20 | },
21 |
22 | data: {
23 | independentID: '',
24 | },
25 |
26 | lifetimes: {
27 | ready() {
28 | this.init();
29 | },
30 | },
31 |
32 | methods: {
33 | onClickGoods(e) {
34 | const { index } = e.currentTarget.dataset;
35 | this.triggerEvent('click', { ...e.detail, index });
36 | },
37 |
38 | onAddCart(e) {
39 | const { index } = e.currentTarget.dataset;
40 | this.triggerEvent('addcart', { ...e.detail, index });
41 | },
42 |
43 | onClickGoodsThumb(e) {
44 | const { index } = e.currentTarget.dataset;
45 | this.triggerEvent('thumb', { ...e.detail, index });
46 | },
47 |
48 | init() {
49 | this.genIndependentID(this.id || '');
50 | },
51 |
52 | genIndependentID(id) {
53 | if (id) {
54 | this.setData({ independentID: id });
55 | } else {
56 | this.setData({
57 | independentID: `goods-list-${~~(Math.random() * 10 ** 8)}`,
58 | });
59 | }
60 | },
61 | },
62 | });
63 |
--------------------------------------------------------------------------------
/components/goods-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "goods-card": "/components/goods-card/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/components/goods-list/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/components/goods-list/index.wxss:
--------------------------------------------------------------------------------
1 | .goods-list-wrap {
2 | display: flex;
3 | flex-flow: row wrap;
4 | justify-content: space-between;
5 | padding: 0;
6 | background: #fff;
7 | }
8 |
--------------------------------------------------------------------------------
/components/load-more/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class', 'wr-class--no-more'],
3 |
4 | options: { multipleSlots: true },
5 |
6 | properties: {
7 | status: {
8 | type: Number,
9 | value: 0,
10 | },
11 | loadingText: {
12 | type: String,
13 | value: '加载中...',
14 | },
15 | noMoreText: {
16 | type: String,
17 | value: '没有更多了',
18 | },
19 | failedText: {
20 | type: String,
21 | value: '加载失败,点击重试',
22 | },
23 | color: {
24 | type: String,
25 | value: '#BBBBBB',
26 | },
27 | failedColor: {
28 | type: String,
29 | value: '#FA550F',
30 | },
31 | size: {
32 | type: null,
33 | value: '40rpx',
34 | },
35 | loadingBackgroundColor: {
36 | type: String,
37 | value: '#F5F5F5',
38 | },
39 | listIsEmpty: {
40 | type: Boolean,
41 | value: false,
42 | },
43 | },
44 |
45 | methods: {
46 | /** 点击处理 */
47 | tapHandle() {
48 | // 失败重试
49 | if (this.data.status === 3) {
50 | this.triggerEvent('retry');
51 | }
52 | },
53 | },
54 | });
55 |
--------------------------------------------------------------------------------
/components/load-more/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-loading": "tdesign-miniprogram/loading/loading",
5 | "t-divider": "tdesign-miniprogram/divider/divider"
6 | }
7 | }
--------------------------------------------------------------------------------
/components/load-more/index.wxml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
17 |
18 |
19 |
20 | {{noMoreText}}
21 |
22 |
23 |
24 |
25 | 加载失败
26 | 刷新
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/components/load-more/index.wxss:
--------------------------------------------------------------------------------
1 | .load-more {
2 | font-size: 24rpx;
3 | height: 100rpx;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: center;
7 | }
8 |
9 | .load-more .t-class-loading {
10 | display: flex;
11 | justify-content: center;
12 |
13 | --td-loading-color: #fa4126;
14 | }
15 |
16 | .load-more .t-class-loading-text {
17 | color: #bbbbbb;
18 | }
19 |
20 | .t-class-divider-content {
21 | margin: 0 10rpx;
22 | color: #bbbbbb;
23 | }
24 | .load-more .t-class-indicator {
25 | color: #b9b9b9 !important;
26 | }
27 |
28 | .load-more__error {
29 | margin: auto;
30 | }
31 |
32 | .load-more__refresh-btn {
33 | margin-left: 16rpx;
34 | color: #fa4126;
35 | }
36 |
--------------------------------------------------------------------------------
/components/loading-content/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class'],
3 | properties: {
4 | position: {
5 | type: String,
6 | value: 'static',
7 | },
8 | noMask: Boolean,
9 | type: {
10 | type: String,
11 | value: 'circular',
12 | },
13 | vertical: Boolean,
14 | size: {
15 | type: String,
16 | value: '50rpx',
17 | },
18 | backgroundColor: {
19 | type: String,
20 | value: 'rgba(0, 0, 0, .6)',
21 | },
22 | },
23 | });
24 |
--------------------------------------------------------------------------------
/components/loading-content/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-loading": "tdesign-miniprogram/loading/loading"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/components/loading-content/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/components/loading-content/index.wxss:
--------------------------------------------------------------------------------
1 | .loading-content {
2 | width: 100%;
3 | height: 100%;
4 | background-color: rgba(0, 0, 0, 0.6);
5 | position: relative;
6 | }
7 | .loading-content.absolute {
8 | position: absolute;
9 | z-index: 1;
10 | left: 0;
11 | top: 0;
12 | }
13 | .loading-content.fixed {
14 | position: fixed;
15 | z-index: 1;
16 | left: 0;
17 | top: 0;
18 | }
19 | .loading-content .loading {
20 | width: 100%;
21 | height: 100%;
22 | visibility: visible;
23 | }
24 |
--------------------------------------------------------------------------------
/components/price/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
5 |
--------------------------------------------------------------------------------
/components/price/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | var REGEXP = getRegExp('^\d+(\.\d+)?$');
3 | function addUnit(value) {
4 | if (value == null) {
5 | return '';
6 | }
7 | return REGEXP.test('' + value) ? value + 'rpx' : value;
8 | }
9 | module.exports = {
10 | addUnit: addUnit
11 | };
12 |
13 |
14 |
15 | {{symbol}}
16 |
17 | {{pArr[0]}}
18 | .{{pArr[1]}}
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/components/price/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: inline-block;
3 | display: inline-block;
4 | font-weight: inherit;
5 | }
6 | .inline {
7 | display: inline;
8 | white-space: nowrap;
9 | }
10 | .price {
11 | display: inline;
12 | color: inherit;
13 | font-size: inherit;
14 | text-decoration: inherit;
15 | }
16 |
17 | .lighter {
18 | font-weight: 400;
19 | font-size: 32rpx;
20 | }
21 | .mini {
22 | font-size: 24rpx;
23 | color: #5d5d5d;
24 | font-weight: 400;
25 | }
26 | .del .pprice {
27 | font-size: 32rpx;
28 | color: #9b9b9b;
29 | text-decoration: line-through;
30 | font-weight: 400;
31 | }
32 | .delthrough {
33 | position: relative;
34 | }
35 | .delthrough .line {
36 | position: absolute;
37 | top: 50%;
38 | left: 0;
39 | right: 0;
40 | transform: translateY(-50%);
41 | margin: 0;
42 | background-color: currentColor;
43 | }
44 |
45 | .symbol {
46 | display: inline;
47 | color: inherit;
48 | font-size: inherit;
49 | font-size: 0.8em;
50 | }
51 | .pprice {
52 | display: inline;
53 | margin: 0 0 0 4rpx;
54 | }
55 | .integer {
56 | color: inherit;
57 | font-size: inherit;
58 | }
59 | .decimal {
60 | color: inherit;
61 | font-size: inherit;
62 | }
63 | .decimal.smaller {
64 | font-size: 0.8em;
65 | vertical-align: baseline;
66 | }
67 |
--------------------------------------------------------------------------------
/components/swipeout/index.js:
--------------------------------------------------------------------------------
1 | let ARRAY = [];
2 | Component({
3 | externalClasses: ['wr-class'],
4 |
5 | options: {
6 | multipleSlots: true,
7 | },
8 | properties: {
9 | disabled: Boolean,
10 | leftWidth: {
11 | type: Number,
12 | value: 0,
13 | },
14 | rightWidth: {
15 | type: Number,
16 | value: 0,
17 | },
18 | asyncClose: Boolean,
19 | },
20 | attached() {
21 | ARRAY.push(this);
22 | },
23 |
24 | detached() {
25 | ARRAY = ARRAY.filter((item) => item !== this);
26 | },
27 |
28 | /**
29 | * Component initial data
30 | */
31 | data: {
32 | wrapperStyle: '',
33 | asyncClose: false,
34 | closed: true,
35 | },
36 |
37 | /**
38 | * Component methods
39 | */
40 | methods: {
41 | open(position) {
42 | this.setData({ closed: false });
43 | this.triggerEvent('close', {
44 | position,
45 | instance: this,
46 | });
47 | },
48 |
49 | close() {
50 | this.setData({ closed: true });
51 | },
52 |
53 | closeOther() {
54 | ARRAY.filter((item) => item !== this).forEach((item) => item.close());
55 | },
56 |
57 | noop() {
58 | return;
59 | },
60 |
61 | onClick(event) {
62 | const { key: position = 'outside' } = event.currentTarget.dataset;
63 | this.triggerEvent('click', position);
64 |
65 | if (this.data.closed) {
66 | return;
67 | }
68 |
69 | if (this.data.asyncClose) {
70 | this.triggerEvent('close', {
71 | position,
72 | instance: this,
73 | });
74 | } else {
75 | this.close();
76 | }
77 | },
78 | },
79 | });
80 |
--------------------------------------------------------------------------------
/components/swipeout/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
5 |
--------------------------------------------------------------------------------
/components/swipeout/index.wxss:
--------------------------------------------------------------------------------
1 | .wr-swipeout {
2 | position: relative;
3 | overflow: hidden;
4 | }
5 | .wr-swipeout__left,
6 | .wr-swipeout__right {
7 | position: absolute;
8 | top: 0;
9 | height: 100%;
10 | }
11 | .wr-swipeout__left {
12 | left: 0;
13 | transform: translate3d(-100%, 0, 0);
14 | }
15 | .wr-swipeout__right {
16 | right: 0;
17 | transform: translate3d(100%, 0, 0);
18 | }
19 |
--------------------------------------------------------------------------------
/components/webp-image/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-image": "tdesign-miniprogram/image/image"
5 | }
6 | }
--------------------------------------------------------------------------------
/components/webp-image/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/components/webp-image/index.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tencent/tdesign-miniprogram-starter-retail/ef92ec100f82dfb724a62a08dfbc1defb50183c2/components/webp-image/index.wxss
--------------------------------------------------------------------------------
/custom-tab-bar/data.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | icon: 'home',
4 | text: '首页',
5 | url: 'pages/home/home',
6 | },
7 | {
8 | icon: 'sort',
9 | text: '分类',
10 | url: 'pages/goods/category/index',
11 | },
12 | {
13 | icon: 'cart',
14 | text: '购物车',
15 | url: 'pages/cart/index',
16 | },
17 | {
18 | icon: 'person',
19 | text: '个人中心',
20 | url: 'pages/usercenter/index',
21 | },
22 | ];
23 |
--------------------------------------------------------------------------------
/custom-tab-bar/index.js:
--------------------------------------------------------------------------------
1 | import TabMenu from './data';
2 | Component({
3 | data: {
4 | active: 0,
5 | list: TabMenu,
6 | },
7 |
8 | methods: {
9 | onChange(event) {
10 | this.setData({ active: event.detail.value });
11 | wx.switchTab({
12 | url: this.data.list[event.detail.value].url.startsWith('/')
13 | ? this.data.list[event.detail.value].url
14 | : `/${this.data.list[event.detail.value].url}`,
15 | });
16 | },
17 |
18 | init() {
19 | const page = getCurrentPages().pop();
20 | const route = page ? page.route.split('?')[0] : '';
21 | const active = this.data.list.findIndex(
22 | (item) =>
23 | (item.url.startsWith('/') ? item.url.substr(1) : item.url) ===
24 | `${route}`,
25 | );
26 | this.setData({ active });
27 | },
28 | },
29 | });
30 |
--------------------------------------------------------------------------------
/custom-tab-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-tab-bar": "tdesign-miniprogram/tab-bar/tab-bar",
5 | "t-tab-bar-item": "tdesign-miniprogram/tab-bar-item/tab-bar-item",
6 | "t-icon": "tdesign-miniprogram/icon/icon"
7 | }
8 | }
--------------------------------------------------------------------------------
/custom-tab-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
6 |
12 |
13 |
14 | {{ item.text }}
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/custom-tab-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .custom-tab-bar-wrapper {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | }
6 |
7 | .custom-tab-bar-wrapper .text {
8 | font-size: 20rpx;
9 | }
10 |
--------------------------------------------------------------------------------
/ext.json:
--------------------------------------------------------------------------------
1 | {
2 | "extEnable": true,
3 | "extAppid": "wx5a75208aa13eee03",
4 | "ext": {},
5 | "window": {}
6 | }
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "."
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/mock.md:
--------------------------------------------------------------------------------
1 | ## 模拟与数据
2 |
3 | model 用于放置模拟后端数据返回的逻辑;假若接入真实后端接口,则本文件夹可改造为数据层适配。
4 | services 用于请求逻辑,根据 config.useMock 配置可控制返回 mock 数据或是真实接口数据
5 |
6 | ### 1 模拟策略
7 |
8 | 1)只依靠 ID 规律进行关联
9 | 大部分情况下推荐使用本方案,ID 为`1`的商品固定会关联 ID 为`1`的优惠券或者[ID 对 10 的模运算结果为 1](https://www.runoob.com/try/try.php?filename=tryjs_oper_mod)的优惠券(看需要 1 个还是多个了)。
10 |
11 | > 为保持关系稳定,模运算统一使用`10`为除数,`ID`为被除数;即`1%10`、`2%10`。
12 |
13 | 2)建立额外关联关系查询
14 | 在无法使用简单数学关系维持关系的情况下,可以采用单独提供关系数据的方式进行关联(目前也没想到什么场景是数学关系稳定不了的了,先假定有,定下规范做法)。如数据 A 与数据 B 之间需要一个关联 AB,则需要提供`A数据mock`、`B数据mock`、以及`A查B与B反查A`共 4 个 mock 源。
15 |
16 | ### 2 使用数据
17 |
18 | 使用数据源时应该在 services 文件夹中按照业务新建自己 fetch 函数导出,fetch 函数以 Promise 形式返回组合调用 model 逻辑得到的数据。
19 |
20 | > 不允许直接在业务中调用、使用 model 数据。
21 |
22 | ## 接入真实 API 后
23 |
24 | 接入真实 API 后 model 文件夹逻辑可以反转层级,作为数据适配层继续为项目服务。举例说明:
25 |
26 | 1. 在没有接入 API 时(useMock 为 true)
27 | 1.1 业务调用 services 进行 fetch
28 | 1.2 fetch 逻辑调用 model 文件夹中对应的数据源,构造、返回业务需要的结构
29 |
30 | 2. 在接入 API 后(useMock 为 false)
31 | 2.1 业务调用 services 进行 fetch
32 | 2.2 fetch 逻辑调用接口得到真实后端数据
33 | 2.3 比对 model 文件夹中数据 mock 数据结构 export 一个数据结构转换函数,输入真实后端数据,输出与 mock 数据结构一致的新数据,返回给 fetch
34 | 2.4 fetch 函数 返回 转换后的 数据结构,业务层无需进行更改
35 |
--------------------------------------------------------------------------------
/model/activities.js:
--------------------------------------------------------------------------------
1 | import { getActivity } from './activity';
2 |
3 | export function getActivityList(baseID = 0, length = 10) {
4 | return new Array(length).fill(0).map((_, idx) => getActivity(idx + baseID));
5 | }
6 |
7 | export const activityList = getActivityList();
8 |
--------------------------------------------------------------------------------
/model/activity.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {string|number} key 唯一值
3 | */
4 | export function getActivity(key) {
5 | return {
6 | promotionId: `${key}`,
7 | title: `满减满折回归${key}`,
8 | description: null,
9 | promotionCode: 'MERCHANT',
10 | promotionSubCode: key % 2 === 0 ? 'MYJ' : 'MYG',
11 | tag: '满减',
12 | timeType: 1,
13 | startTime: '1588737710000',
14 | endTime: '1601467070000',
15 | teasingStartTime: null,
16 | activityLadder: [{ label: '满100元减99.9元' }],
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/model/address.js:
--------------------------------------------------------------------------------
1 | /** 地址 */
2 | export function genAddress(id) {
3 | return {
4 | saasId: '88888888',
5 | uid: `8888888820550${id}`,
6 | authToken: null,
7 | id: `${id}`,
8 | addressId: `${id}`,
9 | phone: '17612345678',
10 | name: `测试用户${id}`,
11 | countryName: '中国',
12 | countryCode: 'chn',
13 | provinceName: '甘肃省',
14 | provinceCode: '620000',
15 | cityName: '甘南藏族自治州',
16 | cityCode: '623000',
17 | districtName: '碌曲县',
18 | districtCode: '623026',
19 | detailAddress: `松日鼎盛大厦${id}层${id}号`,
20 | isDefault: `${id}` === '0' ? 1 : 0,
21 | addressTag: id === 0 ? '' : '公司',
22 | latitude: '34.59103',
23 | longitude: '102.48699',
24 | storeId: null,
25 | };
26 | }
27 |
28 | /** 地址列表 */
29 | export function genAddressList(len = 10) {
30 | return new Array(len).fill(0).map((_, idx) => genAddress(idx));
31 | }
32 |
--------------------------------------------------------------------------------
/model/comments/queryDetail.js:
--------------------------------------------------------------------------------
1 | const queryDetail = {
2 | commentInfos: [
3 | {
4 | id: '647984992708380600',
5 | uid: '',
6 | userName: 'Dean Cheng',
7 | userHeadUrl:
8 | 'https://bizmid-material-qa-1302115263.cos.ap-guangzhou.myqcloud.com/comment/default_head.png',
9 | commentId: '1937712',
10 | commentIdName: '小鹿商品',
11 | commentIdImageUrl:
12 | 'https://bizmid-material-qa-1302115263.file.myqcloud.com/persist/4bf2ded7-1759-4821-919c-cc4960e14120/1078823925183295617/100000114727/material/1/cdbeb389be64427b8c165627895ff0bc-1610425563793-%E5%A4%B4%E5%83%8F.png',
13 | commentStage: 1,
14 | commentCheckStatus: 2,
15 | commentIdType: 1,
16 | content: '',
17 | commentInfo: {
18 | score: null,
19 | content: '',
20 | medias: [],
21 | commentTime: '1617872404000',
22 | },
23 | isAgainComment: 0,
24 | commentHasAgainComment: 0,
25 | isAnonymous: 0,
26 | replyList: [],
27 | specification: '颜色:白色 ',
28 | specificationJson: '{"颜色":"白色"}',
29 | commentExtendId: '1937713',
30 | commentTime: '1617872404000',
31 | score: 0,
32 | goodsScore: null,
33 | freightScore: null,
34 | serviceScore: null,
35 | medias: [],
36 | againCommentList: null,
37 | },
38 | ],
39 | logisticsScore: null,
40 | serviceScore: null,
41 | };
42 |
43 | /**
44 | * @param {string} skuId
45 | * @param {string} spuId
46 | * @param {string} orderNo
47 | */
48 | export function queryCommentDetail() {
49 | return queryDetail;
50 | }
51 |
--------------------------------------------------------------------------------
/model/coupon.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 优惠券
3 | *
4 | * @typedef {'default'|'useless'|'disabled'} CouponCardStatus
5 | * @typedef {'discount'|'price'} CouponCardType
6 | *
7 | * @param {number} [id]
8 | * @param {CouponCardStatus} [status]
9 | * @param {CouponCardType} [type]
10 | */
11 | export function getCoupon(id = 0, status = 'default', type = (id % 2) + 1) {
12 | return {
13 | /** key */
14 | key: `${id}`,
15 | /** 优惠券状态 */
16 | status,
17 | /** 优惠券类型 */
18 | type,
19 | /** 折扣或者满减值 */
20 | value: type === 2 ? 5.5 : 1800,
21 | /** 标签 */
22 | tag: '',
23 | /** 描述 */
24 | desc: parseInt(id) > 0 ? `满${parseInt(id) * 100}元可用` : '无门槛使用',
25 | /** 订单底价,满n元 */
26 | base: 10000 * (parseInt(id) || 0),
27 | /** 标题 */
28 | title: type === 2 ? `生鲜折扣券 - ${id}` : `生鲜满减券 - ${id}`,
29 | /** 有效时间限制 */
30 | timeLimit: '2019.11.18-2023.12.18',
31 | /** 货币符号 */
32 | currency: '¥',
33 | };
34 | }
35 |
36 | /** 优惠券列表 */
37 | export function getCouponList(status = 'default', length = 10) {
38 | return new Array(length).fill(0).map((_, idx) => getCoupon(idx, status));
39 | }
40 |
--------------------------------------------------------------------------------
/model/detailsComments.js:
--------------------------------------------------------------------------------
1 | export function getGoodsDetailsComments() {
2 | return {
3 | homePageComments: [
4 | {
5 | spuId: '1722045',
6 | skuId: null,
7 | specInfo: null,
8 | commentContent:
9 | '收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
10 | commentScore: 4,
11 | uid: '88881048075',
12 | userName: 'Dean',
13 | userHeadUrl:
14 | 'https://wx.qlogo.cn/mmopen/vi_32/5mKrvn3ibyDNaDZSZics3aoKlz1cv0icqn4EruVm6gKjsK0xvZZhC2hkUkRWGxlIzOEc4600JkzKn9icOLE6zjgsxw/132',
15 | },
16 | ],
17 | };
18 | }
19 |
20 | export function getGoodsDetailsCommentsCount() {
21 | return {
22 | commentCount: '47',
23 | badCount: '0',
24 | middleCount: '2',
25 | goodCount: '45',
26 | hasImageCount: '1',
27 | goodRate: 95.7,
28 | uidCount: '0',
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/model/goods.js:
--------------------------------------------------------------------------------
1 | import { genGood } from './good';
2 |
3 | export function getGoodsList(baseID = 0, length = 10) {
4 | return new Array(length).fill(0).map((_, idx) => genGood(idx + baseID));
5 | }
6 |
7 | export const goodsList = getGoodsList();
8 |
--------------------------------------------------------------------------------
/model/promotion.js:
--------------------------------------------------------------------------------
1 | import { getGoodsList } from './goods';
2 |
3 | export function getPromotion(baseID = 0, length = 10) {
4 | return {
5 | list: getGoodsList(baseID, length).map((item) => {
6 | return {
7 | spuId: item.spuId,
8 | thumb: item.primaryImage,
9 | title: item.title,
10 | price: item.minSalePrice,
11 | originPrice: item.maxLinePrice,
12 | tags: item.spuTagList.map((tag) => ({ title: tag.title })),
13 | };
14 | }),
15 | banner:
16 | 'https://cdn-we-retail.ym.tencent.com/tsr/promotion/banner-promotion.png',
17 | time: 1000 * 60 * 60 * 20,
18 | showBannerDesc: true,
19 | statusTag: 'running',
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/model/search.js:
--------------------------------------------------------------------------------
1 | import { getGoodsList } from './goods';
2 |
3 | /**
4 | * @param {number} sort
5 | * @param {number} pageNum
6 | * @param {number} pageSize
7 | * @param {number} minPrice
8 | * @param {number} maxPrice
9 | * @param {string} keyword
10 | */
11 |
12 | export function getSearchHistory() {
13 | return {
14 | historyWords: [
15 | '鸡',
16 | '电脑',
17 | 'iPhone12',
18 | '车载手机支架',
19 | '自然堂',
20 | '小米10',
21 | '原浆古井贡酒',
22 | '欧米伽',
23 | '华为',
24 | '针织半身裙',
25 | '氢跑鞋',
26 | '三盒处理器',
27 | ],
28 | };
29 | }
30 |
31 | export function getSearchPopular() {
32 | return {
33 | popularWords: [
34 | '鸡',
35 | '电脑',
36 | 'iPhone12',
37 | '车载手机支架',
38 | '自然堂',
39 | '小米10',
40 | '原浆古井贡酒',
41 | '欧米伽',
42 | '华为',
43 | '针织半身裙',
44 | '氢跑鞋',
45 | '三盒处理器',
46 | ],
47 | };
48 | }
49 |
50 | export function getSearchResult() {
51 | return {
52 | saasId: null,
53 | storeId: null,
54 | pageNum: 1,
55 | pageSize: 30,
56 | totalCount: 1,
57 | spuList: getGoodsList(7),
58 | algId: 0,
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/model/submitComment.js:
--------------------------------------------------------------------------------
1 | export function getGoods() {
2 | return {
3 | goods: [
4 | {
5 | squid: '1',
6 | checkItems: [
7 | {
8 | name: '匿名评价',
9 | value: 'anonymous',
10 | checked: false,
11 | },
12 | ],
13 | detail: {
14 | image:
15 | 'https://wx.qlogo.cn/mmopen/vi_32/51VSMNuy1CyHiaAhAjLJ00kMZVqqnCqXeZduCLXHUBr52zFHRGxwL7kGia3fHj8GSNzFcqFDInQmRGM1eWjtQgqA/132',
16 | title: '',
17 | },
18 | goodComment: {
19 | /** 商品评价 */
20 | rate: 0,
21 | /** 评价内容 */
22 | label: '123',
23 | /** 上传图片 */
24 | images: [],
25 | },
26 | },
27 | {
28 | squid: '2',
29 | checkItems: [
30 | {
31 | name: '匿名评价',
32 | value: 'anonymous',
33 | checked: false,
34 | },
35 | ],
36 | detail: {
37 | image:
38 | 'https://wx.qlogo.cn/mmopen/vi_32/51VSMNuy1CyHiaAhAjLJ00kMZVqqnCqXeZduCLXHUBr52zFHRGxwL7kGia3fHj8GSNzFcqFDInQmRGM1eWjtQgqA/132',
39 | title: '评价内容 山姆智利进口',
40 | },
41 | goodComment: {
42 | /** 商品评价 */
43 | rate: 0,
44 | /** 评价内容 */
45 | label: '山姆智利进口',
46 | /** 上传图片 */
47 | images: [],
48 | },
49 | },
50 | ],
51 | storeComment: {
52 | /** 物流评价 */
53 | logisticsRate: 0,
54 | /** 服务评价 */
55 | servicesRate: 0,
56 | },
57 | };
58 | }
59 |
--------------------------------------------------------------------------------
/model/swiper.js:
--------------------------------------------------------------------------------
1 | // const images = [
2 | // {
3 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner1.png',
4 | // text: '1',
5 | // },
6 | // {
7 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner2.png',
8 | // text: '2',
9 | // },
10 | // {
11 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner3.png',
12 | // text: '3',
13 | // },
14 | // {
15 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner4.png',
16 | // text: '4',
17 | // },
18 | // {
19 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner5.png',
20 | // text: '5',
21 | // },
22 | // {
23 | // img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner6.png',
24 | // text: '6',
25 | // },
26 | // ];
27 |
28 | const images = [
29 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner1.png',
30 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner2.png',
31 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner3.png',
32 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner4.png',
33 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner5.png',
34 | 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner6.png',
35 | ];
36 |
37 | export function genSwiperImageList() {
38 | return images;
39 | }
40 |
--------------------------------------------------------------------------------
/model/usercenter.js:
--------------------------------------------------------------------------------
1 | const userInfo = {
2 | avatarUrl:
3 | 'https://we-retail-static-1300977798.cos.ap-guangzhou.myqcloud.com/retail-ui/components-exp/avatar/avatar-1.jpg',
4 | nickName: 'TDesign 🌟',
5 | phoneNumber: '13438358888',
6 | gender: 2,
7 | };
8 | const countsData = [
9 | {
10 | num: 2,
11 | name: '积分',
12 | type: 'point',
13 | },
14 | {
15 | num: 10,
16 | name: '优惠券',
17 | type: 'coupon',
18 | },
19 | ];
20 |
21 | const orderTagInfos = [
22 | {
23 | orderNum: 1,
24 | tabType: 5,
25 | },
26 | {
27 | orderNum: 1,
28 | tabType: 10,
29 | },
30 | {
31 | orderNum: 1,
32 | tabType: 40,
33 | },
34 | {
35 | orderNum: 0,
36 | tabType: 0,
37 | },
38 | ];
39 |
40 | const customerServiceInfo = {
41 | servicePhone: '4006336868',
42 | serviceTimeDuration: '每周三至周五 9:00-12:00 13:00-15:00',
43 | };
44 |
45 | export const genSimpleUserInfo = () => ({ ...userInfo });
46 |
47 | export const genUsercenter = () => ({
48 | userInfo,
49 | countsData,
50 | orderTagInfos,
51 | customerServiceInfo,
52 | });
53 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@tencent/tdesign-miniprogram-starter-retail",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "lint": "eslint --cache --fix --ext .js",
9 | "check": "node config/eslintCheck.js",
10 | "prepare": "husky install",
11 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "config": {
16 | "commitizen": {
17 | "path": "./node_modules/cz-conventional-changelog"
18 | }
19 | },
20 | "lint-staged": {
21 | "*.{js, ts}": "eslint --cache --fix",
22 | "*.{js,ts,wxml,html,json,css,less}": [
23 | "prettier --write"
24 | ]
25 | },
26 | "dependencies": {
27 | "dayjs": "^1.9.3",
28 | "tdesign-miniprogram": "^1.0.0",
29 | "tslib": "^1.11.1"
30 | },
31 | "devDependencies": {
32 | "@commitlint/cli": "^17.4.2",
33 | "@commitlint/config-conventional": "^17.4.2",
34 | "commitizen": "^4.3.0",
35 | "conventional-changelog-cli": "^2.2.2",
36 | "cz-conventional-changelog": "^3.3.0",
37 | "eslint": "^6.8.0",
38 | "eslint-config-prettier": "^6.10.0",
39 | "eslint-plugin-import": "^2.20.1",
40 | "eslint-plugin-prettier": "^3.1.2",
41 | "husky": "^8.0.3",
42 | "lint-staged": "^10.0.8",
43 | "prettier": "^2.1.2"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | addGlobalClass: true,
4 | },
5 | /**
6 | * 组件的属性列表
7 | */
8 | properties: {
9 | isAllSelected: {
10 | type: Boolean,
11 | value: false,
12 | },
13 | totalAmount: {
14 | type: Number,
15 | value: 1,
16 | },
17 | totalGoodsNum: {
18 | type: Number,
19 | value: 0,
20 | observer(num) {
21 | const isDisabled = num == 0;
22 | setTimeout(() => {
23 | this.setData({
24 | isDisabled,
25 | });
26 | });
27 | },
28 | },
29 | totalDiscountAmount: {
30 | type: Number,
31 | value: 0,
32 | },
33 | bottomHeight: {
34 | type: Number,
35 | value: 100,
36 | },
37 | fixed: Boolean,
38 | },
39 | data: {
40 | isDisabled: false,
41 | },
42 |
43 | methods: {
44 | handleSelectAll() {
45 | const { isAllSelected } = this.data;
46 | this.setData({
47 | isAllSelected: !isAllSelected,
48 | });
49 | this.triggerEvent('handleSelectAll', {
50 | isAllSelected: isAllSelected,
51 | });
52 | },
53 |
54 | handleToSettle() {
55 | if (this.data.isDisabled) return;
56 | this.triggerEvent('handleToSettle');
57 | },
58 | },
59 | });
60 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "price": "/components/price/index",
5 | "t-icon": "tdesign-miniprogram/icon/icon"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/cart/components/cart-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 | 全选
11 |
12 |
13 | 总计
14 |
20 | (不含运费)
21 |
22 |
23 | 已优惠
24 |
25 |
26 |
27 |
28 | 去结算({{totalGoodsNum}})
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .cart-bar__placeholder {
2 | height: 100rpx;
3 | }
4 | .flex {
5 | display: flex;
6 | }
7 | .flex-v-center {
8 | align-items: center;
9 | }
10 | .flex1 {
11 | flex: 1;
12 | }
13 | .algin-bottom {
14 | text-align: end;
15 | }
16 | .cart-bar--fixed {
17 | position: fixed;
18 | left: 0;
19 | right: 0;
20 | z-index: 99;
21 | bottom: calc(100rpx + env(safe-area-inset-bottom));
22 | }
23 |
24 | .cart-bar {
25 | height: 112rpx;
26 | background-color: #fff;
27 | border-top: 1rpx solid #e5e5e5;
28 | padding: 16rpx 32rpx;
29 | box-sizing: border-box;
30 | font-size: 24rpx;
31 | line-height: 36rpx;
32 | color: #333;
33 | }
34 |
35 | .cart-bar .cart-bar__check {
36 | margin-right: 12rpx;
37 | }
38 |
39 | .cart-bar .cart-bar__total {
40 | margin-left: 24rpx;
41 | }
42 |
43 | .cart-bar .account-btn {
44 | width: 192rpx;
45 | height: 80rpx;
46 | border-radius: 40rpx;
47 | background-color: #fa4126;
48 | font-size: 28rpx;
49 | font-weight: bold;
50 | line-height: 80rpx;
51 | color: #ffffff;
52 | text-align: center;
53 | }
54 | .cart-bar .disabled-btn {
55 | background-color: #cccccc !important;
56 | }
57 | .cart-bar .hover-btn {
58 | opacity: 0.5;
59 | }
60 |
61 | .cart-bar__total .cart-bar__total--bold {
62 | font-size: 28rpx;
63 | line-height: 40rpx;
64 | color: #333;
65 | font-weight: bold;
66 | }
67 | .cart-bar__total .cart-bar__total--normal {
68 | font-size: 24rpx;
69 | line-height: 32rpx;
70 | color: #999;
71 | }
72 |
73 | .cart-bar__total .cart-bar__total--price {
74 | color: #fa4126;
75 | font-weight: bold;
76 | }
77 |
78 | .text-padding-right {
79 | padding-right: 4rpx;
80 | }
81 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-empty/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | properties: {
3 | imgUrl: {
4 | type: String,
5 | value:
6 | 'https://cdn-we-retail.ym.tencent.com/miniapp/template/empty-cart.png',
7 | },
8 | tip: {
9 | type: String,
10 | value: '购物车是空的',
11 | },
12 | btnText: {
13 | type: String,
14 | value: '去首页',
15 | },
16 | },
17 | data: {},
18 | methods: {
19 | handleClick() {
20 | this.triggerEvent('handleClick');
21 | },
22 | },
23 | });
24 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-empty/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-image": "/components/webp-image/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/cart/components/cart-empty/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{tip}}
4 | {{btnText}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-empty/index.wxss:
--------------------------------------------------------------------------------
1 | .cart-empty {
2 | padding: 64rpx 0rpx;
3 | display: flex;
4 | flex-direction: column;
5 | align-items: center;
6 | box-sizing: border-box;
7 | height: calc(100vh - 100rpx);
8 | background-color: #f5f5f5;
9 | }
10 | .cart-empty .cart-img {
11 | width: 160rpx;
12 | height: 160rpx;
13 | margin-bottom: 24rpx;
14 | }
15 |
16 | .cart-empty .tip {
17 | font-size: 28rpx;
18 | line-height: 40rpx;
19 | color: #999;
20 | margin-bottom: 24rpx;
21 | }
22 | .cart-empty .btn {
23 | width: 240rpx;
24 | height: 72rpx;
25 | border-radius: 36rpx;
26 | text-align: center;
27 | line-height: 72rpx;
28 | border: 2rpx solid #fa4126;
29 | color: #fa4126;
30 | background-color: transparent;
31 | font-size: 28rpx;
32 | font-weight: bold;
33 | }
34 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-group/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-toast": "tdesign-miniprogram/toast/toast",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-stepper": "tdesign-miniprogram/stepper/stepper",
7 | "swipeout": "/components/swipeout/index",
8 | "goods-card": "../../components/goods-card/index",
9 | "specs-popup": "../../components/specs-popup/index"
10 | }
11 | }
--------------------------------------------------------------------------------
/pages/cart/components/cart-group/index.wxs:
--------------------------------------------------------------------------------
1 | var hasPromotion = function (code) {
2 | return code && code !== 'EMPTY_PROMOTION';
3 | };
4 |
5 | module.exports.hasPromotion = hasPromotion;
6 |
--------------------------------------------------------------------------------
/pages/cart/components/cart-group/utils.wxs:
--------------------------------------------------------------------------------
1 | module.exports.slice = function(arr) {
2 | return arr.slice(0, 2);
3 | };
4 | module.exports.imgCut = function(url, width, height) {
5 | if (url && (url.slice(0, 5) === 'http:' || url.slice(0, 6) === 'https:' || url.slice(0, 2) === '//')) {
6 | var argsStr = 'imageMogr2/thumbnail/!' + width + 'x' + height + 'r';
7 | if (url.indexOf('?') > -1) {
8 | url = url + '&' + argsStr;
9 | } else {
10 | url = url + '?' + argsStr;
11 | }
12 | if (url.slice(0, 5) === 'http:') {
13 | url = 'https://' + url.slice(5)
14 | }
15 | if (url.slice(0, 2) === '//') {
16 | url = 'https:' + url
17 | }
18 | }
19 | return url;
20 | };
21 |
--------------------------------------------------------------------------------
/pages/cart/components/goods-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "price": "/components/price/index",
5 | "t-tag": "tdesign-miniprogram/tag/tag",
6 | "t-image": "/components/webp-image/index",
7 | "t-icon": "tdesign-miniprogram/icon/icon"
8 | }
9 | }
--------------------------------------------------------------------------------
/pages/cart/components/specs-popup/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | addGlobalClass: true,
4 | multipleSlots: true, // 在组件定义时的选项中启用多slot支持
5 | },
6 |
7 | properties: {
8 | show: {
9 | type: Boolean,
10 | value: false,
11 | },
12 | value: {
13 | type: String,
14 | value: '',
15 | },
16 | title: {
17 | type: String,
18 | observer(newVal) {
19 | this.setData({ 'goods.title': newVal });
20 | },
21 | },
22 | price: {
23 | type: String,
24 | value: '',
25 | observer(newVal) {
26 | this.setData({ 'goods.price': newVal });
27 | },
28 | },
29 | thumb: {
30 | type: String,
31 | value: '',
32 | observer(newVal) {
33 | this.setData({ 'goods.thumb': newVal });
34 | },
35 | },
36 | thumbMode: {
37 | type: String,
38 | value: 'aspectFit',
39 | },
40 | zIndex: {
41 | type: Number,
42 | value: 99,
43 | },
44 | specs: {
45 | type: Array,
46 | value: [],
47 | },
48 | },
49 |
50 | data: {
51 | goods: {
52 | title: '',
53 | thumb: '',
54 | price: '',
55 | hideKey: {
56 | originPrice: true,
57 | tags: true,
58 | specs: true,
59 | num: true,
60 | },
61 | },
62 | },
63 | methods: {
64 | onClose() {
65 | this.triggerEvent('close');
66 | },
67 |
68 | onCloseOver() {
69 | this.triggerEvent('closeover');
70 | },
71 | },
72 | });
73 |
--------------------------------------------------------------------------------
/pages/cart/components/specs-popup/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup",
5 | "goods-card": "../../components/goods-card/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/cart/components/specs-popup/index.wxml:
--------------------------------------------------------------------------------
1 |
7 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/pages/cart/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "购物车",
3 | "usingComponents": {
4 | "cart-group": "./components/cart-group/index",
5 | "cart-empty": "./components/cart-empty/index",
6 | "cart-bar": "./components/cart-bar/index",
7 | "t-toast": "tdesign-miniprogram/toast/toast",
8 | "t-dialog": "tdesign-miniprogram/dialog/dialog"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/cart/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/pages/cart/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | padding-bottom: 100rpx;
3 | }
4 |
5 | .gap {
6 | height: 100rpx;
7 | width: 100%;
8 | }
9 |
10 | .t-button {
11 | --td-button-default-color: #000;
12 | --td-button-primary-text-color: #fa4126;
13 | }
14 |
--------------------------------------------------------------------------------
/pages/coupon/components/coupon-card/index.js:
--------------------------------------------------------------------------------
1 | const statusMap = {
2 | default: { text: '去使用', theme: 'primary' },
3 | useless: { text: '已使用', theme: 'default' },
4 | disabled: { text: '已过期', theme: 'default' },
5 | };
6 | Component({
7 | options: {
8 | addGlobalClass: true,
9 | multipleSlots: true, // 在组件定义时的选项中启用多slot支持
10 | },
11 |
12 | externalClasses: ['coupon-class'],
13 |
14 | properties: {
15 | couponDTO: {
16 | type: Object,
17 | value: {}, // 优惠券数据
18 | },
19 | },
20 |
21 | data: {
22 | btnText: '',
23 | btnTheme: '',
24 | },
25 |
26 | observers: {
27 | couponDTO: function (couponDTO) {
28 | if (!couponDTO) {
29 | return;
30 | }
31 | const statusInfo = statusMap[couponDTO.status];
32 |
33 | this.setData({
34 | btnText: statusInfo.text,
35 | btnTheme: statusInfo.theme,
36 | });
37 | },
38 | },
39 |
40 | attached() {},
41 |
42 | methods: {
43 | // 跳转到详情页
44 | gotoDetail() {
45 | wx.navigateTo({
46 | url: `/pages/coupon/coupon-detail/index?id=${this.data.couponDTO.key}`,
47 | });
48 | },
49 |
50 | // 跳转到商品列表
51 | gotoGoodsList() {
52 | wx.navigateTo({
53 | url: `/pages/coupon/coupon-activity-goods/index?id=${this.data.couponDTO.key}`,
54 | });
55 | },
56 | },
57 | });
58 |
--------------------------------------------------------------------------------
/pages/coupon/components/coupon-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "ui-coupon-card": "../ui-coupon-card/index",
5 | "t-button": "tdesign-miniprogram/button/button"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/pages/coupon/components/coupon-card/index.wxml:
--------------------------------------------------------------------------------
1 |
12 |
13 | {{btnText}}
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/pages/coupon/components/coupon-card/index.wxss:
--------------------------------------------------------------------------------
1 | .coupon-btn-default {
2 | display: none;
3 | }
4 |
5 | .coupon-btn-primary {
6 | --td-button-extra-small-padding-horizontal: 26rpx;
7 | --td-button-primary-outline-color: #fa4126;
8 | --td-button-primary-outline-border-color: #fa4126;
9 | }
10 |
--------------------------------------------------------------------------------
/pages/coupon/components/floating-button/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | data: { icon: 'cart' },
3 |
4 | properties: {
5 | count: {
6 | type: Number,
7 | },
8 | },
9 |
10 | methods: {
11 | goToCart() {
12 | wx.switchTab({
13 | url: '/pages/cart/index',
14 | });
15 | },
16 | },
17 | });
18 |
--------------------------------------------------------------------------------
/pages/coupon/components/floating-button/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/coupon/components/floating-button/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 | {{count}}
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/pages/coupon/components/floating-button/index.wxss:
--------------------------------------------------------------------------------
1 | .floating-button {
2 | position: fixed;
3 | right: 20rpx;
4 | bottom: 108rpx;
5 | }
6 |
7 | .floating-button .floating-inner-container {
8 | display: flex;
9 | align-items: center;
10 | justify-content: center;
11 | height: 96rpx;
12 | width: 96rpx;
13 | background-color: rgba(0, 0, 0, 0.8);
14 | opacity: 0.7;
15 | border-radius: 48rpx;
16 | }
17 |
18 | .floating-button .floating-right-top {
19 | position: absolute;
20 | right: 0rpx;
21 | top: 0rpx;
22 | height: 28rpx;
23 | background: #fa4126;
24 | border-radius: 64rpx;
25 | font-weight: bold;
26 | font-size: 22rpx;
27 | line-height: 28rpx;
28 | color: #fff;
29 | padding: 0 8rpx;
30 | }
31 |
--------------------------------------------------------------------------------
/pages/coupon/components/ui-coupon-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-image": "/components/webp-image/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/coupon/coupon-activity-goods/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "活动商品",
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-popup": "tdesign-miniprogram/popup/popup",
6 | "t-toast": "tdesign-miniprogram/toast/toast",
7 | "goods-list": "/components/goods-list/index",
8 | "floating-button": "../components/floating-button/index"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/coupon/coupon-activity-goods/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 以下商品可使用
5 | {{couponTypeDesc}}
6 | 优惠券
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/pages/coupon/coupon-activity-goods/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | background-color: #f5f5f5;
3 | }
4 |
5 | .coupon-page-container .notice-bar-content {
6 | display: flex;
7 | flex-direction: row;
8 | align-items: center;
9 | padding: 8rpx 0;
10 | }
11 |
12 | .coupon-page-container .notice-bar-text {
13 | font-size: 26rpx;
14 | line-height: 36rpx;
15 | font-weight: 400;
16 | color: #666666;
17 | margin-left: 24rpx;
18 | margin-right: 12rpx;
19 | }
20 |
21 | .coupon-page-container .notice-bar-text .height-light {
22 | color: #fa550f;
23 | }
24 |
25 | .coupon-page-container .popup-content-wrap {
26 | background-color: #fff;
27 | border-top-left-radius: 20rpx;
28 | border-top-right-radius: 20rpx;
29 | }
30 |
31 | .coupon-page-container .popup-content-title {
32 | font-size: 32rpx;
33 | color: #333;
34 | text-align: center;
35 | height: 104rpx;
36 | line-height: 104rpx;
37 | position: relative;
38 | }
39 |
40 | .coupon-page-container .desc-group-wrap {
41 | padding-bottom: env(safe-area-inset-bottom);
42 | }
43 |
44 | .coupon-page-container .desc-group-wrap .item-wrap {
45 | margin: 0 30rpx 30rpx;
46 | }
47 |
48 | .coupon-page-container .desc-group-wrap .item-title {
49 | font-size: 26rpx;
50 | color: #333;
51 | font-weight: 500;
52 | }
53 |
54 | .coupon-page-container .desc-group-wrap .item-label {
55 | font-size: 24rpx;
56 | color: #666;
57 | margin-top: 12rpx;
58 | white-space: pre-line;
59 | word-break: break-all;
60 | line-height: 34rpx;
61 | }
62 |
63 | .coupon-page-container .goods-list-container {
64 | margin: 0 24rpx 24rpx;
65 | }
66 |
67 | .coupon-page-container .goods-list-wrap {
68 | background: #f5f5f5 !important;
69 | }
70 |
--------------------------------------------------------------------------------
/pages/coupon/coupon-detail/index.js:
--------------------------------------------------------------------------------
1 | import { fetchCouponDetail } from '../../../services/coupon/index';
2 |
3 | Page({
4 | data: {
5 | detail: null,
6 | storeInfoList: [],
7 | storeInfoStr: '',
8 | showStoreInfoList: false,
9 | },
10 |
11 | id: '',
12 |
13 | onLoad(query) {
14 | const id = parseInt(query.id);
15 | this.id = id;
16 | this.getGoodsList(id);
17 | },
18 |
19 | getGoodsList(id) {
20 | fetchCouponDetail(id).then(({ detail }) => {
21 | this.setData({
22 | detail,
23 | });
24 | });
25 | },
26 |
27 | navGoodListHandle() {
28 | wx.navigateTo({
29 | url: `/pages/coupon/coupon-activity-goods/index?id=${this.id}`,
30 | });
31 | },
32 | });
33 |
--------------------------------------------------------------------------------
/pages/coupon/coupon-detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "优惠券详情",
3 | "usingComponents": {
4 | "coupon-card": "../components/coupon-card/index",
5 | "t-cell": "tdesign-miniprogram/cell/cell",
6 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
7 | "t-button": "tdesign-miniprogram/button/button",
8 | "t-icon": "tdesign-miniprogram/icon/icon"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/coupon/coupon-detail/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
24 |
32 |
40 |
41 |
42 |
43 | 查看可用商品
44 |
45 |
46 |
--------------------------------------------------------------------------------
/pages/coupon/coupon-list/index.js:
--------------------------------------------------------------------------------
1 | import { fetchCouponList } from '../../../services/coupon/index';
2 |
3 | Page({
4 | data: {
5 | status: 0,
6 | list: [
7 | {
8 | text: '可使用',
9 | key: 0,
10 | },
11 | {
12 | text: '已使用',
13 | key: 1,
14 | },
15 | {
16 | text: '已失效',
17 | key: 2,
18 | },
19 | ],
20 |
21 | couponList: [],
22 | },
23 |
24 | onLoad() {
25 | this.init();
26 | },
27 |
28 | init() {
29 | this.fetchList();
30 | },
31 |
32 | fetchList(status = this.data.status) {
33 | let statusInFetch = '';
34 | switch (Number(status)) {
35 | case 0: {
36 | statusInFetch = 'default';
37 | break;
38 | }
39 | case 1: {
40 | statusInFetch = 'useless';
41 | break;
42 | }
43 | case 2: {
44 | statusInFetch = 'disabled';
45 | break;
46 | }
47 | default: {
48 | throw new Error(`unknown fetchStatus: ${statusInFetch}`);
49 | }
50 | }
51 | fetchCouponList(statusInFetch).then((couponList) => {
52 | this.setData({ couponList });
53 | });
54 | },
55 |
56 | tabChange(e) {
57 | const { value } = e.detail;
58 |
59 | this.setData({ status: value });
60 | this.fetchList(value);
61 | },
62 |
63 | goCouponCenterHandle() {
64 | wx.showToast({ title: '去领券中心', icon: 'none' });
65 | },
66 |
67 | onPullDownRefresh_() {
68 | this.setData(
69 | {
70 | couponList: [],
71 | },
72 | () => {
73 | this.fetchList();
74 | },
75 | );
76 | },
77 | });
78 |
--------------------------------------------------------------------------------
/pages/coupon/coupon-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "优惠券",
3 | "usingComponents": {
4 | "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh",
5 | "t-tabs": "tdesign-miniprogram/tabs/tabs",
6 | "t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel",
7 | "t-icon": "tdesign-miniprogram/icon/icon",
8 | "coupon-card": "../components/coupon-card/index"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/coupon/coupon-list/index.wxml:
--------------------------------------------------------------------------------
1 |
10 |
18 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 领券中心
33 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/c-sidebar-item/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | relations: {
3 | '../../c-sidebar/index': {
4 | type: 'ancestor',
5 | linked(target) {
6 | this.parent = target;
7 | },
8 | },
9 | },
10 |
11 | externalClasses: ['custom-class'],
12 | properties: {
13 | title: String,
14 | disabled: Boolean,
15 | },
16 |
17 | data: {
18 | topRightRadius: false,
19 | bottomRightRadius: false,
20 | },
21 |
22 | methods: {
23 | setActive(selected) {
24 | return this.setData({ selected });
25 | },
26 | onClick() {
27 | const { parent } = this;
28 |
29 | if (!parent || this.properties.disabled) {
30 | return;
31 | }
32 |
33 | const index = parent.children.indexOf(this);
34 |
35 | parent.setActive(index).then(() => {
36 | this.triggerEvent('click', index);
37 | parent.triggerEvent('change', { index });
38 | });
39 | },
40 | setTopRightRadius(val) {
41 | return this.setData({
42 | topRightRadius: val,
43 | });
44 | },
45 | setBottomRightRadius(val) {
46 | return this.setData({
47 | bottomRightRadius: val,
48 | });
49 | },
50 | },
51 | });
52 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/c-sidebar-item/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/c-sidebar-item/index.wxml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/c-sidebar-item/index.wxss:
--------------------------------------------------------------------------------
1 | .c-sidebar-item {
2 | display: flex;
3 | justify-content: center;
4 | text-align: center;
5 | background-color: #f5f5f5;
6 | color: #222427;
7 | padding: 20rpx 0;
8 | font-size: 26rpx;
9 | }
10 |
11 | .c-sidebar-item.active {
12 | position: relative;
13 | background: white;
14 | }
15 |
16 | .c-sidebar-item.active::before {
17 | content: '';
18 | position: absolute;
19 | width: 6rpx;
20 | height: 48rpx;
21 | background-color: #fa4126;
22 | left: 0;
23 | top: 50%;
24 | transform: translate(0, -50%);
25 | border-radius: 64rpx;
26 | }
27 |
28 | .c-sidebar-item__text {
29 | width: 136rpx;
30 | height: 36rpx;
31 | padding: 8rpx 0;
32 | line-height: 36rpx;
33 | text-align: center;
34 | font-size: 28rpx;
35 | color: #666666;
36 | }
37 |
38 | .c-sidebar-item.active .c-sidebar-item__text {
39 | background-color: white;
40 | border-radius: 36rpx;
41 | color: #fa4126;
42 | }
43 |
44 | .text-overflow {
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | white-space: nowrap;
48 | }
49 |
50 | .top-right-radius {
51 | border-top-right-radius: 16rpx;
52 | }
53 |
54 | .bottom-right-radius {
55 | border-bottom-right-radius: 16rpx;
56 | }
57 |
58 | .c-sidebar-item-container {
59 | background-color: white;
60 | }
61 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true
3 | }
4 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/index.wxml:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-sidebar/index.wxss:
--------------------------------------------------------------------------------
1 | .c-sidebar {
2 | width: 176rpx;
3 | height: 100vh;
4 | }
5 | .c-sidebar::-webkit-scrollbar {
6 | width: 0;
7 | height: 0;
8 | color: transparent;
9 | }
10 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/c-tabbar-more/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['custom-class'],
3 |
4 | properties: {
5 | tabList: Array,
6 | },
7 |
8 | data: {
9 | unfolded: false,
10 | boardMaxHeight: null,
11 | },
12 | attached() {
13 | wx.createSelectorQuery()
14 | .in(this)
15 | .select('.c-tabbar-more')
16 | .boundingClientRect((rect) => {
17 | this.setData({ boardMaxHeight: rect.height });
18 | })
19 | .exec();
20 | },
21 |
22 | methods: {
23 | changeFold() {
24 | this.setData({
25 | unfolded: !this.data.unfolded,
26 | });
27 | const { unfolded } = this.data;
28 | this.triggerEvent('change', { unfolded });
29 | },
30 |
31 | onSelect(event) {
32 | const activeKey = event.currentTarget.dataset.index;
33 | this.triggerEvent('select', activeKey);
34 | this.changeFold();
35 | },
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/c-tabbar-more/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
5 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/c-tabbar-more/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
20 | {{ item.name }}
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "c-tabbar-more": "./c-tabbar-more/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
19 | {{ item.name }}
20 |
21 |
22 |
23 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/components/c-tabbar/index.wxss:
--------------------------------------------------------------------------------
1 | .c-tabbar {
2 | width: 100%;
3 | height: 100%;
4 | position: relative;
5 | --tabbar-height: 100rpx;
6 | --tabbar-fontsize: 28rpx;
7 | --tabbar-background-color: white;
8 | }
9 | .c-tabbar__inner {
10 | display: flex;
11 | flex-flow: row nowrap;
12 | }
13 | .c-tabbar__scroll {
14 | position: relative;
15 | }
16 | .c-tabbar__scroll::after {
17 | content: '';
18 | display: block;
19 | position: absolute;
20 | width: 100%;
21 | left: 0;
22 | bottom: -1px;
23 | height: 1px;
24 | background-color: #eee;
25 | z-index: 1;
26 | }
27 | .c-tabbar__inner.c-tabbar__inner_more::after {
28 | content: '';
29 | display: block;
30 | width: 100rpx;
31 | height: 100rpx;
32 | flex: none;
33 | }
34 | .c-tabbar-item {
35 | flex: none;
36 | height: 100rpx;
37 | color: #282828;
38 | font-size: 28rpx;
39 | padding: 0 20rpx;
40 | }
41 | .c-tabbar-item.active:not(.disabled) {
42 | color: #0071ce;
43 | position: relative;
44 | }
45 | .c-tabbar-item.disabled {
46 | color: #ccc;
47 | }
48 | .c-tabbar-item__text {
49 | width: 100%;
50 | text-align: center;
51 | height: 100rpx;
52 | line-height: 100rpx;
53 | }
54 |
--------------------------------------------------------------------------------
/pages/goods/category/components/goods-category/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "c-tabbar": "./components/c-tabbar/index",
5 | "c-sidebar": "./components/c-sidebar/index",
6 | "c-sidebar-item": "./components/c-sidebar/c-sidebar-item/index",
7 | "t-image": "/components/webp-image/index"
8 | }
9 | }
--------------------------------------------------------------------------------
/pages/goods/category/index.js:
--------------------------------------------------------------------------------
1 | import { getCategoryList } from '../../../services/good/fetchCategoryList';
2 | Page({
3 | data: {
4 | list: [],
5 | },
6 | async init() {
7 | try {
8 | const result = await getCategoryList();
9 | this.setData({
10 | list: result,
11 | });
12 | } catch (error) {
13 | console.error('err:', error);
14 | }
15 | },
16 |
17 | onShow() {
18 | this.getTabBar().init();
19 | },
20 | onChange() {
21 | wx.navigateTo({
22 | url: '/pages/goods/list/index',
23 | });
24 | },
25 | onLoad() {
26 | this.init(true);
27 | },
28 | });
29 |
--------------------------------------------------------------------------------
/pages/goods/category/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "分类",
3 | "usingComponents": {
4 | "goods-category": "./components/goods-category/index"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/pages/goods/category/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/pages/goods/category/index.wxss:
--------------------------------------------------------------------------------
1 | .tabbar-position {
2 | position: fixed !important;
3 | bottom: 0;
4 | left: 0;
5 | width: 100%;
6 | }
7 |
8 | .wrap {
9 | height: 100vh;
10 | overflow: hidden;
11 | }
12 | .goods-category-class {
13 | background-color: #f6f6f6 !important;
14 | height: 100%;
15 | }
16 | .goods-category-class .goods-category-normal-item-container-item {
17 | margin-top: 20rpx;
18 | }
19 |
20 | page {
21 | min-height: none;
22 | padding-bottom: 0;
23 | }
24 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/images-videos/assets/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tencent/tdesign-miniprogram-starter-retail/ef92ec100f82dfb724a62a08dfbc1defb50183c2/pages/goods/comments/components/comments-card/components/images-videos/assets/play.png
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/images-videos/index.js:
--------------------------------------------------------------------------------
1 | // pages/goods/comments/components/comments-card/images-videos/index.js
2 | Component({
3 | /**
4 | * 组件的属性列表
5 | */
6 | properties: {
7 | resources: {
8 | type: Array,
9 | value: [],
10 | },
11 | },
12 |
13 | /**
14 | * 组件的初始数据
15 | */
16 | data: {
17 | classType: 'single',
18 | },
19 |
20 | observers: {
21 | resources: function (newVal) {
22 | if (newVal.length <= 1) {
23 | this.setData({ classType: 'single' });
24 | } else if (newVal.length === 2) {
25 | this.setData({ classType: 'double' });
26 | } else {
27 | this.setData({ classType: 'multiple' });
28 | }
29 | },
30 | },
31 |
32 | /**
33 | * 组件的方法列表
34 | */
35 | methods: {},
36 | });
37 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/images-videos/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "my-video": "../my-video/index",
5 | "t-image": "/components/webp-image/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/images-videos/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/images-videos/index.wxss:
--------------------------------------------------------------------------------
1 | .resource-item-single {
2 | width: 360rpx;
3 | height: 360rpx;
4 | border-radius: 8rpx;
5 | }
6 |
7 | .resource-item-double {
8 | width: 334rpx;
9 | height: 334rpx;
10 | border-radius: 8rpx;
11 | }
12 |
13 | .resource-item-multiple {
14 | width: 218rpx;
15 | height: 218rpx;
16 | border-radius: 8rpx;
17 | }
18 |
19 | .resource-container-single {
20 | padding-left: 0;
21 | padding-top: 0;
22 | }
23 |
24 | .resource-container-double {
25 | padding-left: 18rpx;
26 | padding-top: 18rpx;
27 | }
28 |
29 | .resource-container-multiple {
30 | padding-left: 16rpx;
31 | padding-top: 16rpx;
32 | }
33 |
34 | .container-single {
35 | margin-left: 0;
36 | }
37 |
38 | .container-double {
39 | margin-left: -18rpx;
40 | margin-top: -18rpx;
41 | }
42 |
43 | .container-multiple {
44 | margin-left: -16rpx;
45 | margin-top: -16rpx;
46 | }
47 |
48 | .resource-container {
49 | display: flex;
50 | }
51 |
52 | .play-icon {
53 | width: 96rpx;
54 | height: 96rpx;
55 | }
56 |
57 | .images-videos-container {
58 | display: flex;
59 | flex-wrap: wrap;
60 | }
61 |
62 | .image {
63 | border-radius: 8rpx;
64 | }
65 |
66 | .cover-img-container {
67 | background-color: white;
68 | }
69 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/my-video/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['my-video', 'my-cover-img', 'my-play-icon'],
3 | properties: {
4 | videoSrc: { type: String },
5 | },
6 | data: {
7 | isShow: true,
8 | },
9 |
10 | options: {
11 | multipleSlots: true, // 在组件定义时的选项中启用多slot支持
12 | },
13 |
14 | attached() {
15 | this.videoContext = wx.createVideoContext('myVideo', this);
16 | },
17 |
18 | fullScreen: false,
19 |
20 | methods: {
21 | // 点击封面自定义播放按钮时触发
22 | bindplay(e) {
23 | this.setData({
24 | isShow: false,
25 | });
26 | this.videoContext.play();
27 | this.triggerEvent('play', e);
28 | },
29 |
30 | bindplayByVideo(e) {
31 | this.setData({
32 | isShow: false,
33 | });
34 | this.triggerEvent('play', e);
35 | },
36 |
37 | // 监听播放到末尾时触发
38 | bindended(e) {
39 | if (!this.fullScreen) {
40 | this.setData({
41 | isShow: true,
42 | });
43 | }
44 | this.triggerEvent('ended', e);
45 | },
46 | // 监听暂停播放时触发
47 | bindpause(e) {
48 | this.triggerEvent('pause', e);
49 | },
50 | bindfullscreenchange(e) {
51 | const fullScreen = e?.detail?.fullScreen;
52 | this.fullScreen = fullScreen;
53 | },
54 | },
55 | });
56 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/my-video/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/my-video/index.wxml:
--------------------------------------------------------------------------------
1 |
27 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/components/my-video/index.wxss:
--------------------------------------------------------------------------------
1 | .video .video_cover {
2 | width: 100%;
3 | height: 100%;
4 | position: relative;
5 | }
6 |
7 | .video .video_play_icon {
8 | position: absolute;
9 | left: 50%;
10 | top: 50%;
11 | transform: translate(-50%, -50%);
12 | z-index: 5;
13 | }
14 |
15 | .video .video_txt {
16 | margin: 10rpx auto;
17 | }
18 |
19 | .video {
20 | display: flex;
21 | }
22 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class'],
3 | options: {
4 | multipleSlots: true,
5 | },
6 | properties: {
7 | goodsDetailInfo: {
8 | type: String,
9 | value: '',
10 | },
11 | sellerReply: {
12 | type: String,
13 | value: '',
14 | },
15 | userHeadUrl: {
16 | type: String,
17 | value: '',
18 | },
19 | userName: {
20 | type: String,
21 | default: '',
22 | },
23 | commentContent: {
24 | type: String,
25 | value: '',
26 | },
27 | commentScore: {
28 | type: Number,
29 | value: 0,
30 | },
31 | commentTime: {
32 | type: String,
33 | value: '',
34 | },
35 | commentResources: {
36 | type: Array,
37 | value: [],
38 | },
39 | },
40 |
41 | data: {
42 | showMoreStatus: false,
43 | showContent: false,
44 | hideText: false,
45 | eleHeight: null,
46 | overText: false,
47 | isDisabled: true,
48 | startColors: ['#FFC51C', '#DDDDDD'],
49 | },
50 | methods: {},
51 | });
52 |
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-rate": "tdesign-miniprogram/rate/rate",
5 | "images-videos": "./components/images-videos",
6 | "t-image": "/components/webp-image/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/goods/comments/components/comments-card/index.wxml:
--------------------------------------------------------------------------------
1 |
28 |
--------------------------------------------------------------------------------
/pages/goods/comments/create/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "评价商品",
3 | "usingComponents": {
4 | "t-image": "/components/webp-image/index",
5 | "t-rate": "tdesign-miniprogram/rate/rate",
6 | "t-textarea": "tdesign-miniprogram/textarea/textarea",
7 | "t-checkbox": "tdesign-miniprogram/checkbox/checkbox",
8 | "t-button": "tdesign-miniprogram/button/button",
9 | "t-upload": "tdesign-miniprogram/upload/upload",
10 | "t-icon": "tdesign-miniprogram/icon/icon",
11 | "t-toast": "tdesign-miniprogram/toast/toast"
12 | }
13 | }
--------------------------------------------------------------------------------
/pages/goods/comments/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "全部评价",
3 | "usingComponents": {
4 | "t-tag": "tdesign-miniprogram/tag/tag",
5 | "comments-card": "./components/comments-card/index",
6 | "t-load-more": "/components/load-more/index"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/pages/goods/comments/index.wxss:
--------------------------------------------------------------------------------
1 | /* 层级定义
2 | @z-index-0: 1;
3 | @z-index-1: 100;
4 | @z-index-2: 200;
5 | @z-index-5: 500;
6 | @z-index-component: 1000; // 通用组件级别
7 | @z-index-dropdown: @z-index-component;
8 | @z-index-sticky: @z-index-component + 20;
9 | @z-index-fixed: @z-index-component + 30;
10 | @z-index-modal-backdrop:@z-index-component + 40;
11 | @z-index-modal:@z-index-component + 50;
12 | @z-index-popover:@z-index-component + 60;
13 | @z-index-tooltip:@z-index-component + 70;
14 | */
15 | /* var() css变量适配*/
16 | page {
17 | background-color: #FFFFFF;
18 | }
19 |
20 | .comments-header {
21 | display: flex;
22 | flex-wrap: wrap;
23 | padding: 32rpx 32rpx 0rpx;
24 | background-color: #fff;
25 | margin-top: -24rpx;
26 | margin-left: -24rpx;
27 | }
28 |
29 | .comments-header-tag {
30 | margin-top: 24rpx;
31 | margin-left: 24rpx;
32 | height: 56rpx !important;
33 | font-size: 24rpx !important;
34 | justify-content: center;
35 | background-color: #F5F5F5 !important;
36 | border-radius: 8rpx !important;
37 | border: 1px solid #F5F5F5 !important;
38 | }
39 |
40 | .comments-header-active {
41 | background-color: #FFECE9 !important;
42 | color: #FA4126 !important;
43 | border: 1px solid #FA4126 !important;
44 | }
45 |
46 | .no-more {
47 | padding-left: 20rpx;
48 | padding-right: 20rpx;
49 | }
--------------------------------------------------------------------------------
/pages/goods/details/components/buy-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-sold-out', 'wr-class'],
3 |
4 | options: { multipleSlots: true },
5 |
6 | properties: {
7 | soldout: {
8 | // 商品是否下架
9 | type: Boolean,
10 | value: false,
11 | },
12 | jumpArray: {
13 | type: Array,
14 | value: [],
15 | },
16 | isStock: {
17 | type: Boolean,
18 | value: true,
19 | }, // 是否有库存
20 | isSlotButton: {
21 | type: Boolean,
22 | value: false,
23 | }, // 是否开启按钮插槽
24 | shopCartNum: {
25 | type: Number, // 购物车气泡数量
26 | },
27 | buttonType: {
28 | type: Number,
29 | value: 0,
30 | },
31 | minDiscountPrice: {
32 | type: String,
33 | value: '',
34 | },
35 | minSalePrice: {
36 | type: String,
37 | value: '',
38 | },
39 | },
40 |
41 | data: {
42 | fillPrice: false,
43 | },
44 |
45 | methods: {
46 | toAddCart() {
47 | const { isStock } = this.properties;
48 | if (!isStock) return;
49 | this.triggerEvent('toAddCart');
50 | },
51 |
52 | toBuyNow(e) {
53 | const { isStock } = this.properties;
54 | if (!isStock) return;
55 | this.triggerEvent('toBuyNow', e);
56 | },
57 |
58 | toNav(e) {
59 | const { url } = e.currentTarget.dataset;
60 | return this.triggerEvent('toNav', {
61 | e,
62 | url,
63 | });
64 | },
65 | },
66 | });
67 |
--------------------------------------------------------------------------------
/pages/goods/details/components/buy-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/goods/details/components/buy-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | {{soldout ? '商品已下架' : '商品已售馨'}}
3 |
4 |
38 |
39 |
--------------------------------------------------------------------------------
/pages/goods/details/components/goods-specs-popup/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-image": "/components/webp-image/index",
7 | "t-stepper": "tdesign-miniprogram/stepper/stepper",
8 | "t-toast": "tdesign-miniprogram/toast/toast"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/goods/details/components/promotion-popup/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | multipleSlots: true,
4 | },
5 |
6 | properties: {
7 | list: Array,
8 | title: {
9 | type: String,
10 | value: '促销说明',
11 | },
12 | show: {
13 | type: Boolean,
14 | },
15 | },
16 |
17 | // data: {
18 | // list: [],
19 | // },
20 |
21 | methods: {
22 | change(e) {
23 | const { index } = e.currentTarget.dataset;
24 | this.triggerEvent('promotionChange', {
25 | index,
26 | });
27 | },
28 |
29 | closePromotionPopup() {
30 | this.triggerEvent('closePromotionPopup', {
31 | show: false,
32 | });
33 | },
34 | },
35 | });
36 |
--------------------------------------------------------------------------------
/pages/goods/details/components/promotion-popup/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup",
5 | "t-icon": "tdesign-miniprogram/icon/icon"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/goods/details/components/promotion-popup/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/pages/goods/details/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "商品详情",
3 | "usingComponents": {
4 | "t-image": "/components/webp-image/index",
5 | "t-tag": "tdesign-miniprogram/tag/tag",
6 | "t-toast": "tdesign-miniprogram/toast/toast",
7 | "t-rate": "tdesign-miniprogram/rate/rate",
8 | "t-swiper": "tdesign-miniprogram/swiper/swiper",
9 | "t-swiper-nav": "tdesign-miniprogram/swiper-nav/swiper-nav",
10 | "t-button": "tdesign-miniprogram/button/button",
11 | "t-icon": "tdesign-miniprogram/icon/icon",
12 | "t-popup": "tdesign-miniprogram/popup/popup",
13 | "price": "/components/price/index",
14 | "buy-bar": "./components/buy-bar/index",
15 | "promotion-popup": "./components/promotion-popup/index",
16 | "goods-specs-popup": "./components/goods-specs-popup/index"
17 | }
18 | }
--------------------------------------------------------------------------------
/pages/goods/list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "商品列表",
3 | "usingComponents": {
4 | "t-input": "tdesign-miniprogram/input/input",
5 | "t-empty": "tdesign-miniprogram/empty/empty",
6 | "t-toast": "tdesign-miniprogram/toast/toast",
7 | "goods-list": "/components/goods-list/index",
8 | "filter": "/components/filter/index",
9 | "filter-popup": "/components/filter-popup/index",
10 | "load-more": "/components/load-more/index"
11 | }
12 | }
--------------------------------------------------------------------------------
/pages/goods/result/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "搜索",
3 | "usingComponents": {
4 | "t-search": "tdesign-miniprogram/search/search",
5 | "t-input": "tdesign-miniprogram/input/input",
6 | "t-empty": "tdesign-miniprogram/empty/empty",
7 | "t-toast": "tdesign-miniprogram/toast/toast",
8 | "goods-list": "/components/goods-list/index",
9 | "filter": "/components/filter/index",
10 | "filter-popup": "/components/filter-popup/index",
11 | "load-more": "/components/load-more/index",
12 | "t-icon": "tdesign-miniprogram/icon/icon"
13 | },
14 | "onReachBottomDistance": 50
15 | }
--------------------------------------------------------------------------------
/pages/goods/search/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "搜索",
3 | "usingComponents": {
4 | "t-search": "tdesign-miniprogram/search/search",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-dialog": "tdesign-miniprogram/dialog/dialog"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/pages/home/home.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "首页",
3 | "onReachBottomDistance": 10,
4 | "backgroundTextStyle": "light",
5 | "enablePullDownRefresh": true,
6 | "usingComponents": {
7 | "t-search": "tdesign-miniprogram/search/search",
8 | "t-loading": "tdesign-miniprogram/loading/loading",
9 | "t-swiper": "tdesign-miniprogram/swiper/swiper",
10 | "t-swiper-nav": "tdesign-miniprogram/swiper-nav/swiper-nav",
11 | "t-image": "/components/webp-image/index",
12 | "t-icon": "tdesign-miniprogram/icon/icon",
13 | "t-toast": "tdesign-miniprogram/toast/toast",
14 | "t-tabs": "tdesign-miniprogram/tabs/tabs",
15 | "t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel",
16 | "goods-list": "/components/goods-list/index",
17 | "load-more": "/components/load-more/index"
18 | }
19 | }
--------------------------------------------------------------------------------
/pages/home/readme:
--------------------------------------------------------------------------------
1 | 首页功能设定
2 | 1. loading入场
3 | 2. 下拉刷新
4 | 3. 搜索栏
5 | 4. 分类切换
6 | 5. 商品列表
7 | 6. 规格弹层
8 | 7. 加载更多
--------------------------------------------------------------------------------
/pages/order/after-service-detail/api.js:
--------------------------------------------------------------------------------
1 | import { resp } from '../after-service-list/api';
2 | import dayjs from 'dayjs';
3 | import { mockIp, mockReqId } from '../../../utils/mock';
4 |
5 | export const formatTime = (date, template) => dayjs(date).format(template);
6 |
7 | export function getRightsDetail({ rightsNo }) {
8 | const _resq = {
9 | data: {},
10 | code: 'Success',
11 | msg: null,
12 | requestId: mockReqId(),
13 | clientIp: mockIp(),
14 | rt: 79,
15 | success: true,
16 | };
17 | _resq.data =
18 | resp.data.dataList.filter((item) => item.rights.rightsNo === rightsNo) ||
19 | {};
20 | return Promise.resolve(_resq);
21 | }
22 |
23 | export function cancelRights() {
24 | const _resq = {
25 | data: {},
26 | code: 'Success',
27 | msg: null,
28 | requestId: mockReqId(),
29 | clientIp: mockIp(),
30 | rt: 79,
31 | success: true,
32 | };
33 | return Promise.resolve(_resq);
34 | }
35 |
--------------------------------------------------------------------------------
/pages/order/after-service-detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "",
3 | "usingComponents": {
4 | "wr-loading-content": "/components/loading-content/index",
5 | "wr-price": "/components/price/index",
6 | "wr-service-goods-card": "../components/order-goods-card/index",
7 | "t-cell": "tdesign-miniprogram/cell/cell",
8 | "t-icon": "tdesign-miniprogram/icon/icon",
9 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
10 | "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh",
11 | "t-grid": "tdesign-miniprogram/grid/grid",
12 | "t-grid-item": "tdesign-miniprogram/grid-item/grid-item",
13 | "t-toast": "tdesign-miniprogram/toast/toast",
14 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
15 | "t-input": "tdesign-miniprogram/input/input",
16 | "t-swiper": "tdesign-miniprogram/swiper/swiper",
17 | "t-swiper-nav": "tdesign-miniprogram/swiper-nav/swiper-nav",
18 | "wr-after-service-button-bar": "../components/after-service-button-bar/index",
19 | "t-image": "/components/webp-image/index"
20 | }
21 | }
--------------------------------------------------------------------------------
/pages/order/after-service-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "退款/售后",
3 | "usingComponents": {
4 | "wr-load-more": "/components/load-more/index",
5 | "wr-after-service-button-bar": "../components/after-service-button-bar/index",
6 | "wr-price": "/components/price/index",
7 | "wr-order-card": "../components/order-card/index",
8 | "wr-goods-card": "../components/goods-card/index",
9 | "t-icon": "tdesign-miniprogram/icon/icon",
10 | "t-toast": "tdesign-miniprogram/toast/toast",
11 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
12 | "t-empty": "tdesign-miniprogram/empty/empty",
13 | "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh"
14 | }
15 | }
--------------------------------------------------------------------------------
/pages/order/apply-service/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "选择售后类型",
3 | "usingComponents": {
4 | "wr-price": "/components/price/index",
5 | "wr-order-goods-card": "../components/order-goods-card/index",
6 | "wr-reason-sheet": "../components/reason-sheet/index",
7 | "t-cell": "tdesign-miniprogram/cell/cell",
8 | "t-icon": "tdesign-miniprogram/icon/icon",
9 | "t-toast": "tdesign-miniprogram/toast/toast",
10 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
11 | "t-button": "tdesign-miniprogram/button/button",
12 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
13 | "t-stepper": "tdesign-miniprogram/stepper/stepper",
14 | "t-popup": "tdesign-miniprogram/popup/popup",
15 | "t-textarea": "tdesign-miniprogram/textarea/textarea",
16 | "t-input": "tdesign-miniprogram/input/input",
17 | "t-upload": "tdesign-miniprogram/upload/upload"
18 | }
19 | }
--------------------------------------------------------------------------------
/pages/order/components/after-service-button-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-button": "tdesign-miniprogram/button/button"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/pages/order/components/after-service-button-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 | {{leftBtn.name}}
14 |
15 |
16 |
17 |
30 | {{rightBtn.name}}
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/pages/order/components/after-service-button-bar/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | width: 100%;
3 | }
4 | .btn-bar {
5 | display: flex;
6 | justify-content: space-between;
7 | align-items: center;
8 | line-height: 1;
9 | }
10 | .btn-bar .order-btn {
11 | background-color: inherit;
12 | font-size: 26rpx;
13 | padding: 16rpx 28rpx;
14 | line-height: 1;
15 | border-radius: unset;
16 | min-width: 160rpx;
17 | border-radius: 32rpx;
18 | height: 60rpx;
19 | margin-right: 10rpx;
20 | }
21 |
22 | .btn-bar .left .order-btn:not(:first-child),
23 | .btn-bar .right .order-btn:not(:first-child) {
24 | margin-left: 20rpx;
25 | }
26 | .btn-bar .left .delete-btn {
27 | font-size: 22rpx;
28 | }
29 | .btn-bar .left .delete-btn::after {
30 | display: none;
31 | }
32 |
33 | .btn-bar .right .normal {
34 | --td-button-default-color: #333333;
35 | --td-button-default-border-color: #dddddd;
36 | }
37 |
38 | .btn-bar .right .primary {
39 | --td-button-default-color: #fff;
40 | --td-button-default-bg-color: #fa4126;
41 | --td-button-default-border-color: #fa4126;
42 | --td-button-default-active-bg-color: #fa42269c;
43 | }
44 |
--------------------------------------------------------------------------------
/pages/order/components/customer-service/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['wr-class'],
3 |
4 | properties: {
5 | phoneNumber: String,
6 | desc: String,
7 | },
8 |
9 | data: {
10 | show: false,
11 | },
12 |
13 | methods: {
14 | onBtnTap() {
15 | this.setData({
16 | show: true,
17 | });
18 | },
19 |
20 | onDialogClose() {
21 | this.setData({
22 | show: false,
23 | });
24 | },
25 |
26 | onCall() {
27 | const { phoneNumber } = this.properties;
28 | wx.makePhoneCall({
29 | phoneNumber,
30 | });
31 | },
32 | onCallOnlineService() {
33 | wx.showToast({
34 | title: '你点击了在线客服',
35 | });
36 | },
37 | },
38 | });
39 |
--------------------------------------------------------------------------------
/pages/order/components/customer-service/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/pages/order/components/customer-service/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | 联系客服
3 |
4 |
5 |
6 |
7 | 服务时间:
8 | {{desc}}
9 |
10 |
11 | 呼叫 {{phoneNumber}}
17 |
18 | 在线客服
19 | 取消
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/pages/order/components/customer-service/index.wxss:
--------------------------------------------------------------------------------
1 | .text-btn {
2 | display: inline;
3 | color: #333;
4 | font-size: 24rpx;
5 | }
6 | .text-btn--active {
7 | opacity: 0.5;
8 | }
9 | .dialog--customer-service {
10 | background-color: #f3f4f5;
11 | overflow: hidden;
12 | }
13 | .dialog--customer-service .content {
14 | font-size: 26rpx;
15 | margin: 32rpx 30rpx;
16 | text-align: center;
17 | }
18 | .dialog--customer-service .content .title {
19 | display: inline;
20 | color: #999999;
21 | font-weight: bold;
22 | }
23 | .dialog--customer-service .content .subtitle {
24 | display: inline;
25 | color: #999999;
26 | }
27 | .dialog--customer-service .options .option {
28 | color: #333333;
29 | font-size: 30rpx;
30 | text-align: center;
31 | height: 100rpx;
32 | line-height: 100rpx;
33 | background-color: white;
34 | }
35 | .dialog--customer-service .options .option:not(:last-child) {
36 | margin-bottom: 20rpx;
37 | }
38 | .dialog--customer-service .options .option--active {
39 | opacity: 0.5;
40 | }
41 | .dialog--customer-service .options .option.main {
42 | color: #333;
43 | }
44 | .dialog--customer-service .options .option.online {
45 | position: relative;
46 | top: -17rpx;
47 | margin-bottom: 2rpx;
48 | }
49 |
--------------------------------------------------------------------------------
/pages/order/components/goods-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "price": "/components/price/index",
5 | "t-image": "/components/webp-image/index",
6 | "t-icon": "tdesign-miniprogram/icon/icon"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/order/components/noGoods/noGood.wxs:
--------------------------------------------------------------------------------
1 | var isOnlyBack = function (data) {
2 | return data.limitGoodsList || (data.inValidGoodsList && !data.storeGoodsList);
3 | };
4 |
5 | var isShowChangeAddress = function (data) {
6 | return data.abnormalDeliveryGoodsList;
7 | };
8 |
9 | var isShowKeepPay = function (data) {
10 | return data.outOfStockGoodsList || (data.storeGoodsList && data.inValidGoodsList);
11 | };
12 |
13 | module.exports = {
14 | isOnlyBack: isOnlyBack,
15 | isShowChangeAddress: isShowChangeAddress,
16 | isShowKeepPay: isShowKeepPay,
17 | };
18 |
--------------------------------------------------------------------------------
/pages/order/components/noGoods/noGoods.js:
--------------------------------------------------------------------------------
1 | Component({
2 | properties: {
3 | settleDetailData: {
4 | type: Object,
5 | value: {},
6 | observer(settleDetailData) {
7 | const {
8 | outOfStockGoodsList,
9 | abnormalDeliveryGoodsList,
10 | inValidGoodsList,
11 | limitGoodsList,
12 | } = settleDetailData;
13 | // 弹窗逻辑 限购 超出配送范围 失效 库存不足;
14 | const tempList =
15 | limitGoodsList ||
16 | abnormalDeliveryGoodsList ||
17 | inValidGoodsList ||
18 | outOfStockGoodsList ||
19 | [];
20 |
21 | tempList.forEach((goods, index) => {
22 | goods.id = index;
23 | goods.unSettlementGoods &&
24 | goods.unSettlementGoods.forEach((ele) => {
25 | ele.name = ele.goodsName;
26 | ele.price = ele.payPrice;
27 | ele.imgUrl = ele.image;
28 | });
29 | });
30 | this.setData({
31 | // settleDetailData,
32 | goodsList: tempList,
33 | });
34 | },
35 | },
36 | },
37 |
38 | data: {
39 | goodList: [],
40 | },
41 | methods: {
42 | onCard(e) {
43 | const { item } = e.currentTarget.dataset;
44 | if (item === 'cart') {
45 | // 购物车
46 | Navigator.gotoPage('/cart');
47 | } else if (item === 'orderSure') {
48 | // 结算页
49 | this.triggerEvent('change', undefined);
50 | }
51 | },
52 | onDelive() {
53 | // 修改配送地址
54 | Navigator.gotoPage('/address', { type: 'orderSure' });
55 | },
56 | },
57 | });
58 |
--------------------------------------------------------------------------------
/pages/order/components/noGoods/noGoods.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "wr-order-card": "/pages/order/components/order-card/index",
5 | "wr-goods-card": "/components/goods-card/index",
6 | "wr-order-goods-card": "/pages/order/components/order-goods-card/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/order/components/order-button-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-button": "tdesign-miniprogram/button/button",
5 | "t-toast": "tdesign-miniprogram/toast/toast",
6 | "t-dialog": "tdesign-miniprogram/dialog/dialog"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/order/components/order-button-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 | {{leftBtn.name}}
15 |
16 |
17 |
18 |
32 | {{rightBtn.name}}
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/pages/order/components/order-button-bar/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | width: 100%;
3 | }
4 | .btn-bar {
5 | display: flex;
6 | justify-content: space-between;
7 | align-items: center;
8 | line-height: 1;
9 | }
10 | .btn-bar .order-btn {
11 | line-height: 1;
12 | /* border-radius: unset; */
13 | /* min-width: 160rpx; */
14 | }
15 |
16 | .btn-bar .right {
17 | display: flex;
18 | align-items: center;
19 | }
20 | .btn-bar .t-button {
21 | width: 160rpx;
22 | font-weight: 400;
23 | margin-left: 24rpx;
24 | }
25 | .btn-bar .t-button--max {
26 | width: 176rpx;
27 | margin-left: 24rpx;
28 |
29 | --td-button-extra-small-height: 72rpx;
30 | }
31 |
32 | .btn-bar .left .delete-btn {
33 | font-size: 22rpx;
34 | }
35 | .btn-bar .left .delete-btn::after {
36 | display: none;
37 | }
38 |
39 | .btn-bar .right .normal {
40 | --td-button-default-color: #333333;
41 | --td-button-default-border-color: #dddddd;
42 | }
43 |
44 | .btn-bar .right .primary {
45 | --td-button-default-color: #fff;
46 | --td-button-default-bg-color: #fa4126;
47 | --td-button-default-border-color: #fa4126;
48 | --td-button-default-active-bg-color: #fa42269c;
49 | }
50 |
51 | .t-button {
52 | --td-button-default-color: #000;
53 | --td-button-primary-text-color: #fa4126;
54 | }
55 |
--------------------------------------------------------------------------------
/pages/order/components/order-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-image": "/components/webp-image/index",
5 | "t-icon": "tdesign-miniprogram/icon/icon"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/order/components/order-card/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
23 |
24 |
25 | 展开商品信息(共 {{goodsCount}} 个)
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/pages/order/components/order-card/index.wxss:
--------------------------------------------------------------------------------
1 | .order-card {
2 | margin: 24rpx 0;
3 | padding: 24rpx 32rpx 24rpx;
4 | background-color: white;
5 | border-radius: 8rpx;
6 | }
7 | .order-card .header {
8 | display: flex;
9 | justify-content: space-between;
10 | align-items: center;
11 | margin-bottom: 24rpx;
12 | }
13 | .order-card .header .store-name {
14 | font-size: 28rpx;
15 | font-weight: normal;
16 | color: #333333;
17 | display: flex;
18 | align-items: center;
19 | line-height: 40rpx;
20 | }
21 | .order-card .header .store-name__logo {
22 | margin-right: 16rpx;
23 | font-size: 40rpx;
24 | width: 48rpx;
25 | height: 48rpx;
26 | }
27 | .order-card .header .store-name__label {
28 | max-width: 500rpx;
29 | overflow: hidden;
30 | text-overflow: ellipsis;
31 | word-break: break-all;
32 | white-space: nowrap;
33 | }
34 | .order-card .header .order-status {
35 | font-size: 26rpx;
36 | line-height: 40rpx;
37 | color: #fa4126;
38 | }
39 | .order-card .more-mask {
40 | padding: 20rpx 0;
41 | text-align: center;
42 | background-color: white;
43 | color: #fa4126;
44 | font-size: 24rpx;
45 | }
46 |
--------------------------------------------------------------------------------
/pages/order/components/order-goods-card/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | addGlobalClass: true,
4 | multipleSlots: true, // 在组件定义时的选项中启用多slot支持
5 | },
6 |
7 | relations: {
8 | '../order-card/index': {
9 | type: 'ancestor',
10 | linked(target) {
11 | this.parent = target;
12 | },
13 | },
14 | },
15 |
16 | properties: {
17 | goods: Object,
18 | thumbWidth: Number,
19 | thumbHeight: Number,
20 | thumbWidthInPopup: Number,
21 | thumbHeightInPopup: Number,
22 | noTopLine: Boolean,
23 | step: Boolean,
24 | stepDisabled: Boolean,
25 | },
26 |
27 | data: {
28 | goods: {},
29 | hidden: false,
30 | },
31 |
32 | methods: {
33 | setHidden(hidden) {
34 | if (this.data.hidden === hidden) return;
35 | this.setData({ hidden });
36 | },
37 |
38 | onNumChange(e) {
39 | const { value } = e.detail;
40 | this.triggerEvent('num-change', { value });
41 | },
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/pages/order/components/order-goods-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-stepper": "tdesign-miniprogram/stepper/stepper",
5 | "goods-card": "../specs-goods-card/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/order/components/order-goods-card/index.wxml:
--------------------------------------------------------------------------------
1 |
10 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/pages/order/components/reason-sheet/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-popup": "tdesign-miniprogram/popup/popup",
6 | "t-cell": "tdesign-miniprogram/cell/cell",
7 | "t-toast": "tdesign-miniprogram/toast/toast",
8 | "t-button": "tdesign-miniprogram/button/button"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/order/components/reason-sheet/index.wxml:
--------------------------------------------------------------------------------
1 |
7 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/pages/order/components/reason-sheet/index.wxss:
--------------------------------------------------------------------------------
1 | page view {
2 | box-sizing: border-box;
3 | }
4 | .popup-content {
5 | background-color: white;
6 | color: #222427;
7 | border-radius: 20rpx 20rpx 0 0;
8 | overflow: hidden;
9 | }
10 | .popup-content .header {
11 | height: 100rpx;
12 | line-height: 100rpx;
13 | text-align: center;
14 | vertical-align: middle;
15 | font-size: 32rpx;
16 | font-weight: bold;
17 | position: relative;
18 | }
19 | .popup-content .options {
20 | max-height: 60vh;
21 | overflow-y: scroll;
22 | -webkit-overflow-scrolling: touch;
23 | }
24 | .popup-content .options .cell {
25 | height: 100rpx;
26 | align-items: center;
27 | font-size: 30rpx;
28 | color: #333333;
29 | }
30 | .popup-content .button-bar {
31 | width: 100%;
32 | padding: 20rpx 30rpx;
33 | display: flex;
34 | flex-wrap: nowrap;
35 | align-items: center;
36 | justify-content: space-between;
37 | padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
38 | }
39 | .popup-content .button-bar .btn {
40 | width: 100%;
41 | background: #fa4126;
42 | color: #fff;
43 | border-radius: 48rpx;
44 | }
45 | .button-bar .btnWrapper {
46 | width: 100%;
47 | }
48 |
--------------------------------------------------------------------------------
/pages/order/components/reason-sheet/reasonSheet.js:
--------------------------------------------------------------------------------
1 | function getInstance(context, selector = '#wr-reason-sheet') {
2 | if (!context) {
3 | const pages = getCurrentPages();
4 | const page = pages[pages.length - 1];
5 | context = page;
6 | }
7 | const instance = context && context.selectComponent(selector);
8 | if (!instance) {
9 | console.warn(`未找到reason-sheet组件,请检查selector是否正确`);
10 | return null;
11 | }
12 | return instance;
13 | }
14 |
15 | export default function (options) {
16 | const { context, selector, ..._options } = options;
17 | return new Promise((resolve, reject) => {
18 | const instance = getInstance(context, selector);
19 | if (instance) {
20 | instance.setData(Object.assign({}, _options));
21 | instance._onCancel = () => reject();
22 | instance._onConfirm = (indexes) => resolve(indexes);
23 | }
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/pages/order/components/selectCoupons/mock.js:
--------------------------------------------------------------------------------
1 | export const couponsData = {
2 | couponResultList: [
3 | {
4 | couponVO: {
5 | condition: '满200元可用',
6 | couponId: 11,
7 | endTime: 1584530282686,
8 | name: '折扣券',
9 | profit: '5.5折',
10 | promotionCode: 90,
11 | promotionSubCode: 1,
12 | scopeText: '部分商品可用',
13 | startTime: 1584530282686,
14 | storeId: 90,
15 | value: 550,
16 | type: 2,
17 | },
18 | status: 0, // 0:未勾选。1:勾选。-1:置灰
19 | },
20 | ],
21 | reduce: 1000,
22 | };
23 |
--------------------------------------------------------------------------------
/pages/order/components/selectCoupons/selectCoupon.wxs:
--------------------------------------------------------------------------------
1 | function formatDays(value) {
2 | if (value < 10) {
3 | return '0' + value;
4 | }
5 | return value;
6 | }
7 | var dateFormat = function (d) {
8 | var date = getDate(+d);
9 | return (
10 | date.getFullYear() +
11 | '-' +
12 | formatDays(date.getMonth() + 1) +
13 | formatDays(date.getDate())
14 | );
15 | };
16 | module.exports.dateFormat = dateFormat;
17 |
--------------------------------------------------------------------------------
/pages/order/components/selectCoupons/selectCoupons.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-image": "/components/webp-image/index",
7 | "wr-price": "/components/price/index",
8 | "coupon-card": "/pages/coupon/components/ui-coupon-card/index"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/order/components/selectCoupons/selectCoupons.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 选择优惠券
7 |
8 |
9 | 你有{{couponsList.length}}张可用优惠券
10 |
11 | 已选中{{selectedNum}}张推荐优惠券, 共抵扣
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 | 此优惠券不能和已勾选的优惠券叠加使用
32 |
33 |
34 |
35 |
36 |
37 |
38 | 暂无优惠券
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/pages/order/components/specs-goods-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "goods-card": "../goods-card/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/order/components/specs-goods-card/index.wxml:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/pages/order/components/specs-goods-card/index.wxss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tencent/tdesign-miniprogram-starter-retail/ef92ec100f82dfb724a62a08dfbc1defb50183c2/pages/order/components/specs-goods-card/index.wxss
--------------------------------------------------------------------------------
/pages/order/delivery-detail/index.js:
--------------------------------------------------------------------------------
1 | Page({
2 | data: {
3 | logisticsData: {
4 | logisticsNo: '',
5 | nodes: [],
6 | company: '',
7 | phoneNumber: '',
8 | },
9 | active: 0,
10 | },
11 |
12 | onLoad(query) {
13 | let data;
14 | try {
15 | data = JSON.parse(decodeURIComponent(query.data || '{}'));
16 | } catch (e) {
17 | console.warn('物流节点数据解析失败', e);
18 | }
19 | if (Number(query.source) === 2) {
20 | const service = {
21 | company: data.logisticsCompanyName,
22 | logisticsNo: data.logisticsNo,
23 | nodes: data.nodes,
24 | };
25 | this.setData({
26 | logisticsData: service,
27 | });
28 | } else if (data) {
29 | this.setData({ logisticsData: data });
30 | }
31 | },
32 |
33 | onLogisticsNoCopy() {
34 | wx.setClipboardData({ data: this.data.logisticsData.logisticsNo });
35 | },
36 |
37 | onCall() {
38 | const { phoneNumber } = this.data.logisticsData;
39 | wx.makePhoneCall({
40 | phoneNumber,
41 | });
42 | },
43 | });
44 |
--------------------------------------------------------------------------------
/pages/order/delivery-detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "物流信息",
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
6 | "t-image": "/components/webp-image/index",
7 | "t-icon": "tdesign-miniprogram/icon/icon",
8 | "t-steps": "tdesign-miniprogram/steps/steps",
9 | "t-step": "tdesign-miniprogram/step-item/step-item"
10 | }
11 | }
--------------------------------------------------------------------------------
/pages/order/fill-tracking-no/api.js:
--------------------------------------------------------------------------------
1 | import { mockIp, mockReqId } from '../../../utils/mock';
2 |
3 | export function create() {
4 | const _resq = {
5 | data: null,
6 | code: 'Success',
7 | msg: null,
8 | requestId: mockReqId(),
9 | clientIp: mockIp(),
10 | rt: 79,
11 | success: true,
12 | };
13 | return Promise.resolve(_resq);
14 | }
15 |
16 | export function update() {
17 | const _resq = {
18 | data: null,
19 | code: 'Success',
20 | msg: null,
21 | requestId: mockReqId(),
22 | clientIp: mockIp(),
23 | rt: 79,
24 | success: true,
25 | };
26 | return Promise.resolve(_resq);
27 | }
28 |
29 | export function getDeliverCompanyList() {
30 | const _resq = {
31 | data: [
32 | {
33 | name: '中通快递',
34 | code: '0001',
35 | },
36 | {
37 | name: '申通快递',
38 | code: '0002',
39 | },
40 | {
41 | name: '圆通快递',
42 | code: '0003',
43 | },
44 | {
45 | name: '顺丰快递',
46 | code: '0004',
47 | },
48 | {
49 | name: '百世快递',
50 | code: '0005',
51 | },
52 | {
53 | name: '韵达快递',
54 | code: '0006',
55 | },
56 | {
57 | name: '邮政快递',
58 | code: '0007',
59 | },
60 | {
61 | name: '丰网快递',
62 | code: '0008',
63 | },
64 | {
65 | name: '顺丰直邮',
66 | code: '0009',
67 | },
68 | ],
69 | };
70 | return Promise.resolve(_resq);
71 | }
72 |
--------------------------------------------------------------------------------
/pages/order/fill-tracking-no/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "填写运单号",
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-cell": "tdesign-miniprogram/cell/cell",
6 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
7 | "t-textarea": "tdesign-miniprogram/textarea/textarea",
8 | "t-input": "tdesign-miniprogram/input/input",
9 | "t-toast": "tdesign-miniprogram/toast/toast",
10 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
11 | "t-button": "tdesign-miniprogram/button/button",
12 | "ui-reason-sheet": "../components/reason-sheet/index"
13 | }
14 | }
--------------------------------------------------------------------------------
/pages/order/invoice/index.js:
--------------------------------------------------------------------------------
1 | import { fetchOrderDetail } from '../../../services/order/orderDetail';
2 |
3 | Page({
4 | data: {
5 | invoice: {},
6 | },
7 | onLoad({ orderNo }) {
8 | this.orderNo = orderNo;
9 | this.init();
10 | },
11 | init() {
12 | this.getDetail();
13 | },
14 | getDetail() {
15 | const params = {
16 | parameter: this.orderNo,
17 | };
18 | return fetchOrderDetail(params).then((res) => {
19 | const order = res.data;
20 |
21 | const invoice = {
22 | buyerName: order?.invoiceVO?.buyerName, //个人或公司名称
23 | buyerTaxNo: order?.invoiceVO?.buyerTaxNo, //税号
24 | buyerPhone: order?.invoiceVO?.buyerPhone, //手机
25 | email: order?.invoiceVO?.email, //邮箱
26 | titleType: order?.invoiceVO?.titleType === 1 ? '个人' : '公司', //发票抬头 1-个人 2-公司
27 | ontentType: order?.invoiceVO?.ontentType === 1 ? '商品明细' : '2类别', //发票内容 1-明细 2类别
28 | invoiceType:
29 | order?.invoiceVO?.invoiceType === 5 ? '电子普通发票' : '不开发票', //是否开票 0-不开 5-电子发票
30 | isInvoice: order?.invoiceVO?.buyerName ? '已开票' : '未开票',
31 | money: order?.invoiceVO?.money,
32 | };
33 | this.setData({
34 | invoice,
35 | });
36 | });
37 | },
38 | });
39 |
--------------------------------------------------------------------------------
/pages/order/invoice/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "发票详情",
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-button": "tdesign-miniprogram/button/button",
6 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/pages/order/invoice/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | background-color: #f5f5f5;
3 | }
4 |
5 | .invoice-detail .invoice-detail-box {
6 | background-color: #fff;
7 | padding: 24rpx 32rpx;
8 | margin-top: 24rpx;
9 | }
10 |
11 | .invoice-detail-title {
12 | font-size: 14px;
13 | font-weight: 600;
14 | }
15 |
16 | .invoice-detail-box-row {
17 | display: flex;
18 | margin-top: 44rpx;
19 | }
20 |
21 | .invoice-detail-box-title {
22 | font-size: 13px;
23 | color: #666666;
24 | width: 156rpx;
25 | margin-right: 32rpx;
26 | }
27 |
28 | .invoice-detail-box-value {
29 | font-size: 13px;
30 | color: #333333;
31 | }
32 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/components/address-card/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: rileycai
3 | * @Date: 2022-03-05 16:47:16
4 | * @LastEditTime: 2022-03-05 16:48:32
5 | * @LastEditors: rileycai
6 | * @Description:
7 | * @FilePath: /tdesign-miniprogram-starter/pages/order/order-confirm/components/address-card/index.js
8 | */
9 | Component({
10 | externalClasses: ['wr-class'],
11 | properties: {
12 | addressData: {
13 | type: Object,
14 | value: {},
15 | },
16 | },
17 | methods: {
18 | onAddressTap() {
19 | this.triggerEvent('addressclick');
20 | },
21 | onAddTap() {
22 | this.triggerEvent('addclick');
23 | },
24 | },
25 | });
26 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/components/address-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-icon": "tdesign-miniprogram/icon/icon"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/components/address-card/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | var hidePhoneNum = function(array) {
3 | if (!array) return;
4 | var mphone = array.substring(0, 3) + '****' + array.substring(7);
5 | return mphone;
6 | }
7 | module.exports = {
8 | hidePhoneNum:hidePhoneNum
9 | }
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {{addressData.addressTag}}
20 |
21 | {{addressData.provinceName}} {{addressData.cityName}} {{addressData.districtName}}
22 |
23 | {{addressData.detailAddress}}
24 |
25 | {{addressData.name}} {{utils.hidePhoneNum(addressData.phone)}}
26 |
27 |
28 |
34 |
35 |
36 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/components/address-card/index.wxss:
--------------------------------------------------------------------------------
1 | .address-card {
2 | background: #fff;
3 | margin: 0rpx 0rpx 24rpx;
4 | }
5 | .address-card .wr-cell__title {
6 | color: #999;
7 | margin-left: 6rpx;
8 | }
9 | .address-card .order-address {
10 | display: flex;
11 | width: 100%;
12 | }
13 | .address-card .order-address .address-content {
14 | flex: 1;
15 | }
16 | .order-address .address__right {
17 | align-self: center;
18 | }
19 | .address-card .order-address .title {
20 | display: flex;
21 | align-items: center;
22 | height: 40rpx;
23 | font-size: 28rpx;
24 | font-weight: normal;
25 | color: #999999;
26 | line-height: 40rpx;
27 | }
28 | .address-card .order-address .title .address-tag {
29 | width: 52rpx;
30 | height: 29rpx;
31 | border: 1rpx solid #0091ff;
32 | background-color: rgba(122, 167, 251, 0.1);
33 | text-align: center;
34 | line-height: 29rpx;
35 | border-radius: 8rpx;
36 | color: #0091ff;
37 | font-size: 20rpx;
38 | margin-right: 12rpx;
39 | }
40 | .address-card .order-address .detail {
41 | overflow: hidden;
42 | text-overflow: ellipsis;
43 | display: -webkit-box;
44 | -webkit-box-orient: vertical;
45 | -webkit-line-clamp: 2;
46 | font-size: 36rpx;
47 | font-weight: bold;
48 | color: #333333;
49 | line-height: 48rpx;
50 | margin: 8rpx 0;
51 | }
52 | .address-card .order-address .info {
53 | height: 40rpx;
54 | font-size: 28rpx;
55 | font-weight: normal;
56 | color: #333333;
57 | line-height: 40rpx;
58 | }
59 | .address-card .top-line {
60 | width: 100%;
61 | height: 6rpx;
62 | background-color: #fff;
63 | background-image: url(https://cdn-we-retail.ym.tencent.com/miniapp/order/stripe.png);
64 | background-repeat: repeat-x;
65 | display: block;
66 | }
67 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/getNotes.wxs:
--------------------------------------------------------------------------------
1 | var getNotes = function (storeInfoList, storeIndex) {
2 | if (!storeInfoList) {
3 | return '';
4 | }
5 | var storeInfo = storeInfoList[storeIndex];
6 | if (!storeInfo) {
7 | return '';
8 | }
9 | return storeInfoList[storeIndex].remark;
10 | };
11 | module.exports = getNotes;
12 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/handleInvoice.wxs:
--------------------------------------------------------------------------------
1 | var handleInvoice = function (invoiceData) {
2 | if (!invoiceData || invoiceData.invoiceType == 0) {
3 | return '暂不开发票';
4 | }
5 | var title = invoiceData.titleType == 2 ? '公司' : '个人';
6 | var content = invoiceData.contentType == 2 ? '商品类别' : '商品明细';
7 | return invoiceData.email
8 | ? '电子普通发票 (' + content + ' - ' + title + ')'
9 | : '暂不开发票';
10 | };
11 | module.exports = handleInvoice;
12 |
--------------------------------------------------------------------------------
/pages/order/order-confirm/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "订单确认",
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup",
5 | "t-toast": "tdesign-miniprogram/toast/toast",
6 | "t-icon": "tdesign-miniprogram/icon/icon",
7 | "t-cell": "tdesign-miniprogram/cell/cell",
8 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
9 | "t-textarea": "tdesign-miniprogram/textarea/textarea",
10 | "price": "/components/price/index",
11 | "select-coupons": "../components/selectCoupons/selectCoupons",
12 | "no-goods": "../components/noGoods/noGoods",
13 | "t-image": "/components/webp-image/index",
14 | "address-card": "./components/address-card/index"
15 | }
16 | }
--------------------------------------------------------------------------------
/pages/order/order-confirm/order.wxs:
--------------------------------------------------------------------------------
1 | var toHide = function (array) {
2 | if (!array) return;
3 | var mphone = array.substring(0, 3) + '****' + array.substring(7);
4 | return mphone;
5 | };
6 | module.exports = {
7 | toHide: toHide,
8 | };
9 |
--------------------------------------------------------------------------------
/pages/order/order-detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "订单详情",
3 | "usingComponents": {
4 | "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh",
5 | "t-button": "tdesign-miniprogram/button/button",
6 | "t-cell": "tdesign-miniprogram/cell/cell",
7 | "t-icon": "tdesign-miniprogram/icon/icon",
8 | "t-image": "/components/webp-image/index",
9 | "t-count-down": "tdesign-miniprogram/count-down/count-down",
10 | "t-toast": "tdesign-miniprogram/toast/toast",
11 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
12 | "price": "/components/price/index",
13 | "order-card": "../components/order-card/index",
14 | "order-goods-card": "../components/order-goods-card/index",
15 | "order-button-bar": "../components/order-button-bar/index"
16 | }
17 | }
--------------------------------------------------------------------------------
/pages/order/order-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "我的订单",
3 | "usingComponents": {
4 | "t-tabs": "tdesign-miniprogram/tabs/tabs",
5 | "t-tab-panel": "tdesign-miniprogram/tab-panel/tab-panel",
6 | "t-empty": "tdesign-miniprogram/empty/empty",
7 | "t-toast": "tdesign-miniprogram/toast/toast",
8 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
9 | "t-pull-down-refresh": "tdesign-miniprogram/pull-down-refresh/pull-down-refresh",
10 | "load-more": "/components/load-more/index",
11 | "order-button-bar": "../components/order-button-bar/index",
12 | "price": "/components/price/index",
13 | "order-card": "../components/order-card/index",
14 | "specs-goods-card": "../components/specs-goods-card/index"
15 | }
16 | }
--------------------------------------------------------------------------------
/pages/order/pay-result/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: rileycai
3 | * @Date: 2022-03-14 21:18:07
4 | * @LastEditTime: 2022-03-22 21:17:16
5 | * @LastEditors: rileycai
6 | * @Description:
7 | * @FilePath: /tdesign-miniprogram-starter/pages/order/pay-result/index.js
8 | */
9 | Page({
10 | data: {
11 | totalPaid: 0,
12 | orderNo: '',
13 | groupId: '',
14 | groupon: null,
15 | spu: null,
16 | adUrl: '',
17 | },
18 |
19 | onLoad(options) {
20 | const { totalPaid = 0, orderNo = '', groupId = '' } = options;
21 | this.setData({
22 | totalPaid,
23 | orderNo,
24 | groupId,
25 | });
26 | },
27 |
28 | onTapReturn(e) {
29 | const target = e.currentTarget.dataset.type;
30 | const { orderNo } = this.data;
31 | if (target === 'home') {
32 | wx.switchTab({ url: '/pages/home/home' });
33 | } else if (target === 'orderList') {
34 | wx.navigateTo({
35 | url: `/pages/order/order-list/index?orderNo=${orderNo}`,
36 | });
37 | } else if (target === 'order') {
38 | wx.navigateTo({
39 | url: `/pages/order/order-detail/index?orderNo=${orderNo}`,
40 | });
41 | }
42 | },
43 |
44 | navBackHandle() {
45 | wx.navigateBack();
46 | },
47 | });
48 |
--------------------------------------------------------------------------------
/pages/order/pay-result/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "支付结果",
3 | "navigationStyle": "custom",
4 | "usingComponents": {
5 | "t-navbar": "tdesign-miniprogram/navbar/navbar",
6 | "t-icon": "tdesign-miniprogram/icon/icon",
7 | "price": "/components/price/index"
8 | }
9 | }
--------------------------------------------------------------------------------
/pages/order/pay-result/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 支付成功
6 |
7 |
8 | 微信支付:
9 |
16 |
17 |
18 | 查看订单
19 | 返回首页
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/pages/order/pay-result/index.wxss:
--------------------------------------------------------------------------------
1 | .pay-result {
2 | display: flex;
3 | flex-direction: column;
4 | align-items: center;
5 | width: 100%;
6 | }
7 |
8 | .pay-result .pay-status {
9 | margin-top: 100rpx;
10 | font-size: 48rpx;
11 | line-height: 72rpx;
12 | font-weight: bold;
13 | color: #333333;
14 | display: flex;
15 | align-items: center;
16 | }
17 | .pay-result .pay-status text {
18 | padding-left: 12rpx;
19 | }
20 | .pay-result .pay-money {
21 | color: #666666;
22 | font-size: 28rpx;
23 | line-height: 48rpx;
24 | margin-top: 28rpx;
25 | display: flex;
26 | align-items: baseline;
27 | }
28 |
29 | .pay-result .pay-money .pay-money__price {
30 | font-size: 36rpx;
31 | line-height: 48rpx;
32 | color: #fa4126;
33 | }
34 | .pay-result .btn-wrapper {
35 | margin-top: 48rpx;
36 | padding: 12rpx 32rpx;
37 | display: flex;
38 | align-items: center;
39 | justify-content: space-between;
40 | width: 100%;
41 | box-sizing: border-box;
42 | }
43 |
44 | .pay-result .btn-wrapper .status-btn {
45 | height: 88rpx;
46 | width: 334rpx;
47 | border-radius: 44rpx;
48 | border: 2rpx solid #fa4126;
49 | color: #fa4126;
50 | font-size: 28rpx;
51 | font-weight: bold;
52 | line-height: 88rpx;
53 | text-align: center;
54 | }
55 |
--------------------------------------------------------------------------------
/pages/order/receipt/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "发票",
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
6 | "t-toast": "tdesign-miniprogram/toast/toast",
7 | "t-icon": "tdesign-miniprogram/icon/icon",
8 | "t-input": "tdesign-miniprogram/input/input",
9 | "t-button": "tdesign-miniprogram/button/button"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/pages/promotion-detail/index.js:
--------------------------------------------------------------------------------
1 | import Toast from 'tdesign-miniprogram/toast/index';
2 | import { fetchPromotion } from '../../services/promotion/detail';
3 |
4 | Page({
5 | data: {
6 | list: [],
7 | banner: '',
8 | time: 0,
9 | showBannerDesc: false,
10 | statusTag: '',
11 | },
12 |
13 | onLoad(query) {
14 | const promotionID = parseInt(query.promotion_id);
15 | this.getGoodsList(promotionID);
16 | },
17 |
18 | getGoodsList(promotionID) {
19 | fetchPromotion(promotionID).then(
20 | ({ list, banner, time, showBannerDesc, statusTag }) => {
21 | const goods = list.map((item) => ({
22 | ...item,
23 | tags: item.tags.map((v) => v.title),
24 | }));
25 | this.setData({
26 | list: goods,
27 | banner,
28 | time,
29 | showBannerDesc,
30 | statusTag,
31 | });
32 | },
33 | );
34 | },
35 |
36 | goodClickHandle(e) {
37 | const { index } = e.detail;
38 | const { spuId } = this.data.list[index];
39 | wx.navigateTo({ url: `/pages/goods/details/index?spuId=${spuId}` });
40 | },
41 |
42 | cardClickHandle() {
43 | Toast({
44 | context: this,
45 | selector: '#t-toast',
46 | message: '点击加购',
47 | });
48 | },
49 |
50 | bannerClickHandle() {
51 | Toast({
52 | context: this,
53 | selector: '#t-toast',
54 | message: '点击规则详情',
55 | });
56 | },
57 | });
58 |
--------------------------------------------------------------------------------
/pages/promotion-detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "营销详情",
3 | "usingComponents": {
4 | "t-toast": "tdesign-miniprogram/toast/toast",
5 | "t-image": "/components/webp-image/index",
6 | "t-icon": "tdesign-miniprogram/icon/icon",
7 | "count-down": "tdesign-miniprogram/count-down/count-down",
8 | "goods-list": "/components/goods-list/index"
9 | }
10 | }
--------------------------------------------------------------------------------
/pages/usercenter/address/edit/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "添加新地址",
3 | "usingComponents": {
4 | "t-textarea": "tdesign-miniprogram/textarea/textarea",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-input": "tdesign-miniprogram/input/input",
7 | "t-button": "tdesign-miniprogram/button/button",
8 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
9 | "t-cell": "tdesign-miniprogram/cell/cell",
10 | "t-toast": "tdesign-miniprogram/toast/toast",
11 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
12 | "t-switch": "tdesign-miniprogram/switch/switch",
13 | "t-location": "/pages/usercenter/components/t-location/index",
14 | "t-cascader": "tdesign-miniprogram/cascader/cascader"
15 | }
16 | }
--------------------------------------------------------------------------------
/pages/usercenter/address/edit/util.js:
--------------------------------------------------------------------------------
1 | let addressPromise = [];
2 |
3 | /** 地址编辑Promise */
4 | export const getAddressPromise = () => {
5 | let resolver;
6 | let rejecter;
7 | const nextPromise = new Promise((resolve, reject) => {
8 | resolver = resolve;
9 | rejecter = reject;
10 | });
11 |
12 | addressPromise.push({ resolver, rejecter });
13 |
14 | return nextPromise;
15 | };
16 |
17 | /** 用户保存了一个地址 */
18 | export const resolveAddress = (address) => {
19 | const allAddress = [...addressPromise];
20 | addressPromise = [];
21 |
22 | console.info('用户保存了一个地址', address);
23 |
24 | allAddress.forEach(({ resolver }) => resolver(address));
25 | };
26 |
27 | /** 取消编辑 */
28 | export const rejectAddress = () => {
29 | const allAddress = [...addressPromise];
30 | addressPromise = [];
31 |
32 | allAddress.forEach(({ rejecter }) => rejecter(new Error('cancel')));
33 | };
34 |
--------------------------------------------------------------------------------
/pages/usercenter/address/list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "收货地址",
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-image": "/components/webp-image/index",
6 | "t-toast": "tdesign-miniprogram/toast/toast",
7 | "t-address-item": "../../components/ui-address-item/index",
8 | "t-location": "../../components/t-location/index",
9 | "t-empty": "tdesign-miniprogram/empty/empty"
10 | }
11 | }
--------------------------------------------------------------------------------
/pages/usercenter/address/list/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
36 |
37 |
43 | 新建收货地址
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/pages/usercenter/address/list/util.js:
--------------------------------------------------------------------------------
1 | let addressPromise = [];
2 |
3 | /** 获取一个地址选择Promise */
4 | export const getAddressPromise = () => {
5 | let resolver;
6 | let rejecter;
7 | const nextPromise = new Promise((resolve, reject) => {
8 | resolver = resolve;
9 | rejecter = reject;
10 | });
11 |
12 | addressPromise.push({ resolver, rejecter });
13 |
14 | return nextPromise;
15 | };
16 |
17 | /** 用户选择了一个地址 */
18 | export const resolveAddress = (address) => {
19 | const allAddress = [...addressPromise];
20 | addressPromise = [];
21 |
22 | allAddress.forEach(({ resolver }) => resolver(address));
23 | };
24 |
25 | /** 用户没有选择任何地址只是返回上一页了 */
26 | export const rejectAddress = () => {
27 | const allAddress = [...addressPromise];
28 | addressPromise = [];
29 |
30 | allAddress.forEach(({ rejecter }) => rejecter(new Error('cancel')));
31 | };
32 |
--------------------------------------------------------------------------------
/pages/usercenter/components/order-group/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | externalClasses: ['title-class', 'icon-class', 'number-class'],
3 | options: {
4 | multipleSlots: true,
5 | },
6 | properties: {
7 | orderTagInfos: {
8 | type: Array,
9 | value: [],
10 | },
11 | title: {
12 | type: String,
13 | value: '我的订单',
14 | },
15 | desc: {
16 | type: String,
17 | value: '全部订单',
18 | },
19 | isTop: {
20 | type: Boolean,
21 | value: true,
22 | },
23 | classPrefix: {
24 | type: String,
25 | value: 'wr',
26 | },
27 | },
28 | methods: {
29 | onClickItem(e) {
30 | this.triggerEvent('onClickItem', e.currentTarget.dataset.item);
31 | },
32 |
33 | onClickTop() {
34 | this.triggerEvent('onClickTop', {});
35 | },
36 | },
37 | });
38 |
--------------------------------------------------------------------------------
/pages/usercenter/components/order-group/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
6 | "t-badge": "tdesign-miniprogram/badge/badge",
7 | "t-icon": "tdesign-miniprogram/icon/icon"
8 | }
9 | }
--------------------------------------------------------------------------------
/pages/usercenter/components/order-group/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
24 |
25 |
26 |
32 |
33 |
34 | {{item.title}}
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/pages/usercenter/components/order-group/index.wxss:
--------------------------------------------------------------------------------
1 | .order-group {
2 | margin-bottom: 24rpx;
3 | background-color: #ffffff;
4 | border-radius: 16rpx 16rpx 0 0;
5 | }
6 | .order-group .order-group__top {
7 | padding: 24rpx 18rpx 24rpx 32rpx;
8 | border-radius: 16rpx 16rpx 0 0;
9 | }
10 | .order-group__top___title {
11 | font-size: 32rpx;
12 | line-height: 48rpx;
13 | font-weight: bold;
14 | }
15 | .order-group__top__note {
16 | font-size: 28rpx;
17 | }
18 | .order-group__content {
19 | overflow: hidden;
20 | width: 100%;
21 | height: 164rpx;
22 | display: flex;
23 | background-color: #fff;
24 | border-radius: 0 0 16rpx 16rpx;
25 | }
26 | .order-group__item {
27 | overflow: hidden;
28 | display: flex;
29 | flex-direction: column;
30 | align-items: center;
31 | justify-content: center;
32 | flex: 1;
33 | }
34 | .order-group__item:first-child {
35 | border-radius: 0 0 0 16rpx;
36 | }
37 | .order-group__item:last-child {
38 | border-radius: 0 0 16rpx 0;
39 | }
40 | .order-group__item__title {
41 | font-size: 24rpx;
42 | color: #666;
43 | line-height: 32rpx;
44 | }
45 | .order-group__item__icon {
46 | margin-bottom: 20rpx;
47 | width: 56rpx;
48 | height: 56rpx;
49 | position: relative;
50 | }
51 | .order-group__top__title {
52 | font-weight: bold;
53 | }
54 | .order-group .order-group__left {
55 | margin-right: 0;
56 | }
57 |
--------------------------------------------------------------------------------
/pages/usercenter/components/t-location/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-cell": "tdesign-miniprogram/cell/cell",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-toast": "tdesign-miniprogram/toast/toast"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/usercenter/components/t-location/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{title}}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/pages/usercenter/components/t-location/index.wxss:
--------------------------------------------------------------------------------
1 | .wx-address .weixin {
2 | display: inline-block;
3 | font-size: 48rpx !important;
4 | margin-right: 20rpx;
5 | font-weight: normal;
6 | }
7 | .wx-address .cell {
8 | padding: 32rpx 30rpx;
9 | border-radius: 8rpx;
10 | }
11 | .wx-address .cell__title {
12 | font-size: 30rpx;
13 | color: #333333;
14 | }
15 | .wx-address-custom {
16 | display: flex;
17 | align-items: center;
18 | font-size: 32rpx;
19 | }
20 |
--------------------------------------------------------------------------------
/pages/usercenter/components/ui-address-item/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | options: {
3 | addGlobalClass: true,
4 | multipleSlots: true,
5 | },
6 | properties: {
7 | address: {
8 | type: Object,
9 | value: {},
10 | },
11 | customIcon: {
12 | type: String,
13 | value: 'edit-1',
14 | },
15 | extraSpace: {
16 | type: Boolean,
17 | value: true,
18 | },
19 | isDrawLine: {
20 | type: Boolean,
21 | value: true,
22 | },
23 | },
24 | externalClasses: [
25 | 'item-wrapper-class',
26 | 'title-class',
27 | 'default-tag-class',
28 | 'normal-tag-class',
29 | 'address-info-class',
30 | 'delete-class',
31 | ],
32 | methods: {
33 | onDelete(e) {
34 | const { item } = e.currentTarget.dataset;
35 | this.triggerEvent('onDelete', item);
36 | },
37 | onSelect(e) {
38 | const { item } = e.currentTarget.dataset;
39 | this.triggerEvent('onSelect', item);
40 | },
41 | onEdit(e) {
42 | const { item } = e.currentTarget.dataset;
43 | this.triggerEvent('onEdit', item);
44 | },
45 | },
46 | });
47 |
--------------------------------------------------------------------------------
/pages/usercenter/components/ui-address-item/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-tag": "tdesign-miniprogram/tag/tag",
6 | "t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/pages/usercenter/components/ui-address-item/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | var toHide = function(array) { var mphone = array.substring(0, 3) + '****' + array.substring(7); return mphone; }
3 | module.exports.toHide = toHide;
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | {{address.name}}
14 | {{phoneReg.toHide(address.phoneNumber || '')}}
15 |
16 |
17 |
18 | 默认
19 | {{address.tag}}
20 | {{address.address}}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 删除
29 |
30 |
31 |
--------------------------------------------------------------------------------
/pages/usercenter/components/ui-select-picker/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-popup": "tdesign-miniprogram/popup/popup"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/pages/usercenter/components/ui-select-picker/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 | {{ item.name }}
14 |
15 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/pages/usercenter/components/user-center-card/index.js:
--------------------------------------------------------------------------------
1 | const AuthStepType = {
2 | ONE: 1,
3 | TWO: 2,
4 | THREE: 3,
5 | };
6 |
7 | Component({
8 | options: {
9 | multipleSlots: true,
10 | },
11 | properties: {
12 | currAuthStep: {
13 | type: Number,
14 | value: AuthStepType.ONE,
15 | },
16 | userInfo: {
17 | type: Object,
18 | value: {},
19 | },
20 | isNeedGetUserInfo: {
21 | type: Boolean,
22 | value: false,
23 | },
24 | },
25 | data: {
26 | defaultAvatarUrl:
27 | 'https://cdn-we-retail.ym.tencent.com/miniapp/usercenter/icon-user-center-avatar@2x.png',
28 | AuthStepType,
29 | },
30 | methods: {
31 | gotoUserEditPage() {
32 | this.triggerEvent('gotoUserEditPage');
33 | },
34 | },
35 | });
36 |
--------------------------------------------------------------------------------
/pages/usercenter/components/user-center-card/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "t-icon": "tdesign-miniprogram/icon/icon",
5 | "t-avatar": "tdesign-miniprogram/avatar/avatar"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/usercenter/components/user-center-card/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
21 |
22 |
23 |
24 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/pages/usercenter/components/user-center-card/index.wxss:
--------------------------------------------------------------------------------
1 | .user-center-card {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | width: 100%;
6 | height: 480rpx;
7 | background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/template/user-center-bg-v1.png');
8 | background-size: cover;
9 | background-repeat: no-repeat;
10 | padding: 0 24rpx;
11 | }
12 | .user-center-card__header {
13 | margin-top: 192rpx;
14 | margin-bottom: 48rpx;
15 | height: 96rpx;
16 | line-height: 48rpx;
17 | display: flex;
18 | justify-content: flex-start;
19 | align-items: center;
20 | color: #333;
21 | position: relative;
22 | }
23 | .user-center-card__header__avatar {
24 | width: 96rpx;
25 | height: 96rpx;
26 | border-radius: 48rpx;
27 | overflow: hidden;
28 | }
29 |
30 | .user-center-card__header__name {
31 | font-size: 36rpx;
32 | line-height: 48rpx;
33 | color: #333;
34 | font-weight: bold;
35 | margin-left: 24rpx;
36 | margin-right: 16rpx;
37 | }
38 | .user-center-card__header__transparent {
39 | position: absolute;
40 | left: 0;
41 | top: 0;
42 | background-color: transparent;
43 | height: 100%;
44 | width: 100%;
45 | }
46 | .user-center-card__icon {
47 | line-height: 96rpx;
48 | }
49 |
--------------------------------------------------------------------------------
/pages/usercenter/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "个人中心",
3 | "navigationStyle": "custom",
4 | "usingComponents": {
5 | "t-popup": "tdesign-miniprogram/popup/popup",
6 | "t-icon": "tdesign-miniprogram/icon/icon",
7 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
8 | "t-cell": "tdesign-miniprogram/cell/cell",
9 | "t-user-center-card": "./components/user-center-card/index",
10 | "t-order-group": "./components/order-group/index",
11 | "t-toast": "tdesign-miniprogram/toast/toast"
12 | },
13 | "enablePullDownRefresh": true
14 | }
--------------------------------------------------------------------------------
/pages/usercenter/name-edit/index.js:
--------------------------------------------------------------------------------
1 | Page({
2 | data: {
3 | nameValue: '',
4 | },
5 | onLoad(options) {
6 | const { name } = options;
7 | this.setData({
8 | nameValue: name,
9 | });
10 | },
11 | onSubmit() {
12 | wx.navigateBack({ backRefresh: true });
13 | },
14 | clearContent() {
15 | this.setData({
16 | nameValue: '',
17 | });
18 | },
19 | });
20 |
--------------------------------------------------------------------------------
/pages/usercenter/name-edit/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "昵称",
3 | "usingComponents": {
4 | "t-input": "tdesign-miniprogram/input/input",
5 | "t-icon": "tdesign-miniprogram/icon/icon",
6 | "t-button": "tdesign-miniprogram/button/button"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/pages/usercenter/name-edit/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
10 | 最多可输入15个字
11 |
12 | 保存
13 |
14 |
15 |
--------------------------------------------------------------------------------
/pages/usercenter/name-edit/index.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | background-color: #f5f5f5;
3 | }
4 | page view {
5 | box-sizing: border-box;
6 | }
7 | .name-edit {
8 | padding-top: 20rpx;
9 | }
10 | .name-edit .name-edit__input--desc {
11 | font-size: 26rpx;
12 | padding: 16rpx 32rpx;
13 | color: #999;
14 | margin-bottom: 200rpx;
15 | }
16 | .name-edit .name-edit__wrapper {
17 | margin: 0 32rpx;
18 | }
19 |
--------------------------------------------------------------------------------
/pages/usercenter/person-info/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "个人资料",
3 | "usingComponents": {
4 | "t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
5 | "t-cell": "tdesign-miniprogram/cell/cell",
6 | "t-button": "tdesign-miniprogram/button/button",
7 | "t-image": "/components/webp-image/index",
8 | "t-dialog": "tdesign-miniprogram/dialog/dialog",
9 | "t-toast": "tdesign-miniprogram/toast/toast",
10 | "t-select-picker": "../components/ui-select-picker/index"
11 | }
12 | }
--------------------------------------------------------------------------------
/pages/usercenter/person-info/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
22 |
31 |
41 |
42 |
43 |
44 | 切换账号登录
45 |
46 |
54 |
55 |
--------------------------------------------------------------------------------
/pages/usercenter/person-info/index.wxss:
--------------------------------------------------------------------------------
1 | :host {
2 | background-color: #f5f5f5;
3 | }
4 | page view {
5 | box-sizing: border-box;
6 | }
7 | .person-info {
8 | padding-top: 20rpx;
9 | }
10 |
11 | .person-info__btn {
12 | width: 100%;
13 | border: 2rpx solid #ddd;
14 | border-radius: 48rpx;
15 | padding: 18rpx 0;
16 | display: flex;
17 | align-self: center;
18 | justify-content: center;
19 | }
20 | .person-info__wrapper {
21 | width: 100%;
22 | padding: 0 32rpx;
23 | padding-bottom: calc(env(safe-area-inset-bottom) + 20rpx);
24 | position: absolute;
25 | bottom: 0;
26 | left: 0;
27 | }
28 |
29 | .avatarUrl {
30 | width: 80rpx;
31 | height: 80rpx;
32 | border-radius: 50% !important;
33 | overflow: hidden;
34 | }
35 |
36 | .t-class-confirm {
37 | color: #fa550f !important;
38 | }
39 |
40 | .person-info .order-group__left {
41 | margin-right: 0;
42 | }
43 | .person-info .t-cell-class {
44 | height: 112rpx;
45 | }
46 |
--------------------------------------------------------------------------------
/services/_utils/delay.js:
--------------------------------------------------------------------------------
1 | export function delay(ms = 200) {
2 | return new Promise((resolve) => setTimeout(resolve, ms));
3 | }
4 |
--------------------------------------------------------------------------------
/services/_utils/timeout.js:
--------------------------------------------------------------------------------
1 | export function timeout(ms = 1000) {
2 | return new Promise((_, reject) => setTimeout(reject, ms));
3 | }
4 |
--------------------------------------------------------------------------------
/services/activity/fetchActivity.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取活动列表 */
4 | function mockFetchActivity(ID = 0) {
5 | const { delay } = require('../_utils/delay');
6 | const { getActivity } = require('../../model/activity');
7 |
8 | return delay().then(() => getActivity(ID));
9 | }
10 |
11 | /** 获取活动列表 */
12 | export function fetchActivity(ID = 0) {
13 | if (config.useMock) {
14 | return mockFetchActivity(ID);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/services/activity/fetchActivityList.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取活动列表 */
4 | function mockFetchActivityList(pageIndex = 1, pageSize = 20) {
5 | const { delay } = require('../_utils/delay');
6 | const { getActivityList } = require('../../model/activities');
7 |
8 | return delay().then(() => getActivityList(pageIndex, pageSize));
9 | }
10 |
11 | /** 获取活动列表 */
12 | export function fetchActivityList(pageIndex = 1, pageSize = 20) {
13 | if (config.useMock) {
14 | return mockFetchActivityList(pageIndex, pageSize);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/services/address/fetchAddress.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取收货地址 */
4 | function mockFetchDeliveryAddress(id) {
5 | const { delay } = require('../_utils/delay');
6 | const { genAddress } = require('../../model/address');
7 |
8 | return delay().then(() => genAddress(id));
9 | }
10 |
11 | /** 获取收货地址 */
12 | export function fetchDeliveryAddress(id = 0) {
13 | if (config.useMock) {
14 | return mockFetchDeliveryAddress(id);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
22 | /** 获取收货地址列表 */
23 | function mockFetchDeliveryAddressList(len = 0) {
24 | const { delay } = require('../_utils/delay');
25 | const { genAddressList } = require('../../model/address');
26 |
27 | return delay().then(() =>
28 | genAddressList(len).map((address) => {
29 | return {
30 | ...address,
31 | phoneNumber: address.phone,
32 | address: `${address.provinceName}${address.cityName}${address.districtName}${address.detailAddress}`,
33 | tag: address.addressTag,
34 | };
35 | }),
36 | );
37 | }
38 |
39 | /** 获取收货地址列表 */
40 | export function fetchDeliveryAddressList(len = 10) {
41 | if (config.useMock) {
42 | return mockFetchDeliveryAddressList(len);
43 | }
44 |
45 | return new Promise((resolve) => {
46 | resolve('real api');
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/services/cart/cart.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取购物车mock数据 */
4 | function mockFetchCartGroupData(params) {
5 | const { delay } = require('../_utils/delay');
6 | const { genCartGroupData } = require('../../model/cart');
7 |
8 | return delay().then(() => genCartGroupData(params));
9 | }
10 |
11 | /** 获取购物车数据 */
12 | export function fetchCartGroupData(params) {
13 | if (config.useMock) {
14 | return mockFetchCartGroupData(params);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/services/comments/fetchComments.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品评论 */
4 | function mockFetchComments(parmas) {
5 | const { delay } = require('../_utils/delay');
6 | const { getGoodsAllComments } = require('../../model/comments');
7 | return delay().then(() => getGoodsAllComments(parmas));
8 | }
9 |
10 | /** 获取商品评论 */
11 | export function fetchComments(parmas) {
12 | if (config.useMock) {
13 | return mockFetchComments(parmas);
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/services/comments/fetchCommentsCount.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品评论数 */
4 | function mockFetchCommentsCount(ID = 0) {
5 | const { delay } = require('../_utils/delay');
6 | const { getGoodsCommentsCount } = require('../../model/comments');
7 | return delay().then(() => getGoodsCommentsCount(ID));
8 | }
9 |
10 | /** 获取商品评论数 */
11 | export function fetchCommentsCount(ID = 0) {
12 | if (config.useMock) {
13 | return mockFetchCommentsCount(ID);
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/services/good/comments/fetchCommentDetail.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../../config/index';
2 | import { queryCommentDetail } from '../../../model/comments/queryDetail';
3 | /** 获取商品评价数据 */
4 | function mockQueryCommentDetail(params) {
5 | const { delay } = require('../../_utils/delay');
6 | const data = queryCommentDetail(params);
7 | return delay().then(() => {
8 | return data;
9 | });
10 | }
11 |
12 | /** 获取评价详情 */
13 | export function getCommentDetail(params) {
14 | if (config.useMock) {
15 | return mockQueryCommentDetail(params);
16 | }
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
--------------------------------------------------------------------------------
/services/good/fetchCategoryList.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品列表 */
4 | function mockFetchGoodCategory() {
5 | const { delay } = require('../_utils/delay');
6 | const { getCategoryList } = require('../../model/category');
7 | return delay().then(() => getCategoryList());
8 | }
9 |
10 | /** 获取商品列表 */
11 | export function getCategoryList() {
12 | if (config.useMock) {
13 | return mockFetchGoodCategory();
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/services/good/fetchGood.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品列表 */
4 | function mockFetchGood(ID = 0) {
5 | const { delay } = require('../_utils/delay');
6 | const { genGood } = require('../../model/good');
7 | return delay().then(() => genGood(ID));
8 | }
9 |
10 | /** 获取商品列表 */
11 | export function fetchGood(ID = 0) {
12 | if (config.useMock) {
13 | return mockFetchGood(ID);
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/services/good/fetchGoods.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品列表 */
4 | function mockFetchGoodsList(pageIndex = 1, pageSize = 20) {
5 | const { delay } = require('../_utils/delay');
6 | const { getGoodsList } = require('../../model/goods');
7 | return delay().then(() =>
8 | getGoodsList(pageIndex, pageSize).map((item) => {
9 | return {
10 | spuId: item.spuId,
11 | thumb: item.primaryImage,
12 | title: item.title,
13 | price: item.minSalePrice,
14 | originPrice: item.maxLinePrice,
15 | tags: item.spuTagList.map((tag) => tag.title),
16 | };
17 | }),
18 | );
19 | }
20 |
21 | /** 获取商品列表 */
22 | export function fetchGoodsList(pageIndex = 1, pageSize = 20) {
23 | if (config.useMock) {
24 | return mockFetchGoodsList(pageIndex, pageSize);
25 | }
26 | return new Promise((resolve) => {
27 | resolve('real api');
28 | });
29 | }
30 |
--------------------------------------------------------------------------------
/services/good/fetchGoodsDetailsComments.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品详情页评论数 */
4 | function mockFetchGoodDetailsCommentsCount(spuId = 0) {
5 | const { delay } = require('../_utils/delay');
6 | const {
7 | getGoodsDetailsCommentsCount,
8 | } = require('../../model/detailsComments');
9 | return delay().then(() => getGoodsDetailsCommentsCount(spuId));
10 | }
11 |
12 | /** 获取商品详情页评论数 */
13 | export function getGoodsDetailsCommentsCount(spuId = 0) {
14 | if (config.useMock) {
15 | return mockFetchGoodDetailsCommentsCount(spuId);
16 | }
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
22 | /** 获取商品详情页评论 */
23 | function mockFetchGoodDetailsCommentList(spuId = 0) {
24 | const { delay } = require('../_utils/delay');
25 | const { getGoodsDetailsComments } = require('../../model/detailsComments');
26 | return delay().then(() => getGoodsDetailsComments(spuId));
27 | }
28 |
29 | /** 获取商品详情页评论 */
30 | export function getGoodsDetailsCommentList(spuId = 0) {
31 | if (config.useMock) {
32 | return mockFetchGoodDetailsCommentList(spuId);
33 | }
34 | return new Promise((resolve) => {
35 | resolve('real api');
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/services/good/fetchGoodsList.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | import { config } from '../../config/index';
3 |
4 | /** 获取商品列表 */
5 | function mockFetchGoodsList(params) {
6 | const { delay } = require('../_utils/delay');
7 | const { getSearchResult } = require('../../model/search');
8 |
9 | const data = getSearchResult(params);
10 |
11 | if (data.spuList.length) {
12 | data.spuList.forEach((item) => {
13 | item.spuId = item.spuId;
14 | item.thumb = item.primaryImage;
15 | item.title = item.title;
16 | item.price = item.minSalePrice;
17 | item.originPrice = item.maxLinePrice;
18 | item.desc = '';
19 | if (item.spuTagList) {
20 | item.tags = item.spuTagList.map((tag) => tag.title);
21 | } else {
22 | item.tags = [];
23 | }
24 | });
25 | }
26 | return delay().then(() => {
27 | return data;
28 | });
29 | }
30 |
31 | /** 获取商品列表 */
32 | export function fetchGoodsList(params) {
33 | if (config.useMock) {
34 | return mockFetchGoodsList(params);
35 | }
36 | return new Promise((resolve) => {
37 | resolve('real api');
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/services/good/fetchSearchHistory.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取搜索历史 */
4 | function mockSearchHistory() {
5 | const { delay } = require('../_utils/delay');
6 | const { getSearchHistory } = require('../../model/search');
7 | return delay().then(() => getSearchHistory());
8 | }
9 |
10 | /** 获取搜索历史 */
11 | export function getSearchHistory() {
12 | if (config.useMock) {
13 | return mockSearchHistory();
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
20 | /** 获取搜索历史 */
21 | function mockSearchPopular() {
22 | const { delay } = require('../_utils/delay');
23 | const { getSearchPopular } = require('../../model/search');
24 | return delay().then(() => getSearchPopular());
25 | }
26 |
27 | /** 获取搜索历史 */
28 | export function getSearchPopular() {
29 | if (config.useMock) {
30 | return mockSearchPopular();
31 | }
32 | return new Promise((resolve) => {
33 | resolve('real api');
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/services/good/fetchSearchResult.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-param-reassign */
2 | import { config } from '../../config/index';
3 |
4 | /** 获取搜索历史 */
5 | function mockSearchResult(params) {
6 | const { delay } = require('../_utils/delay');
7 | const { getSearchResult } = require('../../model/search');
8 |
9 | const data = getSearchResult(params);
10 |
11 | if (data.spuList.length) {
12 | data.spuList.forEach((item) => {
13 | item.spuId = item.spuId;
14 | item.thumb = item.primaryImage;
15 | item.title = item.title;
16 | item.price = item.minSalePrice;
17 | item.originPrice = item.maxLinePrice;
18 | if (item.spuTagList) {
19 | item.tags = item.spuTagList.map((tag) => ({ title: tag.title }));
20 | } else {
21 | item.tags = [];
22 | }
23 | });
24 | }
25 | return delay().then(() => {
26 | return data;
27 | });
28 | }
29 |
30 | /** 获取搜索历史 */
31 | export function getSearchResult(params) {
32 | if (config.useMock) {
33 | return mockSearchResult(params);
34 | }
35 | return new Promise((resolve) => {
36 | resolve('real api');
37 | });
38 | }
39 |
--------------------------------------------------------------------------------
/services/home/home.js:
--------------------------------------------------------------------------------
1 | import { config, cdnBase } from '../../config/index';
2 |
3 | /** 获取首页数据 */
4 | function mockFetchHome() {
5 | const { delay } = require('../_utils/delay');
6 | const { genSwiperImageList } = require('../../model/swiper');
7 | return delay().then(() => {
8 | return {
9 | swiper: genSwiperImageList(),
10 | tabList: [
11 | {
12 | text: '精选推荐',
13 | key: 0,
14 | },
15 | {
16 | text: '夏日防晒',
17 | key: 1,
18 | },
19 | {
20 | text: '二胎大作战',
21 | key: 2,
22 | },
23 | {
24 | text: '人气榜',
25 | key: 3,
26 | },
27 | {
28 | text: '好评榜',
29 | key: 4,
30 | },
31 | {
32 | text: 'RTX 30',
33 | key: 5,
34 | },
35 | {
36 | text: '手机也疯狂',
37 | key: 6,
38 | },
39 | ],
40 | activityImg: `${cdnBase}/activity/banner.png`,
41 | };
42 | });
43 | }
44 |
45 | /** 获取首页数据 */
46 | export function fetchHome() {
47 | if (config.useMock) {
48 | return mockFetchHome();
49 | }
50 | return new Promise((resolve) => {
51 | resolve('real api');
52 | });
53 | }
54 |
--------------------------------------------------------------------------------
/services/order/orderDetail.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取订单详情mock数据 */
4 | function mockFetchOrderDetail(params) {
5 | const { delay } = require('../_utils/delay');
6 | const { genOrderDetail } = require('../../model/order/orderDetail');
7 |
8 | return delay().then(() => genOrderDetail(params));
9 | }
10 |
11 | /** 获取订单详情数据 */
12 | export function fetchOrderDetail(params) {
13 | if (config.useMock) {
14 | return mockFetchOrderDetail(params);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
22 | /** 获取客服mock数据 */
23 | function mockFetchBusinessTime(params) {
24 | const { delay } = require('../_utils/delay');
25 | const { genBusinessTime } = require('../../model/order/orderDetail');
26 |
27 | return delay().then(() => genBusinessTime(params));
28 | }
29 |
30 | /** 获取客服数据 */
31 | export function fetchBusinessTime(params) {
32 | if (config.useMock) {
33 | return mockFetchBusinessTime(params);
34 | }
35 |
36 | return new Promise((resolve) => {
37 | resolve('real api');
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/services/order/orderList.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取订单列表mock数据 */
4 | function mockFetchOrders(params) {
5 | const { delay } = require('../_utils/delay');
6 | const { genOrders } = require('../../model/order/orderList');
7 |
8 | return delay(200).then(() => genOrders(params));
9 | }
10 |
11 | /** 获取订单列表数据 */
12 | export function fetchOrders(params) {
13 | if (config.useMock) {
14 | return mockFetchOrders(params);
15 | }
16 |
17 | return new Promise((resolve) => {
18 | resolve('real api');
19 | });
20 | }
21 |
22 | /** 获取订单列表mock数据 */
23 | function mockFetchOrdersCount(params) {
24 | const { delay } = require('../_utils/delay');
25 | const { genOrdersCount } = require('../../model/order/orderList');
26 |
27 | return delay().then(() => genOrdersCount(params));
28 | }
29 |
30 | /** 获取订单列表统计 */
31 | export function fetchOrdersCount(params) {
32 | if (config.useMock) {
33 | return mockFetchOrdersCount(params);
34 | }
35 |
36 | return new Promise((resolve) => {
37 | resolve('real api');
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/services/order/orderSubmitComment.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取评价商品 */
4 | function mockGetGoods(parameter) {
5 | const { delay } = require('../_utils/delay');
6 | const { getGoods } = require('../../model/submitComment');
7 | const data = getGoods(parameter);
8 |
9 | return delay().then(() => {
10 | return data;
11 | });
12 | }
13 |
14 | /** 获取评价商品 */
15 | export function getGoods(parameter) {
16 | if (config.useMock) {
17 | return mockGetGoods(parameter);
18 | }
19 | return new Promise((resolve) => {
20 | resolve('real api');
21 | });
22 | }
23 |
--------------------------------------------------------------------------------
/services/promotion/detail.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取商品列表 */
4 | function mockFetchPromotion(ID = 0) {
5 | const { delay } = require('../_utils/delay');
6 | const { getPromotion } = require('../../model/promotion');
7 | return delay().then(() => getPromotion(ID));
8 | }
9 |
10 | /** 获取商品列表 */
11 | export function fetchPromotion(ID = 0) {
12 | if (config.useMock) {
13 | return mockFetchPromotion(ID);
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/services/usercenter/fetchPerson.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取个人中心信息 */
4 | function mockFetchPerson() {
5 | const { delay } = require('../_utils/delay');
6 | const { genSimpleUserInfo } = require('../../model/usercenter');
7 | const { genAddress } = require('../../model/address');
8 | const address = genAddress();
9 | return delay().then(() => ({
10 | ...genSimpleUserInfo(),
11 | address: {
12 | provinceName: address.provinceName,
13 | provinceCode: address.provinceCode,
14 | cityName: address.cityName,
15 | cityCode: address.cityCode,
16 | },
17 | }));
18 | }
19 |
20 | /** 获取个人中心信息 */
21 | export function fetchPerson() {
22 | if (config.useMock) {
23 | return mockFetchPerson();
24 | }
25 | return new Promise((resolve) => {
26 | resolve('real api');
27 | });
28 | }
29 |
--------------------------------------------------------------------------------
/services/usercenter/fetchUsercenter.js:
--------------------------------------------------------------------------------
1 | import { config } from '../../config/index';
2 |
3 | /** 获取个人中心信息 */
4 | function mockFetchUserCenter() {
5 | const { delay } = require('../_utils/delay');
6 | const { genUsercenter } = require('../../model/usercenter');
7 | return delay(200).then(() => genUsercenter());
8 | }
9 |
10 | /** 获取个人中心信息 */
11 | export function fetchUserCenter() {
12 | if (config.useMock) {
13 | return mockFetchUserCenter();
14 | }
15 | return new Promise((resolve) => {
16 | resolve('real api');
17 | });
18 | }
19 |
--------------------------------------------------------------------------------
/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/style/theme.wxss:
--------------------------------------------------------------------------------
1 | /* 主题定制 */
2 | .t-input {
3 | --td-input-placeholder-text-color: #bbbbbb;
4 | --td-input-text-color: #333333;
5 | }
6 |
7 | .t-tab-bar {
8 | --td-tab-bar-color: #bbb;
9 | --td-tab-bar-active-color: #333;
10 | }
11 |
12 | .t-cascader {
13 | --td-cascader-active-color: #fa4126;
14 | }
15 |
16 | .t-switch {
17 | --td-switch-checked-color: #34c759;
18 | }
19 |
20 | .t-button {
21 | --td-button-font-weight: 500;
22 | --td-button-medium-font-size: 32rpx;
23 | --td-button-default-color: #fff;
24 | --td-button-default-bg-color: #fa4126;
25 | --td-button-default-border-color: #fa4126;
26 | --td-button-default-disabled-color: #fff;
27 | --td-button-default-disabled-bg: #cccccc;
28 | --td-button-default-disabled-border-color: #cccccc;
29 | --td-button-default-active-bg-color: #fa4126;
30 | --td-button-default-active-border-color: #fa4126;
31 | }
32 |
33 | .t-textarea {
34 | --td-textarea-placeholder-color: #bbb;
35 | }
36 |
37 | .t-checkbox {
38 | --td-checkbox-icon-checked-color: #fa4126;
39 | }
40 |
41 | .dialog__button-confirm {
42 | color: #fa4126 !important;
43 | }
44 |
45 | .dialog__button-cancel {
46 | color: #aeb3b7 !important;
47 | }
48 |
--------------------------------------------------------------------------------
/utils/addressParse.js:
--------------------------------------------------------------------------------
1 | import { areaData } from '../config/index';
2 |
3 | const addressParse = (provinceName, cityName, countryName) => {
4 | return new Promise((resolve, reject) => {
5 | try {
6 | const province = areaData.find((v) => v.label === provinceName);
7 | const { value: provinceCode } = province;
8 | const city = province.children.find((v) => v.label === cityName);
9 | const { value: cityCode } = city;
10 | const country = city.children.find((v) => v.label === countryName);
11 | const { value: districtCode } = country;
12 | resolve({
13 | provinceCode,
14 | cityCode,
15 | districtCode,
16 | });
17 | } catch (error) {
18 | reject('地址解析失败');
19 | }
20 | });
21 | };
22 |
23 | module.exports = {
24 | addressParse,
25 | };
26 |
--------------------------------------------------------------------------------
/utils/getPermission.js:
--------------------------------------------------------------------------------
1 | const getPermission = ({ code, name }) => {
2 | return new Promise((resolve, reject) => {
3 | wx.getSetting({
4 | success: (res) => {
5 | if (res.authSetting[code] === false) {
6 | wx.showModal({
7 | title: `获取${name}失败`,
8 | content: `获取${name}失败,请在【右上角】-小程序【设置】项中,将【${name}】开启。`,
9 | confirmText: '去设置',
10 | confirmColor: '#FA550F',
11 | cancelColor: '取消',
12 | success(res) {
13 | if (res.confirm) {
14 | wx.openSetting({
15 | success(settinRes) {
16 | if (settinRes.authSetting[code] === true) {
17 | resolve();
18 | } else {
19 | console.warn('用户未打开权限', name, code);
20 | reject();
21 | }
22 | },
23 | });
24 | } else {
25 | reject();
26 | }
27 | },
28 | fail() {
29 | reject();
30 | },
31 | });
32 | } else {
33 | resolve();
34 | }
35 | },
36 | fail() {
37 | reject();
38 | },
39 | });
40 | });
41 | };
42 |
43 | module.exports = {
44 | getPermission,
45 | };
46 |
--------------------------------------------------------------------------------
/utils/mock.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 随机打散字符串
3 | * @param {number} n 长度
4 | * @param {string} str 字符串
5 | * @returns
6 | */
7 | function generateMixed(n, str) {
8 | var res = '';
9 | for (var i = 0; i < n; i++) {
10 | var id = Math.ceil(Math.random() * 35);
11 | res += str[id];
12 | }
13 | return res;
14 | }
15 |
16 | /**
17 | * 生成随机数
18 | * @param {number} min 最小值
19 | * @param {number} max 最大值
20 | * @returns
21 | */
22 | function getRandomNum(min, max) {
23 | var range = max - min;
24 | var rand = Math.random();
25 | return min + Math.round(rand * range);
26 | }
27 |
28 | /**
29 | * 生成随机IP
30 | * @returns
31 | */
32 | function mockIp() {
33 | return `10.${getRandomNum(1, 254)}.${getRandomNum(1, 254)}.${getRandomNum(
34 | 1,
35 | 254,
36 | )}`;
37 | }
38 |
39 | function mockReqId() {
40 | return `${getRandomNum(100000, 999999)}.${new Date().valueOf()}${getRandomNum(
41 | 1000,
42 | 9999,
43 | )}.${getRandomNum(10000000, 99999999)}`;
44 | }
45 |
46 | module.exports = {
47 | generateMixed,
48 | mockIp,
49 | mockReqId,
50 | getRandomNum,
51 | };
52 |
--------------------------------------------------------------------------------