├── .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 | 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 | 8 | 9 | 10 | 11 | 已选规格 12 | 13 | {{spec}} 19 | 20 | 21 | 22 | 23 | 我知道了 24 | 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 | 22 | 规则详情 23 | 24 | 25 | 优惠券有效时间 26 | {{detail.timeLimit}} 27 | 28 | 29 | 优惠券说明 30 | {{detail.desc}} 31 | 32 | 33 | 使用须知 34 | {{detail.useNotes}} 35 | 36 | 37 | 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 | 2 | 8 | {{ title }} 9 | 10 | 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 | 2 | 3 | 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 | 2 | 3 | 4 | 5 | 6 | 7 | {{userName}} 8 | {{commentTime}} 9 | 10 | 11 | 12 | 13 | 14 | {{goodsDetailInfo}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 店家回复: 24 | {{sellerReply}} 25 | 26 | 27 | 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 | 5 | 6 | 15 | 16 | 17 | {{shopCartNum > 99 ? '99+' : shopCartNum}} 18 | 19 | 20 | {{item.title}} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 加入购物车 28 | 29 | 30 | 立即购买 31 | 32 | 33 | 34 | 35 | 36 | 37 | 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 | 3 | 4 | 5 | 6 | 7 | {{title}} 8 | 9 | 10 | 11 | 18 | {{item.tag}} 19 | 20 | {{item.label ? item.label : ''}} 21 | 22 | 28 | 29 | 30 | 31 | 32 | 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 | 3 | 4 | 5 | 6 | 16 | 17 | 18 | {{order.statusDesc}} 19 | 20 | 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 | 8 | 9 | {{title}} 10 | 11 | 12 | 21 | 22 | 28 | 34 | 35 | 36 | 37 | 38 | 44 | {{confirmButtonText}} 45 | 46 | 47 | 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 | 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 | 最多支持添加20个收货地址 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 | 4 | 取消 5 | {{title}} 6 | 确定 7 | 8 | 9 | {{title}} 10 | 11 | 12 | 13 | {{ item.name }} 14 | 15 | 16 | 17 | 取消 18 | 确定 19 | 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 | 5 | 6 | {{'请登录'}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{userInfo.nickName || '微信用户'}} 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 31 | {{userInfo.nickName || '微信用户'}} 32 | 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 | --------------------------------------------------------------------------------