init
This commit is contained in:
commit
369aecfb32
160
.eslintrc.js
Normal file
160
.eslintrc.js
Normal file
@ -0,0 +1,160 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
es6: true,
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020,
|
||||
// ECMAScript modules 模式
|
||||
sourceType: 'module',
|
||||
},
|
||||
extends: ['plugin:prettier/recommended', 'prettier'],
|
||||
globals: {
|
||||
wx: true,
|
||||
App: true,
|
||||
Page: true,
|
||||
Component: true,
|
||||
getApp: true,
|
||||
getCurrentPages: true,
|
||||
Behavior: true,
|
||||
global: true,
|
||||
__wxConfig: true,
|
||||
},
|
||||
ignorePatterns: ['*.wxs'],
|
||||
rules: {
|
||||
'prettier/prettier': 'warn',
|
||||
'no-undef': 'off',
|
||||
camelcase: ['error', { ignoreDestructuring: true }],
|
||||
'class-name-casing': 'off',
|
||||
'no-console': ['warn', { allow: ['warn', 'error'] }],
|
||||
'no-debugger': 'error',
|
||||
'no-unused-expressions': [
|
||||
'error',
|
||||
{ allowShortCircuit: true, allowTernary: true },
|
||||
],
|
||||
'no-empty-interface': 'off',
|
||||
'no-use-before-define': ['error', { functions: false }],
|
||||
'no-useless-constructor': 'error',
|
||||
'prefer-const': 'error',
|
||||
'prefer-destructuring': [
|
||||
'error',
|
||||
{
|
||||
AssignmentExpression: {
|
||||
array: false,
|
||||
object: false,
|
||||
},
|
||||
VariableDeclarator: {
|
||||
array: false,
|
||||
object: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
enforceForRenamedProperties: false,
|
||||
},
|
||||
],
|
||||
'no-const-assign': 'error',
|
||||
'no-new-object': 'error',
|
||||
'no-prototype-builtins': 'error',
|
||||
'no-array-constructor': 'error',
|
||||
'array-callback-return': 'warn',
|
||||
'prefer-template': 'error',
|
||||
'no-useless-escape': 'error',
|
||||
'wrap-iife': ['error', 'outside'],
|
||||
'space-before-function-paren': [
|
||||
'warn',
|
||||
{
|
||||
anonymous: 'always',
|
||||
named: 'never',
|
||||
asyncArrow: 'always',
|
||||
},
|
||||
],
|
||||
'no-param-reassign': [
|
||||
'warn',
|
||||
{
|
||||
props: true,
|
||||
ignorePropertyModificationsFor: [
|
||||
'acc', // for reduce accumulators
|
||||
'accumulator', // for reduce accumulators
|
||||
'e', // for e.returnvalue
|
||||
'ctx', // for Koa routing
|
||||
'req', // for Express requests
|
||||
'request', // for Express requests
|
||||
'res', // for Express responses
|
||||
'response', // for Express responses
|
||||
'$scope', // for Angular 1 scopes
|
||||
'staticContext', // for ReactRouter context
|
||||
'state', // for Vuex
|
||||
],
|
||||
},
|
||||
],
|
||||
'no-confusing-arrow': 'warn',
|
||||
'no-dupe-class-members': 'error',
|
||||
'no-iterator': 'warn',
|
||||
'dot-notation': 'warn',
|
||||
'one-var': ['warn', 'never'],
|
||||
'no-multi-assign': 'error',
|
||||
'no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'after-used',
|
||||
ignoreRestSiblings: true,
|
||||
argsIgnorePattern: '^_.+',
|
||||
varsIgnorePattern: '^_.+',
|
||||
},
|
||||
],
|
||||
eqeqeq: ['warn', 'always'],
|
||||
'no-case-declarations': 'error',
|
||||
'no-nested-ternary': 'warn',
|
||||
'no-unneeded-ternary': 'warn',
|
||||
'no-mixed-operators': [
|
||||
'error',
|
||||
{
|
||||
groups: [
|
||||
['%', '**'],
|
||||
['%', '+'],
|
||||
['%', '-'],
|
||||
['%', '*'],
|
||||
['%', '/'],
|
||||
['&', '|', '<<', '>>', '>>>'],
|
||||
['==', '!=', '===', '!=='],
|
||||
['&&', '||'],
|
||||
],
|
||||
allowSamePrecedence: false,
|
||||
},
|
||||
],
|
||||
'no-else-return': [
|
||||
'warn',
|
||||
{
|
||||
allowElseIf: false,
|
||||
},
|
||||
],
|
||||
'no-new-wrappers': 'warn',
|
||||
indent: [
|
||||
'warn',
|
||||
2,
|
||||
{
|
||||
SwitchCase: 1,
|
||||
VariableDeclarator: 1,
|
||||
outerIIFEBody: 1,
|
||||
FunctionDeclaration: {
|
||||
parameters: 1,
|
||||
body: 1,
|
||||
},
|
||||
FunctionExpression: {
|
||||
parameters: 1,
|
||||
body: 1,
|
||||
},
|
||||
CallExpression: {
|
||||
arguments: 1,
|
||||
},
|
||||
ArrayExpression: 1,
|
||||
ObjectExpression: 1,
|
||||
ImportDeclaration: 1,
|
||||
flatTernaryExpressions: false,
|
||||
ignoreComments: false,
|
||||
},
|
||||
],
|
||||
'linebreak-style': ['warn', 'unix'],
|
||||
},
|
||||
};
|
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
node_modules/
|
||||
yarn-error.log
|
||||
miniprogram/
|
||||
miniprogram_npm/
|
||||
miniprogram_dist/
|
||||
.DS_Store
|
||||
$node_modules/
|
||||
.history/
|
||||
**/dist
|
||||
components/**/*.lock
|
||||
components/**/package-lock.json
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
project.private.config.json
|
||||
.eslintcache
|
4
.husky/commit-msg
Normal file
4
.husky/commit-msg
Normal file
@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx --no-install commitlint --edit ""
|
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
4
.husky/prepare-commit-msg
Normal file
4
.husky/prepare-commit-msg
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
exec < /dev/tty && npx git-cz --hook || true
|
9
.npmrc
Normal file
9
.npmrc
Normal file
@ -0,0 +1,9 @@
|
||||
# 去除注释可以使用代理进行安装
|
||||
# proxy=http://127.0.0.1:1080
|
||||
# https_proxy=http://127.0.0.1:1080
|
||||
|
||||
# 去除注释可以使用淘宝源
|
||||
# registry=https://registry.npm.taobao.org
|
||||
|
||||
# 去除注释可以使用腾讯源
|
||||
#registry=http://mirrors.tencent.com/npm/
|
3
.prettierignore
Normal file
3
.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
miniprogram_npm
|
||||
package.json
|
||||
project.config.json
|
49
.prettierrc.yml
Normal file
49
.prettierrc.yml
Normal file
@ -0,0 +1,49 @@
|
||||
# 一行最多 100 字符
|
||||
printWidth: 120
|
||||
# 使用 2 个空格缩进
|
||||
tabWidth: 2
|
||||
# 不使用缩进符,而使用空格
|
||||
useTabs: false
|
||||
# 行尾需要分号
|
||||
semi: true
|
||||
# 使用单引号
|
||||
singleQuote: true
|
||||
# 对象的 key 仅在必要时用引号
|
||||
quoteProps: as-needed
|
||||
# jsx 不使用单引号,而使用双引号
|
||||
jsxSingleQuote: false
|
||||
# 末尾需要逗号
|
||||
trailingComma: all
|
||||
# 大括号内的首尾需要空格
|
||||
bracketSpacing: true
|
||||
# jsx 标签的反尖括号需要换行
|
||||
jsxBracketSameLine: false
|
||||
# 箭头函数,只有一个参数的时候,不需要括号
|
||||
arrowParens: always
|
||||
# 每个文件格式化的范围是文件的全部内容
|
||||
rangeStart: 0
|
||||
# 不需要写文件开头的 @prettier
|
||||
requirePragma: false
|
||||
# 不需要自动在文件开头插入 @prettier
|
||||
insertPragma: false
|
||||
# 使用默认的折行标准
|
||||
proseWrap: preserve
|
||||
# 根据显示样式决定 html 要不要折行
|
||||
htmlWhitespaceSensitivity: css
|
||||
# 换行符使用 lf
|
||||
endOfLine: lf
|
||||
# 后缀文件名特有规则
|
||||
overrides:
|
||||
- files: '*.{wxss,less}'
|
||||
options:
|
||||
parser: less
|
||||
- files: '*.json,.*rc'
|
||||
options:
|
||||
parser: json
|
||||
- files: '*.{wxml,html}'
|
||||
options:
|
||||
parser: html
|
||||
htmlWhitespaceSensitivity: strict
|
||||
- files: '*.wxs'
|
||||
options:
|
||||
parser: babel
|
34
.vscode/settings.json
vendored
Normal file
34
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"eslint.enable": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.tslint": true,
|
||||
"source.fixAll.eslint": true
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"[wxss]": {
|
||||
"editor.defaultFormatter": "HookyQR.beautify"
|
||||
},
|
||||
"wxmlConfig.onSaveFormat": true,
|
||||
"wxmlConfig.format": {
|
||||
"brace_style": "collapse",
|
||||
"indent_inner_html": true,
|
||||
"indent_scripts": "keep",
|
||||
"indent_size": 2,
|
||||
"indent_char": " ",
|
||||
"unformatted": "['wxs']",
|
||||
"disable_automatic_closing_labels": false,
|
||||
"preserve_newlines": true,
|
||||
"wrap_attributes": "force-expand-multiline",
|
||||
"wrap_attributes_count": 4,
|
||||
"wrap_attributes_indent_size": 2
|
||||
},
|
||||
"editor.tabSize": 2
|
||||
}
|
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-present TDesign
|
||||
|
||||
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:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
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.
|
138
README.md
Normal file
138
README.md
Normal file
@ -0,0 +1,138 @@
|
||||
<p align="center">
|
||||
<a href="https://tdesign.tencent.com/" target="_blank">
|
||||
<img alt="TDesign Logo" width="200" src="https://tdesign.gtimg.com/site/TDesign.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://img.shields.io/github/stars/Tencent/tdesign-miniprogram-starter-retail">
|
||||
<img src="https://img.shields.io/github/stars/Tencent/tdesign-miniprogram-starter-retail" alt="License">
|
||||
</a>
|
||||
<a href="https://github.com/Tencent/tdesign-miniprogram-starter-retail/issues">
|
||||
<img src="https://img.shields.io/github/issues/Tencent/tdesign-miniprogram-starter-retail" alt="License">
|
||||
</a>
|
||||
<a href="https://github.com/Tencent/tdesign-miniprogram-starter-retail/LICENSE">
|
||||
<img src="https://img.shields.io/github/license/Tencent/tdesign-miniprogram-starter-retail" alt="License">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/tdesign-miniprogram">
|
||||
<img src="https://img.shields.io/npm/v/tdesign-miniprogram.svg?sanitize=true" alt="Version">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/tdesign-miniprogram">
|
||||
<img src="https://img.shields.io/npm/dw/tdesign-miniprogram" alt="Downloads">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# TDesign 零售行业模版示例小程序
|
||||
|
||||
TDesign 零售模版示例小程序采用 [TDesign 企业级设计体系小程序解决方案](https://tdesign.tencent.com/miniprogram/overview) 进行搭建,依赖 [TDesign 微信小程序组件库](https://github.com/Tencent/tdesign-miniprogram),涵盖完整的基本零售场景需求。
|
||||
|
||||
## :high_brightness: 预览
|
||||
|
||||
<p>请使用微信扫描以下二维码:</p>
|
||||
|
||||
<img src="https://we-retail-static-1300977798.cos.ap-guangzhou.myqcloud.com/retail-mp/common/qrcode.jpeg" width = "200" height = "200" alt="模版小程序二维码" align=center />
|
||||
|
||||
## :pushpin: 项目介绍
|
||||
|
||||
### 1. 业务介绍
|
||||
|
||||
零售行业模版小程序是个经典的单店版电商小程序,涵盖了电商的黄金链路流程,从商品->购物车->结算->订单等。小程序总共包含 28 个完整的页面,涵盖首页,商品详情页,个人中心,售后流程等基础页面。采用 mock 数据进行展示,提供了完整的零售商品展示、交易与售后流程。页面详情:
|
||||
|
||||
<img src="https://cdn-we-retail.ym.tencent.com/tsr/tdesign-starter-readmeV1.png" width = "650" height = "900" alt="模版小程序页面详情" align=center />
|
||||
|
||||
|
||||
|
||||
主要页面截图如下:
|
||||
|
||||
<p align="center">
|
||||
<img alt="example-home" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/home.png" />
|
||||
<img alt="example-sort" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v2/sort.png" />
|
||||
<img alt="example-cart" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/cart.png" />
|
||||
<img alt="example-user-center" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/user-center.png" />
|
||||
<img alt="example-goods-detail" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/goods-detail.png" />
|
||||
<img alt="example-pay" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/pay.png" />
|
||||
<img alt="example-order" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v1/order.png" />
|
||||
<img alt="example-order-detail" width="200" src="https://cdn-we-retail.ym.tencent.com/tsr/example/v2/order.png" />
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
### 2. 项目构成
|
||||
|
||||
零售行业模版小程序采用基础的 JavaScript + WXSS + ESLint 进行构建,降低了使用门槛。
|
||||
|
||||
项目目录结构如下:
|
||||
|
||||
```
|
||||
|-- tdesign-miniprogram-starter
|
||||
|-- README.md
|
||||
|-- app.js
|
||||
|-- app.json
|
||||
|-- app.wxss
|
||||
|-- components // 公共组件库
|
||||
|-- config // 基础配置
|
||||
|-- custom-tab-bar // 自定义 tabbar
|
||||
|-- model // mock 数据
|
||||
|-- pages
|
||||
| |-- cart // 购物车相关页面
|
||||
| |-- coupon // 优惠券相关页面
|
||||
| |-- goods // 商品相关页面
|
||||
| |-- home // 首页
|
||||
| |-- order // 订单售后相关页面
|
||||
| |-- promotion-detail // 营销活动页面
|
||||
| |-- usercenter // 个人中心及收货地址相关页面
|
||||
|-- services // 请求接口
|
||||
|-- style // 公共样式与iconfont
|
||||
|-- utils // 工具库
|
||||
```
|
||||
|
||||
### 3. 数据模拟
|
||||
|
||||
零售小程序采用真实的接口数据,模拟后端返回逻辑,在小程序展示完整的购物场景与购物体验逻辑。
|
||||
|
||||
### 4. 添加新页面
|
||||
|
||||
1. 在 `pages `目录下创建对应的页面文件夹
|
||||
2. 在 `app.json` 文件中的 ` "pages"` 数组中加上页面路径
|
||||
3. [可选] 在 `project.config.json` 文件的 `"miniprogram-list"` 下添加页面配置
|
||||
|
||||
## :hammer: 构建运行
|
||||
|
||||
1. `npm install`
|
||||
2. 小程序开发工具中引入工程
|
||||
3. 构建 npm
|
||||
|
||||
## :art: 代码风格控制
|
||||
|
||||
`eslint` `prettier`
|
||||
|
||||
## :iphone: 基础库版本
|
||||
|
||||
最低基础库版本`^2.6.5`
|
||||
|
||||
## :dart: 反馈&合作
|
||||
|
||||
本开源项目是由[腾讯云Mall团队](https://ym.qq.com/)核心贡献。项目也在[github](https://github.com/Tencent/tdesign-miniprogram-starter-retail)上做了开源,有任何问题或者建议都欢迎在issue上留言反馈, 或者加入TD小程序开发者群进行反馈:star2::star2::star2:
|
||||
|
||||
<img src="https://cdn.qa.ym.qq.com/officical-site/assets/logo.png?auto=format&fit=max&w=384" width = "100" height = "30" alt="模版小程序页面详情" align=center />
|
||||
|
||||
[云Mall](https://ym.qq.com/)是基于微信小程序的电商SaaS产品,致力于提供全面、可靠的小程序商城经营服务,助力商家成功。支持标准化和定开类型商家入驻。
|
||||
|
||||
企业微信群
|
||||
TDesign 团队会及时在企业微信大群中同步发布版本、问题修复信息,也会有一些关于组件库建设的讨论,欢迎微信或企业微信扫码入群交流:
|
||||
|
||||
<img src="https://oteam-tdesign-1258344706.cos.ap-guangzhou.myqcloud.com/site/doc/TDesign%20IM.png" width = "200" height = "200" alt="模版小程序页面详情" align=center />
|
||||
|
||||
|
||||
邮件联系:tdesign@tencent.com
|
||||
|
||||
## :link: TDesign 其他技术栈实现
|
||||
|
||||
- 移动端 小程序 实现:[mobile-miniprogram](https://github.com/Tencent/tdesign-miniprogram)
|
||||
- 桌面端 Vue 2 实现:[web-vue](https://github.com/Tencent/tdesign-vue)
|
||||
- 桌面端 Vue 3 实现:[web-vue-next](https://github.com/Tencent/tdesign-vue-next)
|
||||
- 桌面端 React 实现:[web-react](https://github.com/Tencent/tdesign-react)
|
||||
|
||||
## :page_with_curl: 开源协议
|
||||
|
||||
TDesign 遵循 [MIT 协议](https://github.com/Tencent/tdesign-miniprogram-starter-retail/LICENSE)。
|
BIN
__MACOSX/components/._.DS_Store
Normal file
BIN
__MACOSX/components/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/model/._.DS_Store
Normal file
BIN
__MACOSX/model/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/pages/._.DS_Store
Normal file
BIN
__MACOSX/pages/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/pages/coupon/._.DS_Store
Normal file
BIN
__MACOSX/pages/coupon/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/pages/goods/._.DS_Store
Normal file
BIN
__MACOSX/pages/goods/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/pages/order/._.DS_Store
Normal file
BIN
__MACOSX/pages/order/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/pages/usercenter/._.DS_Store
Normal file
BIN
__MACOSX/pages/usercenter/._.DS_Store
Normal file
Binary file not shown.
BIN
__MACOSX/services/._.DS_Store
Normal file
BIN
__MACOSX/services/._.DS_Store
Normal file
Binary file not shown.
8
app.js
Normal file
8
app.js
Normal file
@ -0,0 +1,8 @@
|
||||
import updateManager from './common/updateManager';
|
||||
|
||||
App({
|
||||
onLaunch: function () {},
|
||||
onShow: function () {
|
||||
updateManager();
|
||||
},
|
||||
});
|
73
app.json
Normal file
73
app.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/home/home",
|
||||
"pages/usercenter/index",
|
||||
"pages/usercenter/person-info/index",
|
||||
"pages/usercenter/address/list/index",
|
||||
"pages/usercenter/address/edit/index",
|
||||
"pages/goods/list/index",
|
||||
"pages/goods/details/index",
|
||||
"pages/goods/category/index",
|
||||
"pages/goods/search/index",
|
||||
"pages/goods/result/index",
|
||||
"pages/cart/index",
|
||||
"pages/order/order-confirm/index",
|
||||
"pages/order/receipt/index",
|
||||
"pages/order/pay-result/index",
|
||||
"pages/order/order-list/index",
|
||||
"pages/order/order-detail/index",
|
||||
"pages/goods/comments/index",
|
||||
"pages/order/apply-service/index",
|
||||
"pages/order/after-service-list/index",
|
||||
"pages/order/after-service-detail/index",
|
||||
"pages/goods/comments/create/index",
|
||||
"pages/coupon/coupon-list/index",
|
||||
"pages/coupon/coupon-detail/index",
|
||||
"pages/coupon/coupon-activity-goods/index",
|
||||
"pages/promotion-detail/index",
|
||||
"pages/order/fill-tracking-no/index",
|
||||
"pages/order/delivery-detail/index",
|
||||
"pages/order/invoice/index",
|
||||
"pages/usercenter/name-edit/index"
|
||||
],
|
||||
"tabBar": {
|
||||
"custom": true,
|
||||
"color": "#666666",
|
||||
"selectedColor": "#FF5F15",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "black",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/home",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/goods/category/index",
|
||||
"text": "分类"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/cart/index",
|
||||
"text": "购物车"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/usercenter/index",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"requiredPrivateInfos": ["chooseAddress"],
|
||||
"lazyCodeLoading": "requiredComponents",
|
||||
"usingComponents": {},
|
||||
"window": {
|
||||
"backgroundTextStyle": "light",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTitleText": "Weixin",
|
||||
"navigationBarTextStyle": "black"
|
||||
},
|
||||
"sitemapLocation": "sitemap.json",
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "你的位置信息将用于小程序位置接口的效果展示"
|
||||
}
|
||||
}
|
||||
}
|
3
app.wxss
Normal file
3
app.wxss
Normal file
@ -0,0 +1,3 @@
|
||||
@import 'style/iconfont.wxss';
|
||||
|
||||
@import 'style/theme.wxss';
|
1
commitlint.config.js
Normal file
1
commitlint.config.js
Normal file
@ -0,0 +1 @@
|
||||
module.exports = { extends: ['@commitlint/config-conventional'] };
|
29
common/updateManager.js
Normal file
29
common/updateManager.js
Normal file
@ -0,0 +1,29 @@
|
||||
export default () => {
|
||||
if (!wx.canIUse('getUpdateManager')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateManager = wx.getUpdateManager();
|
||||
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
console.log('版本信息', res);
|
||||
});
|
||||
|
||||
updateManager.onUpdateReady(function () {
|
||||
wx.showModal({
|
||||
title: '更新提示',
|
||||
content: '新版本已经准备好,是否重启应用?',
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
updateManager.onUpdateFailed(function () {
|
||||
// 新版本下载失败
|
||||
});
|
||||
};
|
36
components/filter-popup/index.js
Normal file
36
components/filter-popup/index.js
Normal file
@ -0,0 +1,36 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class'],
|
||||
|
||||
options: {
|
||||
multipleSlots: true,
|
||||
},
|
||||
|
||||
properties: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
observer(show) {
|
||||
this.setData({ visible: show });
|
||||
},
|
||||
},
|
||||
closeBtn: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
data: { visible: false },
|
||||
|
||||
methods: {
|
||||
reset() {
|
||||
this.triggerEvent('reset');
|
||||
},
|
||||
confirm() {
|
||||
this.triggerEvent('confirm');
|
||||
},
|
||||
close() {
|
||||
this.triggerEvent('showFilterPopupClose');
|
||||
|
||||
this.setData({ visible: false });
|
||||
},
|
||||
},
|
||||
});
|
6
components/filter-popup/index.json
Normal file
6
components/filter-popup/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-popup": "tdesign-miniprogram/popup/popup"
|
||||
}
|
||||
}
|
18
components/filter-popup/index.wxml
Normal file
18
components/filter-popup/index.wxml
Normal file
@ -0,0 +1,18 @@
|
||||
<t-popup
|
||||
visible="{{visible}}"
|
||||
placement="right"
|
||||
bind:visible-change="close"
|
||||
data-index="5"
|
||||
close-btn="{{closeBtn}}"
|
||||
>
|
||||
<view class="content">
|
||||
<slot name="filterSlot" />
|
||||
<view class="filter-btns-wrap">
|
||||
<view class="filter-btn btn-reset" bind:tap="reset">重置</view>
|
||||
<view class="filter-btn btn-confirm" bind:tap="confirm" data-index="5">
|
||||
确定
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</t-popup>
|
||||
|
39
components/filter-popup/index.wxss
Normal file
39
components/filter-popup/index.wxss
Normal file
@ -0,0 +1,39 @@
|
||||
.content .filter-btns-wrap {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-radius: 10rpx 0 0 10rpx;
|
||||
padding: 16rpx 32rpx;
|
||||
border-top: 1rpx solid #e5e5e5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.btn-reset {
|
||||
color: #fa4126;
|
||||
background: rgba(255, 255, 255, 1);
|
||||
position: relative;
|
||||
border: 1rpx solid #fa4126;
|
||||
border-radius: 84rpx 0 0 84rpx;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
border-radius: 0 84rpx 84rpx 0;
|
||||
border: 1rpx solid #fa4126;
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
color: #fff;
|
||||
background: #fa4126;
|
||||
}
|
84
components/filter/index.js
Normal file
84
components/filter/index.js
Normal file
@ -0,0 +1,84 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class'],
|
||||
|
||||
options: {
|
||||
multipleSlots: true,
|
||||
},
|
||||
|
||||
properties: {
|
||||
overall: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
observer(overall) {
|
||||
this.setData({
|
||||
overall,
|
||||
});
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
observer(layout) {
|
||||
this.setData({
|
||||
layout,
|
||||
});
|
||||
},
|
||||
},
|
||||
sorts: {
|
||||
type: String,
|
||||
value: '',
|
||||
observer(sorts) {
|
||||
this.setData({
|
||||
sorts,
|
||||
});
|
||||
},
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
value: '#FA550F',
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
layout: 1,
|
||||
overall: 1,
|
||||
sorts: '',
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChangeShowAction() {
|
||||
const { layout } = this.data;
|
||||
const nextLayout = layout === 1 ? 0 : 1;
|
||||
this.triggerEvent('change', { ...this.properties, layout: nextLayout });
|
||||
},
|
||||
|
||||
handlePriseSort() {
|
||||
const { sorts } = this.data;
|
||||
this.triggerEvent('change', {
|
||||
...this.properties,
|
||||
overall: 0,
|
||||
sorts: sorts === 'desc' ? 'asc' : 'desc',
|
||||
});
|
||||
},
|
||||
|
||||
open() {
|
||||
this.triggerEvent('showFilterPopup', {
|
||||
show: true,
|
||||
});
|
||||
},
|
||||
|
||||
onOverallAction() {
|
||||
const { overall } = this.data;
|
||||
const nextOverall = overall === 1 ? 0 : 1;
|
||||
const nextData = {
|
||||
sorts: '',
|
||||
prices: [],
|
||||
};
|
||||
this.triggerEvent('change', {
|
||||
...this.properties,
|
||||
...nextData,
|
||||
overall: nextOverall,
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
6
components/filter/index.json
Normal file
6
components/filter/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-icon": "tdesign-miniprogram/icon/icon"
|
||||
}
|
||||
}
|
37
components/filter/index.wxml
Normal file
37
components/filter/index.wxml
Normal file
@ -0,0 +1,37 @@
|
||||
<!-- 过滤组件 -->
|
||||
<view class="wr-class filter-wrap">
|
||||
<view class="filter-left-content">
|
||||
<view class="filter-item {{overall === 1 ? 'filter-active-item' : ''}}" bindtap="onOverallAction">
|
||||
综合
|
||||
</view>
|
||||
<view class="filter-item" bind:tap="handlePriseSort">
|
||||
<text style="color: {{sorts !== '' ? color : '' }}">价格</text>
|
||||
<view class="filter-price">
|
||||
<t-icon
|
||||
prefix="wr"
|
||||
name="arrow_drop_up"
|
||||
size="18rpx"
|
||||
style="color:{{sorts === 'asc' ? color : '#bbb'}}"
|
||||
/>
|
||||
<t-icon
|
||||
prefix="wr"
|
||||
name="arrow_drop_down"
|
||||
size="18rpx"
|
||||
style="color:{{sorts === 'desc' ? color : '#bbb'}}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="filter-item {{prices.length ? 'filter-active-item' : ''}}" bindtap="open" data-index="5">
|
||||
筛选
|
||||
<t-icon
|
||||
name="filter"
|
||||
prefix="wr"
|
||||
color="#333"
|
||||
size="32rpx"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 筛选弹框 -->
|
||||
<slot name="filterPopup" />
|
||||
|
50
components/filter/index.wxss
Normal file
50
components/filter/index.wxss
Normal file
@ -0,0 +1,50 @@
|
||||
.filter-wrap {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.filter-right-content {
|
||||
height: 100%;
|
||||
flex-basis: 100rpx;
|
||||
text-align: center;
|
||||
line-height: 88rpx;
|
||||
}
|
||||
|
||||
.filter-left-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-grow: 2;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.filter-left-content .filter-item {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26rpx;
|
||||
line-height: 36rpx;
|
||||
font-weight: 400;
|
||||
color: rgba(51, 51, 51, 1);
|
||||
}
|
||||
|
||||
.filter-left-content .filter-item .filter-price {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 6rpx;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.filter-left-content .filter-item .wr-filter {
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
.filter-left-content .filter-active-item {
|
||||
color: #fa550f;
|
||||
}
|
141
components/goods-card/index.js
Normal file
141
components/goods-card/index.js
Normal file
@ -0,0 +1,141 @@
|
||||
Component({
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
},
|
||||
|
||||
properties: {
|
||||
id: {
|
||||
type: String,
|
||||
value: '',
|
||||
observer(id) {
|
||||
this.genIndependentID(id);
|
||||
if (this.properties.thresholds?.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
}
|
||||
},
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
observer(data) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
let isValidityLinePrice = true;
|
||||
if (data.originPrice && data.price && data.originPrice < data.price) {
|
||||
isValidityLinePrice = false;
|
||||
}
|
||||
this.setData({ goods: data, isValidityLinePrice });
|
||||
},
|
||||
},
|
||||
currency: {
|
||||
type: String,
|
||||
value: '¥',
|
||||
},
|
||||
|
||||
thresholds: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer(thresholds) {
|
||||
if (thresholds && thresholds.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
} else {
|
||||
this.clearIntersectionObserverHandle();
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
independentID: '',
|
||||
goods: { id: '' },
|
||||
isValidityLinePrice: false,
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
ready() {
|
||||
this.init();
|
||||
},
|
||||
detached() {
|
||||
this.clear();
|
||||
},
|
||||
},
|
||||
|
||||
pageLifeTimes: {},
|
||||
|
||||
methods: {
|
||||
clickHandle() {
|
||||
this.triggerEvent('click', { goods: this.data.goods });
|
||||
},
|
||||
|
||||
clickThumbHandle() {
|
||||
this.triggerEvent('thumb', { goods: this.data.goods });
|
||||
},
|
||||
|
||||
addCartHandle(e) {
|
||||
const { id } = e.currentTarget;
|
||||
const { id: cardID } = e.currentTarget.dataset;
|
||||
this.triggerEvent('add-cart', {
|
||||
...e.detail,
|
||||
id,
|
||||
cardID,
|
||||
goods: this.data.goods,
|
||||
});
|
||||
},
|
||||
|
||||
genIndependentID(id) {
|
||||
let independentID;
|
||||
if (id) {
|
||||
independentID = id;
|
||||
} else {
|
||||
independentID = `goods-card-${~~(Math.random() * 10 ** 8)}`;
|
||||
}
|
||||
this.setData({ independentID });
|
||||
},
|
||||
|
||||
init() {
|
||||
const { thresholds, id } = this.properties;
|
||||
this.genIndependentID(id);
|
||||
if (thresholds && thresholds.length) {
|
||||
this.createIntersectionObserverHandle();
|
||||
}
|
||||
},
|
||||
|
||||
clear() {
|
||||
this.clearIntersectionObserverHandle();
|
||||
},
|
||||
|
||||
intersectionObserverContext: null,
|
||||
|
||||
createIntersectionObserverHandle() {
|
||||
if (this.intersectionObserverContext || !this.data.independentID) {
|
||||
return;
|
||||
}
|
||||
this.intersectionObserverContext = this.createIntersectionObserver({
|
||||
thresholds: this.properties.thresholds,
|
||||
}).relativeToViewport();
|
||||
|
||||
this.intersectionObserverContext.observe(
|
||||
`#${this.data.independentID}`,
|
||||
(res) => {
|
||||
this.intersectionObserverCB(res);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
intersectionObserverCB() {
|
||||
this.triggerEvent('ob', {
|
||||
goods: this.data.goods,
|
||||
context: this.intersectionObserverContext,
|
||||
});
|
||||
},
|
||||
|
||||
clearIntersectionObserverHandle() {
|
||||
if (this.intersectionObserverContext) {
|
||||
try {
|
||||
this.intersectionObserverContext.disconnect();
|
||||
} catch (e) {}
|
||||
this.intersectionObserverContext = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
8
components/goods-card/index.json
Normal file
8
components/goods-card/index.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"price": "/components/price/index",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-image": "/components/webp-image/index"
|
||||
}
|
||||
}
|
63
components/goods-card/index.wxml
Normal file
63
components/goods-card/index.wxml
Normal file
@ -0,0 +1,63 @@
|
||||
<view
|
||||
id="{{independentID}}"
|
||||
class="goods-card"
|
||||
bind:tap="clickHandle"
|
||||
data-goods="{{ goods }}"
|
||||
>
|
||||
<view class="goods-card__main">
|
||||
<view class="goods-card__thumb" bind:tap="clickThumbHandle">
|
||||
<t-image
|
||||
wx:if="{{ !!goods.thumb }}"
|
||||
t-class="goods-card__img"
|
||||
src="{{ goods.thumb }}"
|
||||
mode="aspectFill"
|
||||
lazy-load
|
||||
/>
|
||||
</view>
|
||||
<view class="goods-card__body">
|
||||
<view class="goods-card__upper">
|
||||
<view wx:if="{{ goods.title }}" class="goods-card__title">
|
||||
{{ goods.title }}
|
||||
</view>
|
||||
<view wx:if="{{ goods.tags && !!goods.tags.length }}" class="goods-card__tags">
|
||||
<view
|
||||
wx:for="{{ goods.tags }}"
|
||||
wx:key="index"
|
||||
wx:for-item="tag"
|
||||
class="goods-card__tag"
|
||||
data-index="{{index}}"
|
||||
>
|
||||
{{tag}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="goods-card__down">
|
||||
<price
|
||||
wx:if="{{ goods.price }}"
|
||||
wr-class="spec-for-price"
|
||||
symbol-class="spec-for-symbol"
|
||||
symbol="{{currency}}"
|
||||
price="{{goods.price}}"
|
||||
/>
|
||||
<price
|
||||
wx:if="{{ goods.originPrice && isValidityLinePrice }}"
|
||||
wr-class="goods-card__origin-price"
|
||||
symbol="{{currency}}"
|
||||
price="{{goods.originPrice}}"
|
||||
type="delthrough"
|
||||
/>
|
||||
<t-icon
|
||||
class="goods-card__add-cart"
|
||||
prefix="wr"
|
||||
name="cartAdd"
|
||||
id="{{independentID}}-cart"
|
||||
data-id="{{independentID}}"
|
||||
catchtap="addCartHandle"
|
||||
size="48rpx"
|
||||
color="#FA550F"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
133
components/goods-card/index.wxss
Normal file
133
components/goods-card/index.wxss
Normal file
@ -0,0 +1,133 @@
|
||||
.goods-card {
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
border-radius: 0 0 16rpx 16rpx;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.goods-card__main {
|
||||
position: relative;
|
||||
display: flex;
|
||||
line-height: 1;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
width: 342rpx;
|
||||
border-radius: 0 0 16rpx 16rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16rpx;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.goods-card__thumb {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
width: 340rpx;
|
||||
height: 340rpx;
|
||||
}
|
||||
|
||||
.goods-card__thumb:empty {
|
||||
display: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.goods-card__img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.goods-card__body {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
background: #fff;
|
||||
border-radius: 0 0 16rpx 16rpx;
|
||||
padding: 16rpx 24rpx 18rpx;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.goods-card__upper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.goods-card__title {
|
||||
flex-shrink: 0;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
display: -webkit-box;
|
||||
height: 72rpx;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
|
||||
.goods-card__tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 8rpx 0 0 0;
|
||||
}
|
||||
|
||||
.goods-card__tag {
|
||||
color: #fa4126;
|
||||
background: transparent;
|
||||
font-size: 20rpx;
|
||||
border: 1rpx solid #fa4126;
|
||||
padding: 0 8rpx;
|
||||
border-radius: 16rpx;
|
||||
line-height: 30rpx;
|
||||
margin: 0 8rpx 8rpx 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
word-break: keep-all;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.goods-card__down {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: baseline;
|
||||
line-height: 32rpx;
|
||||
margin: 8rpx 0 0 0;
|
||||
}
|
||||
|
||||
.goods-card__origin-price {
|
||||
white-space: nowrap;
|
||||
font-weight: 700;
|
||||
order: 2;
|
||||
color: #bbbbbb;
|
||||
font-size: 24rpx;
|
||||
margin: 0 0 0 8rpx;
|
||||
}
|
||||
|
||||
.goods-card__add-cart {
|
||||
order: 3;
|
||||
margin: auto 0 0 auto;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.spec-for-price {
|
||||
font-size: 36rpx;
|
||||
white-space: nowrap;
|
||||
font-weight: 700;
|
||||
order: 1;
|
||||
color: #fa4126;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.spec-for-symbol {
|
||||
font-size: 24rpx;
|
||||
}
|
62
components/goods-list/index.js
Normal file
62
components/goods-list/index.js
Normal file
@ -0,0 +1,62 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class'],
|
||||
|
||||
properties: {
|
||||
goodsList: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
value: '',
|
||||
observer: (id) => {
|
||||
this.genIndependentID(id);
|
||||
},
|
||||
},
|
||||
thresholds: {
|
||||
type: Array,
|
||||
value: [],
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
independentID: '',
|
||||
},
|
||||
|
||||
lifetimes: {
|
||||
ready() {
|
||||
this.init();
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickGoods(e) {
|
||||
const { index } = e.currentTarget.dataset;
|
||||
this.triggerEvent('click', { ...e.detail, index });
|
||||
},
|
||||
|
||||
onAddCart(e) {
|
||||
const { index } = e.currentTarget.dataset;
|
||||
this.triggerEvent('addcart', { ...e.detail, index });
|
||||
},
|
||||
|
||||
onClickGoodsThumb(e) {
|
||||
const { index } = e.currentTarget.dataset;
|
||||
this.triggerEvent('thumb', { ...e.detail, index });
|
||||
},
|
||||
|
||||
init() {
|
||||
this.genIndependentID(this.id || '');
|
||||
},
|
||||
|
||||
genIndependentID(id) {
|
||||
if (id) {
|
||||
this.setData({ independentID: id });
|
||||
} else {
|
||||
this.setData({
|
||||
independentID: `goods-list-${~~(Math.random() * 10 ** 8)}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
6
components/goods-list/index.json
Normal file
6
components/goods-list/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"goods-card": "/components/goods-card/index"
|
||||
}
|
||||
}
|
16
components/goods-list/index.wxml
Normal file
16
components/goods-list/index.wxml
Normal file
@ -0,0 +1,16 @@
|
||||
<view class="goods-list-wrap wr-class" id="{{independentID}}">
|
||||
<block wx:for="{{goodsList}}" wx:for-item="item" wx:key="index">
|
||||
<goods-card
|
||||
id="{{independentID}}-gd-{{index}}"
|
||||
data="{{item}}"
|
||||
currency="{{item.currency || '¥'}}"
|
||||
thresholds="{{thresholds}}"
|
||||
class="goods-card-inside"
|
||||
data-index="{{index}}"
|
||||
bind:thumb="onClickGoodsThumb"
|
||||
bind:click="onClickGoods"
|
||||
bind:add-cart="onAddCart"
|
||||
/>
|
||||
</block>
|
||||
</view>
|
||||
|
7
components/goods-list/index.wxss
Normal file
7
components/goods-list/index.wxss
Normal file
@ -0,0 +1,7 @@
|
||||
.goods-list-wrap {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
}
|
54
components/load-more/index.js
Normal file
54
components/load-more/index.js
Normal file
@ -0,0 +1,54 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class', 'wr-class--no-more'],
|
||||
|
||||
options: { multipleSlots: true },
|
||||
|
||||
properties: {
|
||||
status: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
loadingText: {
|
||||
type: String,
|
||||
value: '加载中...',
|
||||
},
|
||||
noMoreText: {
|
||||
type: String,
|
||||
value: '没有更多了',
|
||||
},
|
||||
failedText: {
|
||||
type: String,
|
||||
value: '加载失败,点击重试',
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
value: '#BBBBBB',
|
||||
},
|
||||
failedColor: {
|
||||
type: String,
|
||||
value: '#FA550F',
|
||||
},
|
||||
size: {
|
||||
type: null,
|
||||
value: '40rpx',
|
||||
},
|
||||
loadingBackgroundColor: {
|
||||
type: String,
|
||||
value: '#F5F5F5',
|
||||
},
|
||||
listIsEmpty: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
/** 点击处理 */
|
||||
tapHandle() {
|
||||
// 失败重试
|
||||
if (this.data.status === 3) {
|
||||
this.triggerEvent('retry');
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
7
components/load-more/index.json
Normal file
7
components/load-more/index.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-loading": "tdesign-miniprogram/loading/loading",
|
||||
"t-divider": "tdesign-miniprogram/divider/divider"
|
||||
}
|
||||
}
|
31
components/load-more/index.wxml
Normal file
31
components/load-more/index.wxml
Normal file
@ -0,0 +1,31 @@
|
||||
<view
|
||||
class="load-more wr-class"
|
||||
style="{{listIsEmpty && (status === 0 || status === 2) ? 'display: none' : '' }}"
|
||||
bindtap="tapHandle"
|
||||
>
|
||||
<!-- 加载中 -->
|
||||
|
||||
<t-loading
|
||||
t-class="t-class-loading"
|
||||
t-class-text="t-class-loading-text"
|
||||
t-class-indicator="t-class-indicator"
|
||||
loading="{{status === 1}}"
|
||||
text="加载中..."
|
||||
theme="circular"
|
||||
size="40rpx"
|
||||
/>
|
||||
|
||||
<!-- 已全部加载 -->
|
||||
<t-divider wx:if="{{status === 2}}" t-class="t-class-divider" t-class-content="t-class-divider-content">
|
||||
<text slot="content">{{noMoreText}}</text>
|
||||
</t-divider>
|
||||
|
||||
<!-- 加载失败 -->
|
||||
<view class="load-more__error" wx:if="{{status===3}}">
|
||||
加载失败
|
||||
<text class="load-more__refresh-btn" bind:tap="tapHandle">刷新</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支持通过slot传入页面/列表的空态,load-more来控制空态的显示状态 -->
|
||||
<slot wx:if="{{listIsEmpty && (status === 0 || status === 2)}}" name="empty" />
|
35
components/load-more/index.wxss
Normal file
35
components/load-more/index.wxss
Normal file
@ -0,0 +1,35 @@
|
||||
.load-more {
|
||||
font-size: 24rpx;
|
||||
height: 100rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.load-more .t-class-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
--td-loading-color: #fa4126;
|
||||
}
|
||||
|
||||
.load-more .t-class-loading-text {
|
||||
color: #bbbbbb;
|
||||
}
|
||||
|
||||
.t-class-divider-content {
|
||||
margin: 0 10rpx;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
.load-more .t-class-indicator {
|
||||
color: #b9b9b9 !important;
|
||||
}
|
||||
|
||||
.load-more__error {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.load-more__refresh-btn {
|
||||
margin-left: 16rpx;
|
||||
color: #fa4126;
|
||||
}
|
23
components/loading-content/index.js
Normal file
23
components/loading-content/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class'],
|
||||
properties: {
|
||||
position: {
|
||||
type: String,
|
||||
value: 'static',
|
||||
},
|
||||
noMask: Boolean,
|
||||
type: {
|
||||
type: String,
|
||||
value: 'circular',
|
||||
},
|
||||
vertical: Boolean,
|
||||
size: {
|
||||
type: String,
|
||||
value: '50rpx',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
value: 'rgba(0, 0, 0, .6)',
|
||||
},
|
||||
},
|
||||
});
|
6
components/loading-content/index.json
Normal file
6
components/loading-content/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-loading": "tdesign-miniprogram/loading/loading"
|
||||
}
|
||||
}
|
11
components/loading-content/index.wxml
Normal file
11
components/loading-content/index.wxml
Normal file
@ -0,0 +1,11 @@
|
||||
<view class="t-class loading-content {{position}}" style="{{(position === 'static' || noMask) ? 'visibility: hidden;' : ''}} background-color: {{backgroundColor}}">
|
||||
<t-loading
|
||||
t-class="loading"
|
||||
theme="{{type}}"
|
||||
layout="{{vertical}}"
|
||||
size="{{size}}"
|
||||
>
|
||||
<slot/>
|
||||
</t-loading>
|
||||
</view>
|
||||
|
23
components/loading-content/index.wxss
Normal file
23
components/loading-content/index.wxss
Normal file
@ -0,0 +1,23 @@
|
||||
.loading-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
position: relative;
|
||||
}
|
||||
.loading-content.absolute {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.loading-content.fixed {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.loading-content .loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
visibility: visible;
|
||||
}
|
71
components/price/index.js
Normal file
71
components/price/index.js
Normal file
@ -0,0 +1,71 @@
|
||||
Component({
|
||||
externalClasses: ['wr-class', 'symbol-class', 'decimal-class'],
|
||||
useStore: [],
|
||||
properties: {
|
||||
priceUnit: {
|
||||
type: String,
|
||||
value: 'fen',
|
||||
}, // 价格单位,分 | 元, fen,yuan
|
||||
price: {
|
||||
type: null,
|
||||
value: '',
|
||||
observer(price) {
|
||||
this.format(price);
|
||||
},
|
||||
}, // 价格, 以分为单位
|
||||
type: {
|
||||
type: String,
|
||||
value: '', //
|
||||
}, // main 粗体, lighter 细体, mini 黑色, del 中划线, delthrough 中划线,包括货币符号
|
||||
symbol: {
|
||||
type: String,
|
||||
value: '¥', // '¥',
|
||||
}, // 货币符号,默认是人民币符号¥
|
||||
fill: Boolean, // 是否自动补齐两位小数
|
||||
decimalSmaller: Boolean, // 小数字号小一点
|
||||
lineThroughWidth: {
|
||||
type: null,
|
||||
value: '0.12em',
|
||||
}, // 划线价线条高度
|
||||
},
|
||||
|
||||
data: {
|
||||
pArr: [],
|
||||
},
|
||||
|
||||
methods: {
|
||||
format(price) {
|
||||
price = parseFloat(`${price}`);
|
||||
const pArr = [];
|
||||
if (!isNaN(price)) {
|
||||
const isMinus = price < 0;
|
||||
if (isMinus) {
|
||||
price = -price;
|
||||
}
|
||||
if (this.properties.priceUnit === 'yuan') {
|
||||
const priceSplit = price.toString().split('.');
|
||||
pArr[0] = priceSplit[0];
|
||||
pArr[1] = !priceSplit[1]
|
||||
? '00'
|
||||
: priceSplit[1].length === 1
|
||||
? `${priceSplit[1]}0`
|
||||
: priceSplit[1];
|
||||
} else {
|
||||
price = Math.round(price * 10 ** 8) / 10 ** 8; // 恢复精度丢失
|
||||
price = Math.ceil(price); // 向上取整
|
||||
pArr[0] = price >= 100 ? `${price}`.slice(0, -2) : '0';
|
||||
pArr[1] = `${price + 100}`.slice(-2);
|
||||
}
|
||||
if (!this.properties.fill) {
|
||||
// 如果 fill 为 false, 不显示小数末尾的0
|
||||
if (pArr[1] === '00') pArr[1] = '';
|
||||
else if (pArr[1][1] === '0') pArr[1] = pArr[1][0];
|
||||
}
|
||||
if (isMinus) {
|
||||
pArr[0] = `-${pArr[0]}`;
|
||||
}
|
||||
}
|
||||
this.setData({ pArr });
|
||||
},
|
||||
},
|
||||
});
|
4
components/price/index.json
Normal file
4
components/price/index.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
21
components/price/index.wxml
Normal file
21
components/price/index.wxml
Normal file
@ -0,0 +1,21 @@
|
||||
<wxs module="utils">
|
||||
var REGEXP = getRegExp('^\d+(\.\d+)?$');
|
||||
function addUnit(value) {
|
||||
if (value == null) {
|
||||
return '';
|
||||
}
|
||||
return REGEXP.test('' + value) ? value + 'rpx' : value;
|
||||
}
|
||||
module.exports = {
|
||||
addUnit: addUnit
|
||||
};
|
||||
</wxs>
|
||||
<view class="price {{type}} wr-class">
|
||||
<view wx:if="{{type === 'delthrough'}}" class="line" style="height:{{utils.addUnit(lineThroughWidth)}};" />
|
||||
<view class="symbol symbol-class">{{symbol}}</view>
|
||||
<view class="pprice">
|
||||
<view class="integer inline">{{pArr[0]}}</view>
|
||||
<view wx:if="{{pArr[1]}}" class="decimal inline {{decimalSmaller ? 'smaller' : ''}} decimal-class">.{{pArr[1]}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
66
components/price/index.wxss
Normal file
66
components/price/index.wxss
Normal file
@ -0,0 +1,66 @@
|
||||
:host {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
font-weight: inherit;
|
||||
}
|
||||
.inline {
|
||||
display: inline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.price {
|
||||
display: inline;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
.lighter {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
.mini {
|
||||
font-size: 24rpx;
|
||||
color: #5d5d5d;
|
||||
font-weight: 400;
|
||||
}
|
||||
.del .pprice {
|
||||
font-size: 32rpx;
|
||||
color: #9b9b9b;
|
||||
text-decoration: line-through;
|
||||
font-weight: 400;
|
||||
}
|
||||
.delthrough {
|
||||
position: relative;
|
||||
}
|
||||
.delthrough .line {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
margin: 0;
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
.symbol {
|
||||
display: inline;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.pprice {
|
||||
display: inline;
|
||||
margin: 0 0 0 4rpx;
|
||||
}
|
||||
.integer {
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
.decimal {
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
.decimal.smaller {
|
||||
font-size: 0.8em;
|
||||
vertical-align: baseline;
|
||||
}
|
79
components/swipeout/index.js
Normal file
79
components/swipeout/index.js
Normal file
@ -0,0 +1,79 @@
|
||||
let ARRAY = [];
|
||||
Component({
|
||||
externalClasses: ['wr-class'],
|
||||
|
||||
options: {
|
||||
multipleSlots: true,
|
||||
},
|
||||
properties: {
|
||||
disabled: Boolean,
|
||||
leftWidth: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
rightWidth: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
asyncClose: Boolean,
|
||||
},
|
||||
attached() {
|
||||
ARRAY.push(this);
|
||||
},
|
||||
|
||||
detached() {
|
||||
ARRAY = ARRAY.filter((item) => item !== this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Component initial data
|
||||
*/
|
||||
data: {
|
||||
wrapperStyle: '',
|
||||
asyncClose: false,
|
||||
closed: true,
|
||||
},
|
||||
|
||||
/**
|
||||
* Component methods
|
||||
*/
|
||||
methods: {
|
||||
open(position) {
|
||||
this.setData({ closed: false });
|
||||
this.triggerEvent('close', {
|
||||
position,
|
||||
instance: this,
|
||||
});
|
||||
},
|
||||
|
||||
close() {
|
||||
this.setData({ closed: true });
|
||||
},
|
||||
|
||||
closeOther() {
|
||||
ARRAY.filter((item) => item !== this).forEach((item) => item.close());
|
||||
},
|
||||
|
||||
noop() {
|
||||
return;
|
||||
},
|
||||
|
||||
onClick(event) {
|
||||
const { key: position = 'outside' } = event.currentTarget.dataset;
|
||||
this.triggerEvent('click', position);
|
||||
|
||||
if (this.data.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.data.asyncClose) {
|
||||
this.triggerEvent('close', {
|
||||
position,
|
||||
instance: this,
|
||||
});
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
4
components/swipeout/index.json
Normal file
4
components/swipeout/index.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
174
components/swipeout/index.wxml
Normal file
174
components/swipeout/index.wxml
Normal file
@ -0,0 +1,174 @@
|
||||
<wxs module="swipe">
|
||||
var THRESHOLD = 0.3;
|
||||
var MIN_DISTANCE = 10;
|
||||
var owner;
|
||||
var state;
|
||||
|
||||
var getState = function(ownerInstance) {
|
||||
owner = ownerInstance;
|
||||
state = owner.getState();
|
||||
state.leftWidth = state.leftWidth || 0;
|
||||
state.rightWidth = state.rightWidth || 0;
|
||||
state.offset = state.offset || 0;
|
||||
state.startOffset = state.startOffset || 0;
|
||||
};
|
||||
|
||||
var initRightWidth = function(newVal, oldVal, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
state.rightWidth = newVal;
|
||||
if (state.offset < 0) {
|
||||
swipeMove(-state.rightWidth);
|
||||
}
|
||||
};
|
||||
|
||||
var initLeftWidth = function(newVal, oldVal, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
state.leftWidth = newVal;
|
||||
if (state.offset > 0) {
|
||||
swipeMove(state.leftWidth);
|
||||
}
|
||||
}
|
||||
|
||||
var resetTouchStatus = function() {
|
||||
state.direction = '';
|
||||
state.deltaX = 0;
|
||||
state.deltaY = 0;
|
||||
state.offsetX = 0;
|
||||
state.offsetY = 0;
|
||||
};
|
||||
|
||||
var touchMove = function(event) {
|
||||
var touchPoint = event.touches[0];
|
||||
state.deltaX = touchPoint.clientX - state.startX;
|
||||
state.deltaY = touchPoint.clientY - state.startY;
|
||||
state.offsetX = Math.abs(state.deltaX);
|
||||
state.offsetY = Math.abs(state.deltaY);
|
||||
state.direction = state.direction || getDirection(state.offsetX, state.offsetY);
|
||||
};
|
||||
|
||||
var getDirection = function(x, y) {
|
||||
if (x > y && x > MIN_DISTANCE) {
|
||||
return 'horizontal';
|
||||
}
|
||||
if (y > x && y > MIN_DISTANCE) {
|
||||
return 'vertical';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
var range = function(num, min, max) {
|
||||
return Math.min(Math.max(num, min), max);
|
||||
};
|
||||
|
||||
var swipeMove = function(_offset = 0) {
|
||||
state.offset = range(
|
||||
_offset,
|
||||
-state.rightWidth,
|
||||
+state.leftWidth,
|
||||
);
|
||||
|
||||
var transform = 'translate3d(' + state.offset + 'px, 0, 0)';
|
||||
var transition = state.dragging
|
||||
? 'none'
|
||||
: 'transform .6s cubic-bezier(0.18, 0.89, 0.32, 1)';
|
||||
owner.selectComponent('#wrapper').setStyle({
|
||||
'-webkit-transform': transform,
|
||||
'-webkit-transition': transition,
|
||||
'transform': transform,
|
||||
'transition': transition
|
||||
});
|
||||
};
|
||||
|
||||
var close = function() {
|
||||
swipeMove(0);
|
||||
};
|
||||
|
||||
var onCloseChange = function(newVal, oldVal, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
if (newVal === oldVal) return;
|
||||
if (newVal) {
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
var touchStart = function(event) {
|
||||
resetTouchStatus();
|
||||
state.startOffset = state.offset;
|
||||
var touchPoint = event.touches[0];
|
||||
state.startX = touchPoint.clientX;
|
||||
state.startY = touchPoint.clientY;
|
||||
owner.callMethod('closeOther');
|
||||
};
|
||||
|
||||
var startDrag = function(event, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
touchStart(event);
|
||||
};
|
||||
|
||||
var onDrag = function(event, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
touchMove(event);
|
||||
if (state.direction !== 'horizontal') {
|
||||
return;
|
||||
}
|
||||
state.dragging = true;
|
||||
swipeMove(state.startOffset + state.deltaX);
|
||||
};
|
||||
|
||||
var open = function(position) {
|
||||
var _offset = position === 'left' ? +state.leftWidth : -state.rightWidth;
|
||||
owner.callMethod('open', { position: position });
|
||||
swipeMove(_offset);
|
||||
};
|
||||
|
||||
var endDrag = function(event, ownerInstance) {
|
||||
getState(ownerInstance);
|
||||
state.dragging = false;
|
||||
// 左/右侧有可滑动区域,且当前不是已open状态,且滑动幅度超过阈值时open左/右侧(滚动到该侧的最边上)
|
||||
if (+state.rightWidth > 0 && -state.startOffset < +state.rightWidth && -state.offset > +state.rightWidth * THRESHOLD) {
|
||||
open('right');
|
||||
} else if (+state.leftWidth > 0 && state.startOffset < +state.leftWidth && state.offset > +state.leftWidth * THRESHOLD) {
|
||||
open('left');
|
||||
} else {
|
||||
// 仅在有发生侧滑的情况下自动关闭(由js控制是否异步关闭)
|
||||
if (state.startOffset !== state.offset) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
initLeftWidth: initLeftWidth,
|
||||
initRightWidth: initRightWidth,
|
||||
startDrag: startDrag,
|
||||
onDrag: onDrag,
|
||||
endDrag: endDrag,
|
||||
onCloseChange: onCloseChange
|
||||
};
|
||||
</wxs>
|
||||
|
||||
<view
|
||||
class="wr-class wr-swipeout"
|
||||
data-key="cell"
|
||||
capture-bind:tap="onClick"
|
||||
bindtouchstart="{{disabled || swipe.startDrag}}"
|
||||
capture-bind:touchmove="{{disabled || swipe.onDrag}}"
|
||||
bindtouchend="{{disabled || swipe.endDrag}}"
|
||||
bindtouchcancel="{{disabled || swipe.endDrag}}"
|
||||
closed="{{closed}}"
|
||||
change:closed="{{swipe.onCloseChange}}"
|
||||
leftWidth="{{leftWidth}}"
|
||||
rightWidth="{{rightWidth}}"
|
||||
change:leftWidth="{{swipe.initLeftWidth}}"
|
||||
change:rightWidth="{{swipe.initRightWidth}}"
|
||||
>
|
||||
<view id="wrapper">
|
||||
<view wx:if="{{ leftWidth }}" class="wr-swipeout__left" data-key="left" catch:tap="onClick">
|
||||
<slot name="left" />
|
||||
</view>
|
||||
<slot />
|
||||
<view wx:if="{{ rightWidth }}" class="wr-swipeout__right" data-key="right" catch:tap="onClick">
|
||||
<slot name="right" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
18
components/swipeout/index.wxss
Normal file
18
components/swipeout/index.wxss
Normal file
@ -0,0 +1,18 @@
|
||||
.wr-swipeout {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.wr-swipeout__left,
|
||||
.wr-swipeout__right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
.wr-swipeout__left {
|
||||
left: 0;
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
.wr-swipeout__right {
|
||||
right: 0;
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
86
components/webp-image/index.js
Normal file
86
components/webp-image/index.js
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* @Author: rileycai
|
||||
* @Date: 2022-03-14 14:21:26
|
||||
* @LastEditTime: 2022-03-14 15:23:04
|
||||
* @LastEditors: rileycai
|
||||
* @Description: webp-image组件对t-image包裹了一层,主要实现图片裁剪、webp压缩功能
|
||||
* @FilePath: /tdesign-miniprogram-starter/components/webp-image/index.js
|
||||
*/
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
Component({
|
||||
externalClasses: ['t-class', 't-class-load'],
|
||||
properties: {
|
||||
loadFailed: {
|
||||
type: String,
|
||||
value: 'default',
|
||||
},
|
||||
loading: {
|
||||
type: String,
|
||||
value: 'default',
|
||||
},
|
||||
src: {
|
||||
type: String,
|
||||
value: '',
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
value: 'aspectFill',
|
||||
},
|
||||
webp: {
|
||||
type: Boolean,
|
||||
value: true,
|
||||
},
|
||||
lazyLoad: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
showMenuByLongpress: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
data: {
|
||||
thumbHeight: 375,
|
||||
thumbWidth: 375,
|
||||
systemInfo,
|
||||
},
|
||||
lifetimes: {
|
||||
ready() {
|
||||
const { mode } = this.properties;
|
||||
// 获取容器的真实宽高,设置图片的裁剪宽度
|
||||
this.getRect('.J-image').then((res) => {
|
||||
if (res) {
|
||||
const { width, height } = res;
|
||||
this.setData(
|
||||
mode === 'heightFix'
|
||||
? {
|
||||
thumbHeight: this.px2rpx(height) || 375,
|
||||
}
|
||||
: {
|
||||
thumbWidth: this.px2rpx(width) || 375,
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
px2rpx(px) {
|
||||
return (750 / (systemInfo.screenWidth || 375)) * px;
|
||||
},
|
||||
getRect(selector) {
|
||||
return new Promise((resolve) => {
|
||||
if (!this.selectorQuery) {
|
||||
this.selectorQuery = this.createSelectorQuery();
|
||||
}
|
||||
this.selectorQuery.select(selector).boundingClientRect(resolve).exec();
|
||||
});
|
||||
},
|
||||
onLoad(e) {
|
||||
this.triggerEvent('load', e.detail);
|
||||
},
|
||||
onError(e) {
|
||||
this.triggerEvent('error', e.detail);
|
||||
},
|
||||
},
|
||||
});
|
6
components/webp-image/index.json
Normal file
6
components/webp-image/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-image": "tdesign-miniprogram/image/image"
|
||||
}
|
||||
}
|
14
components/webp-image/index.wxml
Normal file
14
components/webp-image/index.wxml
Normal file
@ -0,0 +1,14 @@
|
||||
<wxs src="./utils.wxs" module="Utils" />
|
||||
<t-image
|
||||
t-class="J-image"
|
||||
src="{{Utils.getSrc({src, thumbWidth: thumbWidth || 0, thumbHeight: thumbHeight || 0, systemInfo, webp, mode})}}"
|
||||
t-class="t-class"
|
||||
t-class-load="t-class-load"
|
||||
mode="{{ mode }}"
|
||||
lazy="{{ lazyLoad }}"
|
||||
show-menu-by-longpress="{{showMenuByLongpress}}"
|
||||
error="{{loadFailed}}"
|
||||
loading="{{loading}}"
|
||||
binderror="onError"
|
||||
bindload="onLoad"
|
||||
/>
|
0
components/webp-image/index.wxss
Normal file
0
components/webp-image/index.wxss
Normal file
140
components/webp-image/utils.wxs
Normal file
140
components/webp-image/utils.wxs
Normal file
@ -0,0 +1,140 @@
|
||||
var isString = function (value) {
|
||||
return typeof value === 'string';
|
||||
};
|
||||
|
||||
var isNumber = function (value) {
|
||||
return typeof value === 'number';
|
||||
};
|
||||
|
||||
var getFileExt = function (src) {
|
||||
var fileUrl = src.split('?')[0];
|
||||
var splitUlr = fileUrl.split('/');
|
||||
var filepath = splitUlr[splitUlr.length - 1];
|
||||
return filepath.split('.')[1] || 'jpg';
|
||||
};
|
||||
|
||||
function isUrl(url) {
|
||||
// NOCC:ToolNameCheck(非敏感词)
|
||||
var urlReg = getRegExp(
|
||||
'/[(http(s)?)://(www.)?a-zA-Z0-9@:%._+~#=]{2,256}.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/',
|
||||
'ig',
|
||||
);
|
||||
|
||||
return urlReg.test(url);
|
||||
}
|
||||
|
||||
function rpx2px(rpx, screenWidth) {
|
||||
// px / systemWidth = rpx / 750
|
||||
var result = (rpx * (screenWidth || 375)) / 750;
|
||||
|
||||
return Math.round(result);
|
||||
}
|
||||
|
||||
function imageMogr(url, options) {
|
||||
if (!isString(url) || !url) return '';
|
||||
|
||||
if (
|
||||
url.indexOf('qlogo.cn') !== -1 ||
|
||||
url.indexOf('wxfile://') === 0 ||
|
||||
url.indexOf('http://tmp/wx') === 0 ||
|
||||
url.indexOf('imageMogr2') !== -1
|
||||
) {
|
||||
//qlogo.cn域名或者本地图片不做转换
|
||||
return url;
|
||||
} //强制转https
|
||||
|
||||
if (url.indexOf('http://') === 0) {
|
||||
url = url.replace('http://', 'https://');
|
||||
} else if (url.indexOf('//') === 0) {
|
||||
url = 'https:' + url;
|
||||
}
|
||||
|
||||
if (!options) return url;
|
||||
|
||||
var width = Math.ceil(options.width),
|
||||
height = Math.ceil(options.height),
|
||||
format = options.format,
|
||||
_optionsQuality = options.quality,
|
||||
quality = _optionsQuality === undefined ? 70 : _optionsQuality,
|
||||
_optionsStrip = options.strip,
|
||||
strip = _optionsStrip === undefined ? true : _optionsStrip,
|
||||
crop = options.crop;
|
||||
var isValidWidth = isNumber(width) && width > 0;
|
||||
var isValidHeight = isNumber(height) && height > 0;
|
||||
var imageMogrStr = '';
|
||||
var size = '';
|
||||
|
||||
if (isValidWidth && isValidHeight) {
|
||||
size = ''.concat(width, 'x').concat(height);
|
||||
} else if (isValidWidth) {
|
||||
size = ''.concat(width, 'x');
|
||||
} else if (isValidHeight) {
|
||||
size = 'x'.concat(height);
|
||||
}
|
||||
|
||||
if (size) {
|
||||
//缩放或者裁剪
|
||||
imageMogrStr += '/'.concat(crop ? 'crop' : 'thumbnail', '/').concat(size);
|
||||
|
||||
if (crop) {
|
||||
//裁剪目前需求只有以图片中心为基准
|
||||
imageMogrStr += '/gravity/center';
|
||||
}
|
||||
}
|
||||
|
||||
if (isNumber(quality)) {
|
||||
//质量变换
|
||||
imageMogrStr += '/quality/'.concat(quality);
|
||||
}
|
||||
|
||||
if (strip) {
|
||||
//去除元信息
|
||||
imageMogrStr += '/strip';
|
||||
}
|
||||
|
||||
var ext = getFileExt(url);
|
||||
|
||||
// gif 图片不做格式转换,否则会损坏动图
|
||||
if (ext === 'gif') {
|
||||
imageMogrStr += '/cgif/1';
|
||||
} else if (format) {
|
||||
//格式转换
|
||||
imageMogrStr += '/format/'.concat(format);
|
||||
}
|
||||
|
||||
if (format === 'jpg' || (!format && (ext === 'jpg' || ext === 'jpeg'))) {
|
||||
//渐进式 jpg 加载
|
||||
imageMogrStr += '/interlace/1';
|
||||
}
|
||||
if (!imageMogrStr) return url;
|
||||
return ''
|
||||
.concat(url)
|
||||
.concat(url.indexOf('?') !== -1 ? '&' : '?', 'imageMogr2')
|
||||
.concat(imageMogrStr);
|
||||
}
|
||||
function getSrc(options) {
|
||||
if (!options.src) return '';
|
||||
|
||||
if (options.thumbWidth || options.thumbHeight) {
|
||||
return imageMogr(options.src, {
|
||||
width:
|
||||
options.mode !== 'heightFix'
|
||||
? rpx2px(options.thumbWidth, options.systemInfo.screenWidth) *
|
||||
options.systemInfo.pixelRatio
|
||||
: null,
|
||||
height:
|
||||
options.mode !== 'widthFix'
|
||||
? rpx2px(options.thumbHeight, options.systemInfo.screenWidth) *
|
||||
options.systemInfo.pixelRatio
|
||||
: null,
|
||||
format: options.webp ? 'webp' : null,
|
||||
});
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
imageMogr: imageMogr,
|
||||
getSrc: getSrc,
|
||||
};
|
91
config/eslintCheck.js
Normal file
91
config/eslintCheck.js
Normal file
@ -0,0 +1,91 @@
|
||||
/* eslint-disable prefer-template */
|
||||
/**
|
||||
* 工程代码pre-commit 检查工具
|
||||
* @date 2019.9.4
|
||||
* @author 310227663@qq.com
|
||||
*/
|
||||
const { exec } = require('child_process');
|
||||
const chalk = require('chalk');
|
||||
const { CLIEngine } = require('eslint');
|
||||
const cli = new CLIEngine({});
|
||||
const { log } = console;
|
||||
|
||||
function getErrorLevel(number) {
|
||||
switch (number) {
|
||||
case 2:
|
||||
return 'error';
|
||||
case 1:
|
||||
return 'warn';
|
||||
default:
|
||||
}
|
||||
return 'undefined';
|
||||
}
|
||||
let pass = 0;
|
||||
exec(
|
||||
'git diff --cached --name-only --diff-filter=ACM | grep -Ei "\\.ts$|\\.js$"',
|
||||
(error, stdout) => {
|
||||
if (stdout.length) {
|
||||
const array = stdout.split('\n');
|
||||
array.pop();
|
||||
const { results } = cli.executeOnFiles(array);
|
||||
let errorCount = 0;
|
||||
let warningCount = 0;
|
||||
results.forEach((result) => {
|
||||
errorCount += result.errorCount;
|
||||
warningCount += result.warningCount;
|
||||
if (result.messages.length > 0) {
|
||||
log('\n');
|
||||
log(result.filePath);
|
||||
result.messages.forEach((obj) => {
|
||||
const level = getErrorLevel(obj.severity);
|
||||
if (level === 'warn')
|
||||
log(
|
||||
' ' +
|
||||
obj.line +
|
||||
':' +
|
||||
obj.column +
|
||||
'\t ' +
|
||||
chalk.yellow(level) +
|
||||
' \0 ' +
|
||||
obj.message +
|
||||
'\t\t' +
|
||||
chalk.grey(obj.ruleId) +
|
||||
'',
|
||||
);
|
||||
if (level === 'error')
|
||||
log(
|
||||
' ' +
|
||||
obj.line +
|
||||
':' +
|
||||
obj.column +
|
||||
'\t ' +
|
||||
chalk.red.bold(level) +
|
||||
' \0 ' +
|
||||
obj.message +
|
||||
'\t\t ' +
|
||||
chalk.grey(obj.ruleId) +
|
||||
'',
|
||||
);
|
||||
if (level === 'error') pass = 1;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (warningCount > 0 || errorCount > 0) {
|
||||
log(
|
||||
'\n' +
|
||||
chalk.bgRed.bold(errorCount + warningCount + ' problems') +
|
||||
' (' +
|
||||
chalk.red.bold(errorCount) +
|
||||
' errors, ' +
|
||||
chalk.yellow(warningCount) +
|
||||
' warnings) \0',
|
||||
);
|
||||
}
|
||||
!pass && log(chalk.green.bold('~~ Done: 代码检验通过,提交成功 ~~'));
|
||||
process.exit(pass);
|
||||
}
|
||||
if (error !== null) {
|
||||
log(`exec error: ${error}`);
|
||||
}
|
||||
},
|
||||
);
|
20437
config/index.js
Normal file
20437
config/index.js
Normal file
File diff suppressed because it is too large
Load Diff
22
custom-tab-bar/data.js
Normal file
22
custom-tab-bar/data.js
Normal file
@ -0,0 +1,22 @@
|
||||
export default [
|
||||
{
|
||||
icon: 'home',
|
||||
text: '首页',
|
||||
url: 'pages/home/home',
|
||||
},
|
||||
{
|
||||
icon: 'sort',
|
||||
text: '分类',
|
||||
url: 'pages/goods/category/index',
|
||||
},
|
||||
{
|
||||
icon: 'cart',
|
||||
text: '购物车',
|
||||
url: 'pages/cart/index',
|
||||
},
|
||||
{
|
||||
icon: 'person',
|
||||
text: '个人中心',
|
||||
url: 'pages/usercenter/index',
|
||||
},
|
||||
];
|
29
custom-tab-bar/index.js
Normal file
29
custom-tab-bar/index.js
Normal file
@ -0,0 +1,29 @@
|
||||
import TabMenu from './data';
|
||||
Component({
|
||||
data: {
|
||||
active: 0,
|
||||
list: TabMenu,
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChange(event) {
|
||||
this.setData({ active: event.detail.value });
|
||||
wx.switchTab({
|
||||
url: this.data.list[event.detail.value].url.startsWith('/')
|
||||
? this.data.list[event.detail.value].url
|
||||
: `/${this.data.list[event.detail.value].url}`,
|
||||
});
|
||||
},
|
||||
|
||||
init() {
|
||||
const page = getCurrentPages().pop();
|
||||
const route = page ? page.route.split('?')[0] : '';
|
||||
const active = this.data.list.findIndex(
|
||||
(item) =>
|
||||
(item.url.startsWith('/') ? item.url.substr(1) : item.url) ===
|
||||
`${route}`,
|
||||
);
|
||||
this.setData({ active });
|
||||
},
|
||||
},
|
||||
});
|
8
custom-tab-bar/index.json
Normal file
8
custom-tab-bar/index.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-tab-bar": "tdesign-miniprogram/tab-bar/tab-bar",
|
||||
"t-tab-bar-item": "tdesign-miniprogram/tab-bar-item/tab-bar-item",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon"
|
||||
}
|
||||
}
|
18
custom-tab-bar/index.wxml
Normal file
18
custom-tab-bar/index.wxml
Normal file
@ -0,0 +1,18 @@
|
||||
<t-tab-bar
|
||||
value="{{active}}"
|
||||
bindchange="onChange"
|
||||
split="{{false}}"
|
||||
>
|
||||
<t-tab-bar-item
|
||||
wx:for="{{list}}"
|
||||
wx:for-item="item"
|
||||
wx:for-index="index"
|
||||
wx:key="index"
|
||||
>
|
||||
<view class="custom-tab-bar-wrapper">
|
||||
<t-icon prefix="wr" name="{{item.icon}}" size="48rpx" />
|
||||
<view class="text">{{ item.text }}</view>
|
||||
</view>
|
||||
</t-tab-bar-item>
|
||||
</t-tab-bar>
|
||||
|
9
custom-tab-bar/index.wxss
Normal file
9
custom-tab-bar/index.wxss
Normal file
@ -0,0 +1,9 @@
|
||||
.custom-tab-bar-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.custom-tab-bar-wrapper .text {
|
||||
font-size: 20rpx;
|
||||
}
|
5
jsconfig.json
Normal file
5
jsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
34
mock.md
Normal file
34
mock.md
Normal file
@ -0,0 +1,34 @@
|
||||
## 模拟与数据
|
||||
|
||||
model 用于放置模拟后端数据返回的逻辑;假若接入真实后端接口,则本文件夹可改造为数据层适配。
|
||||
services 用于请求逻辑,根据 config.useMock 配置可控制返回 mock 数据或是真实接口数据
|
||||
|
||||
### 1 模拟策略
|
||||
|
||||
1)只依靠 ID 规律进行关联
|
||||
大部分情况下推荐使用本方案,ID 为`1`的商品固定会关联 ID 为`1`的优惠券或者[ID 对 10 的模运算结果为 1](https://www.runoob.com/try/try.php?filename=tryjs_oper_mod)的优惠券(看需要 1 个还是多个了)。
|
||||
|
||||
> 为保持关系稳定,模运算统一使用`10`为除数,`ID`为被除数;即`1%10`、`2%10`。
|
||||
|
||||
2)建立额外关联关系查询
|
||||
在无法使用简单数学关系维持关系的情况下,可以采用单独提供关系数据的方式进行关联(目前也没想到什么场景是数学关系稳定不了的了,先假定有,定下规范做法)。如数据 A 与数据 B 之间需要一个关联 AB,则需要提供`A数据mock`、`B数据mock`、以及`A查B与B反查A`共 4 个 mock 源。
|
||||
|
||||
### 2 使用数据
|
||||
|
||||
使用数据源时应该在 services 文件夹中按照业务新建自己 fetch 函数导出,fetch 函数以 Promise 形式返回组合调用 model 逻辑得到的数据。
|
||||
|
||||
> 不允许直接在业务中调用、使用 model 数据。
|
||||
|
||||
## 接入真实 API 后
|
||||
|
||||
接入真实 API 后 model 文件夹逻辑可以反转层级,作为数据适配层继续为项目服务。举例说明:
|
||||
|
||||
1. 在没有接入 API 时(useMock 为 true)
|
||||
1.1 业务调用 services 进行 fetch
|
||||
1.2 fetch 逻辑调用 model 文件夹中对应的数据源,构造、返回业务需要的结构
|
||||
|
||||
2. 在接入 API 后(useMock 为 false)
|
||||
2.1 业务调用 services 进行 fetch
|
||||
2.2 fetch 逻辑调用接口得到真实后端数据
|
||||
2.3 比对 model 文件夹中数据 mock 数据结构 export 一个数据结构转换函数,输入真实后端数据,输出与 mock 数据结构一致的新数据,返回给 fetch
|
||||
2.4 fetch 函数 返回 转换后的 数据结构,业务层无需进行更改
|
7
model/activities.js
Normal file
7
model/activities.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { getActivity } from './activity';
|
||||
|
||||
export function getActivityList(baseID = 0, length = 10) {
|
||||
return new Array(length).fill(0).map((_, idx) => getActivity(idx + baseID));
|
||||
}
|
||||
|
||||
export const activityList = getActivityList();
|
18
model/activity.js
Normal file
18
model/activity.js
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @param {string|number} key 唯一值
|
||||
*/
|
||||
export function getActivity(key) {
|
||||
return {
|
||||
promotionId: `${key}`,
|
||||
title: `满减满折回归${key}`,
|
||||
description: null,
|
||||
promotionCode: 'MERCHANT',
|
||||
promotionSubCode: key % 2 === 0 ? 'MYJ' : 'MYG',
|
||||
tag: '满减',
|
||||
timeType: 1,
|
||||
startTime: '1588737710000',
|
||||
endTime: '1601467070000',
|
||||
teasingStartTime: null,
|
||||
activityLadder: [{ label: '满100元减99.9元' }],
|
||||
};
|
||||
}
|
31
model/address.js
Normal file
31
model/address.js
Normal file
@ -0,0 +1,31 @@
|
||||
/** 地址 */
|
||||
export function genAddress(id) {
|
||||
return {
|
||||
saasId: '88888888',
|
||||
uid: `8888888820550${id}`,
|
||||
authToken: null,
|
||||
id: `${id}`,
|
||||
addressId: `${id}`,
|
||||
phone: '17612345678',
|
||||
name: `测试用户${id}`,
|
||||
countryName: '中国',
|
||||
countryCode: 'chn',
|
||||
provinceName: '甘肃省',
|
||||
provinceCode: '620000',
|
||||
cityName: '甘南藏族自治州',
|
||||
cityCode: '623000',
|
||||
districtName: '碌曲县',
|
||||
districtCode: '623026',
|
||||
detailAddress: `松日鼎盛大厦${id}层${id}号`,
|
||||
isDefault: `${id}` === '0' ? 1 : 0,
|
||||
addressTag: id === 0 ? '' : '公司',
|
||||
latitude: '34.59103',
|
||||
longitude: '102.48699',
|
||||
storeId: null,
|
||||
};
|
||||
}
|
||||
|
||||
/** 地址列表 */
|
||||
export function genAddressList(len = 10) {
|
||||
return new Array(len).fill(0).map((_, idx) => genAddress(idx));
|
||||
}
|
324
model/cart.js
Normal file
324
model/cart.js
Normal file
@ -0,0 +1,324 @@
|
||||
import { mockIp, mockReqId } from '../utils/mock';
|
||||
|
||||
export function genCartGroupData() {
|
||||
const resp = {
|
||||
data: {
|
||||
isNotEmpty: true,
|
||||
storeGoods: [
|
||||
{
|
||||
storeId: '1000',
|
||||
storeName: '云Mall深圳旗舰店',
|
||||
storeStatus: 1,
|
||||
totalDiscountSalePrice: '9990',
|
||||
promotionGoodsList: [
|
||||
{
|
||||
title: '满减满折回归',
|
||||
promotionCode: 'MERCHANT',
|
||||
promotionSubCode: 'MYJ',
|
||||
promotionId: '159174555838121985',
|
||||
tagText: ['满100元减99.9元'],
|
||||
promotionStatus: 3,
|
||||
tag: '满减',
|
||||
description: '满100元减99.9元,已减99.9元',
|
||||
doorSillRemain: null,
|
||||
isNeedAddOnShop: 0,
|
||||
goodsPromotionList: [
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '12',
|
||||
skuId: '135691622',
|
||||
isSelected: 1,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-3a.png',
|
||||
title:
|
||||
'腾讯极光盒子4智能网络电视机顶盒6K千兆网络机顶盒4K高分辨率',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-3a.png',
|
||||
quantity: 1,
|
||||
stockStatus: true,
|
||||
stockQuantity: 3,
|
||||
price: '9900',
|
||||
originPrice: '16900',
|
||||
tagPrice: null,
|
||||
titlePrefixTags: [{ text: '新品' }, { text: '火爆' }],
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '经典白',
|
||||
},
|
||||
{
|
||||
specTitle: '类型',
|
||||
specValue: '经典套装',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-06-29T07:55:40.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '18',
|
||||
skuId: '135681631',
|
||||
isSelected: 1,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-09a.png',
|
||||
title:
|
||||
'白色短袖连衣裙荷叶边裙摆宽松韩版休闲纯白清爽优雅连衣裙',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-09a.png',
|
||||
quantity: 1,
|
||||
stockStatus: true,
|
||||
stockQuantity: 177,
|
||||
price: '29800',
|
||||
originPrice: '40000',
|
||||
tagPrice: null,
|
||||
titlePrefixTags: null,
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '米色荷叶边',
|
||||
},
|
||||
{
|
||||
specTitle: '尺码',
|
||||
specValue: 'M',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-06-29T07:55:27.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '13',
|
||||
skuId: '135698362',
|
||||
isSelected: 1,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/muy-3a.png',
|
||||
title:
|
||||
'带帽午休毯虎年款多功能加厚加大加绒简约多功能午休毯连帽披肩',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/muy-3a.png',
|
||||
quantity: 13,
|
||||
stockStatus: true,
|
||||
stockQuantity: 9,
|
||||
price: '29900',
|
||||
originPrice: '0',
|
||||
tagPrice: null,
|
||||
titlePrefixTags: [{ text: '火爆' }],
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '浅灰色',
|
||||
},
|
||||
{
|
||||
specTitle: '尺码',
|
||||
specValue: 'M',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-06-29T07:54:43.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '7',
|
||||
skuId: '135681625',
|
||||
isSelected: 1,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/gh-2b.png',
|
||||
title:
|
||||
'不锈钢刀叉勺套装家用西餐餐具ins简约耐用不锈钢金色银色可选',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/gh-2b.png',
|
||||
quantity: 1,
|
||||
stockStatus: true,
|
||||
stockQuantity: 0,
|
||||
price: '29900',
|
||||
originPrice: '29900',
|
||||
tagPrice: null,
|
||||
titlePrefixTags: null,
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '奶黄色',
|
||||
},
|
||||
{
|
||||
specTitle: '数量',
|
||||
specValue: '六件套',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-06-29T07:55:00.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
],
|
||||
lastJoinTime: '2020-06-29T07:55:40.000+0000',
|
||||
},
|
||||
{
|
||||
title: null,
|
||||
promotionCode: 'EMPTY_PROMOTION',
|
||||
promotionSubCode: null,
|
||||
promotionId: null,
|
||||
tagText: null,
|
||||
promotionStatus: null,
|
||||
tag: null,
|
||||
description: null,
|
||||
doorSillRemain: null,
|
||||
isNeedAddOnShop: 0,
|
||||
goodsPromotionList: [
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '11',
|
||||
skuId: '135691629',
|
||||
isSelected: 0,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-17a.png',
|
||||
title: '运动连帽拉链卫衣休闲开衫长袖多色运动细绒面料运动上衣',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-17a.png',
|
||||
quantity: 1,
|
||||
stockStatus: false,
|
||||
stockQuantity: 0,
|
||||
price: '25900',
|
||||
originPrice: '39900',
|
||||
tagPrice: null,
|
||||
tagText: null,
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '军绿色',
|
||||
},
|
||||
{
|
||||
specTitle: '尺码',
|
||||
specValue: 'S',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-04-24T06:26:48.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '5',
|
||||
skuId: '135691635',
|
||||
isSelected: 0,
|
||||
thumb:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-2a.png',
|
||||
title:
|
||||
'迷你便携高颜值蓝牙无线耳机立体声只能触控式操作简约立体声耳机',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-2a.png',
|
||||
quantity: 1,
|
||||
stockStatus: true,
|
||||
stockQuantity: 96,
|
||||
price: '29000',
|
||||
originPrice: '29900',
|
||||
tagPrice: null,
|
||||
tagText: null,
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '黑色',
|
||||
},
|
||||
{
|
||||
specTitle: '类型',
|
||||
specValue: '简约款',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-06-29T07:55:17.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
],
|
||||
lastJoinTime: null,
|
||||
},
|
||||
],
|
||||
lastJoinTime: '2020-06-29T07:55:40.000+0000',
|
||||
postageFreePromotionVo: {
|
||||
title: null,
|
||||
promotionCode: null,
|
||||
promotionSubCode: null,
|
||||
promotionId: null,
|
||||
tagText: null,
|
||||
promotionStatus: null,
|
||||
tag: null,
|
||||
description: null,
|
||||
doorSillRemain: null,
|
||||
isNeedAddOnShop: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
invalidGoodItems: [
|
||||
{
|
||||
uid: '88888888205468',
|
||||
saasId: '88888888',
|
||||
storeId: '1000',
|
||||
spuId: '1',
|
||||
skuId: '135691631',
|
||||
isSelected: 1,
|
||||
thumb: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
title: '纯色纯棉休闲圆领短袖T恤纯白亲肤厚柔软细腻面料纯白短袖套头T恤',
|
||||
primaryImage:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
quantity: 8,
|
||||
stockStatus: true,
|
||||
stockQuantity: 177,
|
||||
price: '26900',
|
||||
originPrice: '31900',
|
||||
tagPrice: null,
|
||||
tagText: null,
|
||||
roomId: null,
|
||||
specInfo: [
|
||||
{
|
||||
specTitle: '颜色',
|
||||
specValue: '白色',
|
||||
},
|
||||
{
|
||||
specTitle: '尺码',
|
||||
specValue: 'S',
|
||||
},
|
||||
],
|
||||
joinCartTime: '2020-04-28T04:03:59.000+0000',
|
||||
available: 1,
|
||||
putOnSale: 1,
|
||||
etitle: null,
|
||||
},
|
||||
],
|
||||
isAllSelected: false,
|
||||
selectedGoodsCount: 16,
|
||||
totalAmount: '179997',
|
||||
totalDiscountAmount: '110000',
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 269,
|
||||
success: true,
|
||||
};
|
||||
return resp;
|
||||
}
|
206
model/category.js
Normal file
206
model/category.js
Normal file
@ -0,0 +1,206 @@
|
||||
export function getCategoryList() {
|
||||
return [
|
||||
{
|
||||
groupId: '24948',
|
||||
name: '女装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249481',
|
||||
name: '女装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '卫衣',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-1.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '毛呢外套',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-2.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '雪纺衫',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-3.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '羽绒服',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-4.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '毛衣',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-5.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '棉衣',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-6.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '西装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-7.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '马甲',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-8.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '连衣裙',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-9.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '半身裙',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-10.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '裤子',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-11.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupId: '24948',
|
||||
name: '男装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249481',
|
||||
name: '男装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '卫衣',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-1.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '裤子',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-11.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '西装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-7.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '羽绒服',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-4.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '马甲',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-8.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupId: '24948',
|
||||
name: '儿童装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249481',
|
||||
name: '儿童装',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '马甲',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-8.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '裤子',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-11.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '连衣裙',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/classify/img-9.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '其他',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/muy-3b.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupId: '24948',
|
||||
name: '美妆',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249481',
|
||||
name: '美妆',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/category/category-default.png',
|
||||
children: [
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '唇釉',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/mz-20a1.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '美妆蛋',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/mz-11a1.png',
|
||||
},
|
||||
{
|
||||
groupId: '249480',
|
||||
name: '眼影',
|
||||
thumbnail:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/mz-12b.png',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
338
model/comments.js
Normal file
338
model/comments.js
Normal file
@ -0,0 +1,338 @@
|
||||
/**
|
||||
* * @param {number} spuId
|
||||
* @param {number} pageNum
|
||||
* @param {number} pageSize
|
||||
* @param {number} commentsLevel
|
||||
* @param {boolean} hasImage
|
||||
*/
|
||||
export function getGoodsAllComments(params) {
|
||||
const { hasImage } = params.queryParameter;
|
||||
if (hasImage) {
|
||||
return {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
totalCount: '1',
|
||||
pageList: [
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '0',
|
||||
specInfo: '',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentResources: [
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
],
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1591953561000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '0',
|
||||
specInfo: '',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentResources: [
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
type: 'image',
|
||||
},
|
||||
],
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1591953561000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '0',
|
||||
specInfo: '',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentResources: [
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
],
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1591953561000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '0',
|
||||
specInfo: '',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentResources: [
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
{
|
||||
src: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/comment-video.mp4',
|
||||
type: 'video',
|
||||
coverSrc:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
},
|
||||
],
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1591953561000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
return {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
totalCount: '47',
|
||||
pageList: [
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '很不错',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 1,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592224320000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697693',
|
||||
specInfo: '很适合',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 1,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592224320000',
|
||||
isAutoComment: false,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: 'NICE',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592218074000',
|
||||
isAutoComment: true,
|
||||
sellerReply:
|
||||
'亲,你好,我们会联系商家和厂商给您一个满意的答复请一定妥善保管好发票',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '0',
|
||||
specInfo: '',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592218074000',
|
||||
isAutoComment: false,
|
||||
goodsDetailInfo: '颜色:纯净白 尺码:S码',
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '测试dr超长:dr专用超长;bwtgg01:fff',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592217607000',
|
||||
isAutoComment: false,
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697693',
|
||||
specInfo: '测试dr超长:超长测试超长测试1;bwtgg01:bbb',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592217607000',
|
||||
isAutoComment: false,
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '测试dr超长:dr专用超长;bwtgg01:fff',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592205599000',
|
||||
isAutoComment: false,
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '测试dr超长:dr专用超长;bwtgg01:fff',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1592188822000',
|
||||
isAutoComment: false,
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '测试dr超长:dr专用超长;bwtgg01:fff',
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881055835',
|
||||
userName: 'Max',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1593792002000',
|
||||
isAutoComment: true,
|
||||
},
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: '1697694',
|
||||
specInfo: '测试dr超长:dr专用超长;bwtgg01:fff',
|
||||
commentContent: '',
|
||||
commentImageUrls: null,
|
||||
commentScore: 5,
|
||||
uid: '88881055835',
|
||||
userName: 'Max',
|
||||
userHeadUrl:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/avatar/avatar1.png',
|
||||
isAnonymity: false,
|
||||
commentTime: '1593792001000',
|
||||
isAutoComment: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getGoodsCommentsCount() {
|
||||
return {
|
||||
commentCount: '47',
|
||||
badCount: '0',
|
||||
middleCount: '2',
|
||||
goodCount: '45',
|
||||
hasImageCount: '1',
|
||||
goodRate: 95.7,
|
||||
uidCount: '0',
|
||||
};
|
||||
}
|
50
model/comments/queryDetail.js
Normal file
50
model/comments/queryDetail.js
Normal file
@ -0,0 +1,50 @@
|
||||
const queryDetail = {
|
||||
commentInfos: [
|
||||
{
|
||||
id: '647984992708380600',
|
||||
uid: '',
|
||||
userName: 'Dean Cheng',
|
||||
userHeadUrl:
|
||||
'https://bizmid-material-qa-1302115263.cos.ap-guangzhou.myqcloud.com/comment/default_head.png',
|
||||
commentId: '1937712',
|
||||
commentIdName: '小鹿商品',
|
||||
commentIdImageUrl:
|
||||
'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',
|
||||
commentStage: 1,
|
||||
commentCheckStatus: 2,
|
||||
commentIdType: 1,
|
||||
content: '',
|
||||
commentInfo: {
|
||||
score: null,
|
||||
content: '',
|
||||
medias: [],
|
||||
commentTime: '1617872404000',
|
||||
},
|
||||
isAgainComment: 0,
|
||||
commentHasAgainComment: 0,
|
||||
isAnonymous: 0,
|
||||
replyList: [],
|
||||
specification: '颜色:白色 ',
|
||||
specificationJson: '{"颜色":"白色"}',
|
||||
commentExtendId: '1937713',
|
||||
commentTime: '1617872404000',
|
||||
score: 0,
|
||||
goodsScore: null,
|
||||
freightScore: null,
|
||||
serviceScore: null,
|
||||
medias: [],
|
||||
againCommentList: null,
|
||||
},
|
||||
],
|
||||
logisticsScore: null,
|
||||
serviceScore: null,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} skuId
|
||||
* @param {string} spuId
|
||||
* @param {string} orderNo
|
||||
*/
|
||||
export function queryCommentDetail() {
|
||||
return queryDetail;
|
||||
}
|
39
model/coupon.js
Normal file
39
model/coupon.js
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 优惠券
|
||||
*
|
||||
* @typedef {'default'|'useless'|'disabled'} CouponCardStatus
|
||||
* @typedef {'discount'|'price'} CouponCardType
|
||||
*
|
||||
* @param {number} [id]
|
||||
* @param {CouponCardStatus} [status]
|
||||
* @param {CouponCardType} [type]
|
||||
*/
|
||||
export function getCoupon(id = 0, status = 'default', type = (id % 2) + 1) {
|
||||
return {
|
||||
/** key */
|
||||
key: `${id}`,
|
||||
/** 优惠券状态 */
|
||||
status,
|
||||
/** 优惠券类型 */
|
||||
type,
|
||||
/** 折扣或者满减值 */
|
||||
value: type === 2 ? 5.5 : 1800,
|
||||
/** 标签 */
|
||||
tag: '',
|
||||
/** 描述 */
|
||||
desc: parseInt(id) > 0 ? `满${parseInt(id) * 100}元可用` : '无门槛使用',
|
||||
/** 订单底价,满n元 */
|
||||
base: 10000 * (parseInt(id) || 0),
|
||||
/** 标题 */
|
||||
title: type === 2 ? `生鲜折扣券 - ${id}` : `生鲜满减券 - ${id}`,
|
||||
/** 有效时间限制 */
|
||||
timeLimit: '2019.11.18-2023.12.18',
|
||||
/** 货币符号 */
|
||||
currency: '¥',
|
||||
};
|
||||
}
|
||||
|
||||
/** 优惠券列表 */
|
||||
export function getCouponList(status = 'default', length = 10) {
|
||||
return new Array(length).fill(0).map((_, idx) => getCoupon(idx, status));
|
||||
}
|
30
model/detailsComments.js
Normal file
30
model/detailsComments.js
Normal file
@ -0,0 +1,30 @@
|
||||
export function getGoodsDetailsComments() {
|
||||
return {
|
||||
homePageComments: [
|
||||
{
|
||||
spuId: '1722045',
|
||||
skuId: null,
|
||||
specInfo: null,
|
||||
commentContent:
|
||||
'收到货了,第一时间试了一下,很漂亮特别喜欢,大爱大爱,颜色也很好看。棒棒!',
|
||||
commentScore: 4,
|
||||
uid: '88881048075',
|
||||
userName: 'Dean',
|
||||
userHeadUrl:
|
||||
'https://wx.qlogo.cn/mmopen/vi_32/5mKrvn3ibyDNaDZSZics3aoKlz1cv0icqn4EruVm6gKjsK0xvZZhC2hkUkRWGxlIzOEc4600JkzKn9icOLE6zjgsxw/132',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getGoodsDetailsCommentsCount() {
|
||||
return {
|
||||
commentCount: '47',
|
||||
badCount: '0',
|
||||
middleCount: '2',
|
||||
goodCount: '45',
|
||||
hasImageCount: '1',
|
||||
goodRate: 95.7,
|
||||
uidCount: '0',
|
||||
};
|
||||
}
|
1916
model/good.js
Normal file
1916
model/good.js
Normal file
File diff suppressed because it is too large
Load Diff
7
model/goods.js
Normal file
7
model/goods.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { genGood } from './good';
|
||||
|
||||
export function getGoodsList(baseID = 0, length = 10) {
|
||||
return new Array(length).fill(0).map((_, idx) => genGood(idx + baseID));
|
||||
}
|
||||
|
||||
export const goodsList = getGoodsList();
|
295
model/order/applyService.js
Normal file
295
model/order/applyService.js
Normal file
@ -0,0 +1,295 @@
|
||||
import { mockIp, mockReqId } from '../../utils/mock';
|
||||
|
||||
const orderResps = [
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '135691625',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '132222623132329291',
|
||||
goodsInfo: {
|
||||
goodsName:
|
||||
'迷你便携高颜值蓝牙无线耳机立体声只能触控式操作简约立体声耳机',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-2a.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '黑色',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '尺码',
|
||||
specValue: '简约款',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '135676631',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '132222623132329291',
|
||||
goodsInfo: {
|
||||
goodsName: '白色短袖连衣裙荷叶边裙摆宽松韩版休闲纯白清爽优雅连衣裙',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-09a.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '米色荷叶边',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '尺码',
|
||||
specValue: 'S',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '135691622',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '132222623132329291',
|
||||
goodsInfo: {
|
||||
goodsName: '腾讯极光盒子4智能网络电视机顶盒6K千兆网络机顶盒4K高分辨率',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/dz-3a.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '经典白',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '类型',
|
||||
specValue: '经典套装',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '135676629',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '132222623132329291',
|
||||
goodsInfo: {
|
||||
goodsName: '带帽午休毯虎年款多功能加厚加大加绒简约多功能午休毯连帽披肩',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/muy-3a.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '浅灰色',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '尺码',
|
||||
specValue: 'S',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '135686631',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '132222623132329291',
|
||||
goodsInfo: {
|
||||
goodsName: '运动连帽拉链卫衣休闲开衫长袖多色运动细绒面料运动上衣',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-17a.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '军绿色',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '尺码',
|
||||
specValue: 'XS',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
data: {
|
||||
saasId: '88888888',
|
||||
uid: '88888888205468',
|
||||
storeId: '1000',
|
||||
skuId: '19384938948343',
|
||||
numOfSku: 1,
|
||||
numOfSkuAvailable: 1,
|
||||
refundableAmount: '26900',
|
||||
refundableDiscountAmount: '0',
|
||||
shippingFeeIncluded: '0',
|
||||
paidAmountEach: '26900',
|
||||
boughtQuantity: 1,
|
||||
orderNo: '130169571554503755',
|
||||
goodsInfo: {
|
||||
goodsName:
|
||||
'纯色纯棉休闲圆领短袖T恤纯白亲肤厚柔软细腻面料纯白短袖套头T恤',
|
||||
skuImage: 'https://cdn-we-retail.ym.tencent.com/tsr/goods/nz-08b.png',
|
||||
specInfo: [
|
||||
{
|
||||
specId: '50456',
|
||||
specTitle: '颜色',
|
||||
specValue: '军绿色',
|
||||
},
|
||||
{
|
||||
specId: '50459',
|
||||
specTitle: '尺码',
|
||||
specValue: 'XS',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 36,
|
||||
success: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function genRightsPreview(params) {
|
||||
const { orderNo, skuId } = params;
|
||||
const resp = orderResps.find(
|
||||
(r) => r.data.orderNo === orderNo && r.data.skuId === skuId,
|
||||
);
|
||||
return resp;
|
||||
}
|
||||
|
||||
export function genApplyReasonList(params) {
|
||||
const resp = {
|
||||
data: {
|
||||
saasId: '70000001',
|
||||
rightsReasonList: [
|
||||
{ id: '1', desc: '实际商品与描述不符' },
|
||||
{ id: '2', desc: '质量问题' },
|
||||
{ id: '3', desc: '少件/漏发' },
|
||||
{ id: '4', desc: '包装/商品/污迹/裂痕/变形' },
|
||||
{ id: '5', desc: '发货太慢' },
|
||||
{ id: '6', desc: '物流配送太慢' },
|
||||
{ id: '7', desc: '商家发错货' },
|
||||
{ id: '8', desc: '不喜欢' },
|
||||
],
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 6,
|
||||
success: true,
|
||||
};
|
||||
// 未收货对应的原因列表
|
||||
if (params.rightsReasonType === 'REFUND_MONEY') {
|
||||
resp.data.rightsReasonList = [
|
||||
{ id: '9', desc: '空包裹' },
|
||||
{ id: '10', desc: '快递/物流一直未送到' },
|
||||
{ id: '11', desc: '货物破损已拒签' },
|
||||
{ id: '12', desc: '不喜欢' },
|
||||
];
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
export function applyService() {
|
||||
const resp = {
|
||||
data: {
|
||||
rightsNo: '123123423',
|
||||
saasId: '70000001',
|
||||
uid: '700000011070005',
|
||||
storeId: '542',
|
||||
result: null,
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 269,
|
||||
success: true,
|
||||
};
|
||||
return resp;
|
||||
}
|
147
model/order/orderConfirm.js
Normal file
147
model/order/orderConfirm.js
Normal file
@ -0,0 +1,147 @@
|
||||
import { mockIp, mockReqId } from '../../utils/mock';
|
||||
|
||||
export const transformGoodsDataToConfirmData = (goodsDataList) => {
|
||||
const list = [];
|
||||
|
||||
goodsDataList.forEach((goodsData) => {
|
||||
list.push({
|
||||
storeId: goodsData.storeId,
|
||||
spuId: goodsData.spuId,
|
||||
skuId: goodsData.skuId,
|
||||
goodsName: goodsData.title,
|
||||
image: goodsData.primaryImage,
|
||||
reminderStock: 119,
|
||||
quantity: goodsData.quantity,
|
||||
payPrice: goodsData.price,
|
||||
totalSkuPrice: goodsData.price,
|
||||
discountSettlePrice: goodsData.price,
|
||||
realSettlePrice: goodsData.price,
|
||||
settlePrice: goodsData.price,
|
||||
oriPrice: goodsData.originPrice,
|
||||
tagPrice: null,
|
||||
tagText: null,
|
||||
skuSpecLst: goodsData.specInfo,
|
||||
promotionIds: null,
|
||||
weight: 0.0,
|
||||
unit: 'KG',
|
||||
volume: null,
|
||||
masterGoodsType: 0,
|
||||
viceGoodsType: 0,
|
||||
roomId: goodsData.roomId,
|
||||
egoodsName: null,
|
||||
});
|
||||
});
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
/** 生成结算数据 */
|
||||
export function genSettleDetail(params) {
|
||||
const { userAddressReq, couponList, goodsRequestList } = params;
|
||||
|
||||
const resp = {
|
||||
data: {
|
||||
settleType: 0,
|
||||
userAddress: null,
|
||||
totalGoodsCount: 3,
|
||||
packageCount: 1,
|
||||
totalAmount: '289997',
|
||||
totalPayAmount: '',
|
||||
totalDiscountAmount: '110000',
|
||||
totalPromotionAmount: '1100',
|
||||
totalCouponAmount: '0',
|
||||
totalSalePrice: '289997',
|
||||
totalGoodsAmount: '289997',
|
||||
totalDeliveryFee: '0',
|
||||
invoiceRequest: null,
|
||||
skuImages: null,
|
||||
deliveryFeeList: null,
|
||||
storeGoodsList: [
|
||||
{
|
||||
storeId: '1000',
|
||||
storeName: '云Mall深圳旗舰店',
|
||||
remark: null,
|
||||
goodsCount: 1,
|
||||
deliveryFee: '0',
|
||||
deliveryWords: null,
|
||||
storeTotalAmount: '0',
|
||||
storeTotalPayAmount: '179997',
|
||||
storeTotalDiscountAmount: '110000',
|
||||
storeTotalCouponAmount: '0',
|
||||
skuDetailVos: [],
|
||||
couponList: [
|
||||
{
|
||||
couponId: 11,
|
||||
storeId: '1000',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
inValidGoodsList: null,
|
||||
outOfStockGoodsList: null,
|
||||
limitGoodsList: null,
|
||||
abnormalDeliveryGoodsList: null,
|
||||
invoiceSupport: 1,
|
||||
},
|
||||
code: 'Success',
|
||||
msg: null,
|
||||
requestId: mockReqId(),
|
||||
clientIp: mockIp(),
|
||||
rt: 244,
|
||||
success: true,
|
||||
};
|
||||
|
||||
const list = transformGoodsDataToConfirmData(goodsRequestList);
|
||||
|
||||
// 获取购物车传递的商品数据
|
||||
resp.data.storeGoodsList[0].skuDetailVos = list;
|
||||
|
||||
// 判断是否携带优惠券数据
|
||||
const discountPrice = [];
|
||||
|
||||
if (couponList && couponList.length > 0) {
|
||||
couponList.forEach((coupon) => {
|
||||
if (coupon.status === 'default') {
|
||||
discountPrice.push({
|
||||
type: coupon.type,
|
||||
value: coupon.value,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 模拟计算场景
|
||||
|
||||
// 计算总价
|
||||
const totalPrice = list.reduce((pre, cur) => {
|
||||
return pre + cur.quantity * Number(cur.settlePrice);
|
||||
}, 0);
|
||||
|
||||
// 计算折扣
|
||||
const totalDiscountPrice =
|
||||
discountPrice.length > 0
|
||||
? discountPrice.reduce((pre, cur) => {
|
||||
if (cur.type === 1) {
|
||||
return pre + cur.value;
|
||||
}
|
||||
if (cur.type === 2) {
|
||||
return pre + (Number(totalPrice) * cur.value) / 10;
|
||||
}
|
||||
|
||||
return pre + cur;
|
||||
}, 0)
|
||||
: 0;
|
||||
|
||||
resp.data.totalSalePrice = totalPrice;
|
||||
|
||||
resp.data.totalCouponAmount = totalDiscountPrice;
|
||||
|
||||
resp.data.totalPayAmount =
|
||||
totalPrice - totalDiscountPrice - Number(resp.data.totalPromotionAmount);
|
||||
|
||||
if (userAddressReq) {
|
||||
resp.data.settleType = 1;
|
||||
resp.data.userAddress = userAddressReq;
|
||||
}
|
||||
return resp;
|
||||
}
|
1212
model/order/orderDetail.js
Normal file
1212
model/order/orderDetail.js
Normal file
File diff suppressed because it is too large
Load Diff
1054
model/order/orderList.js
Normal file
1054
model/order/orderList.js
Normal file
File diff suppressed because it is too large
Load Diff
21
model/promotion.js
Normal file
21
model/promotion.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { getGoodsList } from './goods';
|
||||
|
||||
export function getPromotion(baseID = 0, length = 10) {
|
||||
return {
|
||||
list: getGoodsList(baseID, length).map((item) => {
|
||||
return {
|
||||
spuId: item.spuId,
|
||||
thumb: item.primaryImage,
|
||||
title: item.title,
|
||||
price: item.minSalePrice,
|
||||
originPrice: item.maxLinePrice,
|
||||
tags: item.spuTagList.map((tag) => ({ title: tag.title })),
|
||||
};
|
||||
}),
|
||||
banner:
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/promotion/banner-promotion.png',
|
||||
time: 1000 * 60 * 60 * 20,
|
||||
showBannerDesc: true,
|
||||
statusTag: 'running',
|
||||
};
|
||||
}
|
60
model/search.js
Normal file
60
model/search.js
Normal file
@ -0,0 +1,60 @@
|
||||
import { getGoodsList } from './goods';
|
||||
|
||||
/**
|
||||
* @param {number} sort
|
||||
* @param {number} pageNum
|
||||
* @param {number} pageSize
|
||||
* @param {number} minPrice
|
||||
* @param {number} maxPrice
|
||||
* @param {string} keyword
|
||||
*/
|
||||
|
||||
export function getSearchHistory() {
|
||||
return {
|
||||
historyWords: [
|
||||
'鸡',
|
||||
'电脑',
|
||||
'iPhone12',
|
||||
'车载手机支架',
|
||||
'自然堂',
|
||||
'小米10',
|
||||
'原浆古井贡酒',
|
||||
'欧米伽',
|
||||
'华为',
|
||||
'针织半身裙',
|
||||
'氢跑鞋',
|
||||
'三盒处理器',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchPopular() {
|
||||
return {
|
||||
popularWords: [
|
||||
'鸡',
|
||||
'电脑',
|
||||
'iPhone12',
|
||||
'车载手机支架',
|
||||
'自然堂',
|
||||
'小米10',
|
||||
'原浆古井贡酒',
|
||||
'欧米伽',
|
||||
'华为',
|
||||
'针织半身裙',
|
||||
'氢跑鞋',
|
||||
'三盒处理器',
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResult() {
|
||||
return {
|
||||
saasId: null,
|
||||
storeId: null,
|
||||
pageNum: 1,
|
||||
pageSize: 30,
|
||||
totalCount: 1,
|
||||
spuList: getGoodsList(7),
|
||||
algId: 0,
|
||||
};
|
||||
}
|
58
model/submitComment.js
Normal file
58
model/submitComment.js
Normal file
@ -0,0 +1,58 @@
|
||||
export function getGoods() {
|
||||
return {
|
||||
goods: [
|
||||
{
|
||||
squid: '1',
|
||||
checkItems: [
|
||||
{
|
||||
name: '匿名评价',
|
||||
value: 'anonymous',
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
detail: {
|
||||
image:
|
||||
'https://wx.qlogo.cn/mmopen/vi_32/51VSMNuy1CyHiaAhAjLJ00kMZVqqnCqXeZduCLXHUBr52zFHRGxwL7kGia3fHj8GSNzFcqFDInQmRGM1eWjtQgqA/132',
|
||||
title: '',
|
||||
},
|
||||
goodComment: {
|
||||
/** 商品评价 */
|
||||
rate: 0,
|
||||
/** 评价内容 */
|
||||
label: '123',
|
||||
/** 上传图片 */
|
||||
images: [],
|
||||
},
|
||||
},
|
||||
{
|
||||
squid: '2',
|
||||
checkItems: [
|
||||
{
|
||||
name: '匿名评价',
|
||||
value: 'anonymous',
|
||||
checked: false,
|
||||
},
|
||||
],
|
||||
detail: {
|
||||
image:
|
||||
'https://wx.qlogo.cn/mmopen/vi_32/51VSMNuy1CyHiaAhAjLJ00kMZVqqnCqXeZduCLXHUBr52zFHRGxwL7kGia3fHj8GSNzFcqFDInQmRGM1eWjtQgqA/132',
|
||||
title: '评价内容 山姆智利进口',
|
||||
},
|
||||
goodComment: {
|
||||
/** 商品评价 */
|
||||
rate: 0,
|
||||
/** 评价内容 */
|
||||
label: '山姆智利进口',
|
||||
/** 上传图片 */
|
||||
images: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
storeComment: {
|
||||
/** 物流评价 */
|
||||
logisticsRate: 0,
|
||||
/** 服务评价 */
|
||||
servicesRate: 0,
|
||||
},
|
||||
};
|
||||
}
|
39
model/swiper.js
Normal file
39
model/swiper.js
Normal file
@ -0,0 +1,39 @@
|
||||
// const images = [
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner1.png',
|
||||
// text: '1',
|
||||
// },
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner2.png',
|
||||
// text: '2',
|
||||
// },
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner3.png',
|
||||
// text: '3',
|
||||
// },
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner4.png',
|
||||
// text: '4',
|
||||
// },
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner5.png',
|
||||
// text: '5',
|
||||
// },
|
||||
// {
|
||||
// img: 'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner6.png',
|
||||
// text: '6',
|
||||
// },
|
||||
// ];
|
||||
|
||||
const images = [
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner1.png',
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner2.png',
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner3.png',
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner4.png',
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner5.png',
|
||||
'https://cdn-we-retail.ym.tencent.com/tsr/home/v2/banner6.png',
|
||||
];
|
||||
|
||||
export function genSwiperImageList() {
|
||||
return images;
|
||||
}
|
52
model/usercenter.js
Normal file
52
model/usercenter.js
Normal file
@ -0,0 +1,52 @@
|
||||
const userInfo = {
|
||||
avatarUrl:
|
||||
'https://we-retail-static-1300977798.cos.ap-guangzhou.myqcloud.com/retail-ui/components-exp/avatar/avatar-1.jpg',
|
||||
nickName: 'TDesign 🌟',
|
||||
phoneNumber: '13438358888',
|
||||
gender: 2,
|
||||
};
|
||||
const countsData = [
|
||||
{
|
||||
num: 2,
|
||||
name: '积分',
|
||||
type: 'point',
|
||||
},
|
||||
{
|
||||
num: 10,
|
||||
name: '优惠券',
|
||||
type: 'coupon',
|
||||
},
|
||||
];
|
||||
|
||||
const orderTagInfos = [
|
||||
{
|
||||
orderNum: 1,
|
||||
tabType: 5,
|
||||
},
|
||||
{
|
||||
orderNum: 1,
|
||||
tabType: 10,
|
||||
},
|
||||
{
|
||||
orderNum: 1,
|
||||
tabType: 40,
|
||||
},
|
||||
{
|
||||
orderNum: 0,
|
||||
tabType: 0,
|
||||
},
|
||||
];
|
||||
|
||||
const customerServiceInfo = {
|
||||
servicePhone: '4006336868',
|
||||
serviceTimeDuration: '每周三至周五 9:00-12:00 13:00-15:00',
|
||||
};
|
||||
|
||||
export const genSimpleUserInfo = () => ({ ...userInfo });
|
||||
|
||||
export const genUsercenter = () => ({
|
||||
userInfo,
|
||||
countsData,
|
||||
orderTagInfos,
|
||||
customerServiceInfo,
|
||||
});
|
45
package.json
Normal file
45
package.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "supermarket-pages",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"lint": "eslint --cache --fix --ext .js",
|
||||
"check": "node config/eslintCheck.js",
|
||||
"prepare": "husky install",
|
||||
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js, ts}": "eslint --cache --fix",
|
||||
"*.{js,ts,wxml,html,json,css,less}": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"dayjs": "^1.9.3",
|
||||
"tdesign-miniprogram": "^1.0.0",
|
||||
"tslib": "^1.11.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.4.2",
|
||||
"@commitlint/config-conventional": "^17.4.2",
|
||||
"commitizen": "^4.3.0",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.10.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-prettier": "^3.1.2",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^10.0.8",
|
||||
"prettier": "^2.1.2"
|
||||
}
|
||||
}
|
59
pages/cart/components/cart-bar/index.js
Normal file
59
pages/cart/components/cart-bar/index.js
Normal file
@ -0,0 +1,59 @@
|
||||
Component({
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
},
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
isAllSelected: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
totalAmount: {
|
||||
type: Number,
|
||||
value: 1,
|
||||
},
|
||||
totalGoodsNum: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
observer(num) {
|
||||
const isDisabled = num == 0;
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
isDisabled,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
totalDiscountAmount: {
|
||||
type: Number,
|
||||
value: 0,
|
||||
},
|
||||
bottomHeight: {
|
||||
type: Number,
|
||||
value: 100,
|
||||
},
|
||||
fixed: Boolean,
|
||||
},
|
||||
data: {
|
||||
isDisabled: false,
|
||||
},
|
||||
|
||||
methods: {
|
||||
handleSelectAll() {
|
||||
const { isAllSelected } = this.data;
|
||||
this.setData({
|
||||
isAllSelected: !isAllSelected,
|
||||
});
|
||||
this.triggerEvent('handleSelectAll', {
|
||||
isAllSelected: isAllSelected,
|
||||
});
|
||||
},
|
||||
|
||||
handleToSettle() {
|
||||
if (this.data.isDisabled) return;
|
||||
this.triggerEvent('handleToSettle');
|
||||
},
|
||||
},
|
||||
});
|
7
pages/cart/components/cart-bar/index.json
Normal file
7
pages/cart/components/cart-bar/index.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"price": "/components/price/index",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon"
|
||||
}
|
||||
}
|
31
pages/cart/components/cart-bar/index.wxml
Normal file
31
pages/cart/components/cart-bar/index.wxml
Normal file
@ -0,0 +1,31 @@
|
||||
<view class="cart-bar__placeholder" wx:if="{{fixed}}" />
|
||||
<view class="cart-bar {{fixed ? 'cart-bar--fixed' : ''}} flex flex-v-center" style="bottom: {{fixed ? 'calc(' + bottomHeight + 'rpx + env(safe-area-inset-bottom))' : ''}};">
|
||||
<t-icon
|
||||
size="40rpx"
|
||||
color="{{isAllSelected ? '#FA4126' : '#BBBBBB'}}"
|
||||
name="{{isAllSelected ? 'check-circle-filled' : 'circle'}}"
|
||||
class="cart-bar__check"
|
||||
catchtap="handleSelectAll"
|
||||
/>
|
||||
<text>全选</text>
|
||||
<view class="cart-bar__total flex1">
|
||||
<view>
|
||||
<text class="cart-bar__total--bold text-padding-right">总计</text>
|
||||
<price
|
||||
price="{{totalAmount || '0'}}"
|
||||
fill="{{false}}"
|
||||
decimalSmaller
|
||||
class="cart-bar__total--bold cart-bar__total--price"
|
||||
/>
|
||||
<text class="cart-bar__total--normal">(不含运费)</text>
|
||||
</view>
|
||||
<view wx:if="{{totalDiscountAmount}}">
|
||||
<text class="cart-bar__total--normal text-padding-right">已优惠</text>
|
||||
<price class="cart-bar__total--normal" price="{{totalDiscountAmount || '0'}}" fill="{{false}}" />
|
||||
</view>
|
||||
</view>
|
||||
<view catchtap="handleToSettle" class="{{!isDisabled ? '' : 'disabled-btn'}} account-btn" hover-class="{{!isDisabled ? '' : 'hover-btn'}}">
|
||||
去结算({{totalGoodsNum}})
|
||||
</view>
|
||||
</view>
|
||||
|
80
pages/cart/components/cart-bar/index.wxss
Normal file
80
pages/cart/components/cart-bar/index.wxss
Normal file
@ -0,0 +1,80 @@
|
||||
.cart-bar__placeholder {
|
||||
height: 100rpx;
|
||||
}
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.flex-v-center {
|
||||
align-items: center;
|
||||
}
|
||||
.flex1 {
|
||||
flex: 1;
|
||||
}
|
||||
.algin-bottom {
|
||||
text-align: end;
|
||||
}
|
||||
.cart-bar--fixed {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 99;
|
||||
bottom: calc(100rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.cart-bar {
|
||||
height: 112rpx;
|
||||
background-color: #fff;
|
||||
border-top: 1rpx solid #e5e5e5;
|
||||
padding: 16rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
line-height: 36rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.cart-bar .cart-bar__check {
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.cart-bar .cart-bar__total {
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.cart-bar .account-btn {
|
||||
width: 192rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #fa4126;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
line-height: 80rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
.cart-bar .disabled-btn {
|
||||
background-color: #cccccc !important;
|
||||
}
|
||||
.cart-bar .hover-btn {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.cart-bar__total .cart-bar__total--bold {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
.cart-bar__total .cart-bar__total--normal {
|
||||
font-size: 24rpx;
|
||||
line-height: 32rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.cart-bar__total .cart-bar__total--price {
|
||||
color: #fa4126;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-padding-right {
|
||||
padding-right: 4rpx;
|
||||
}
|
23
pages/cart/components/cart-empty/index.js
Normal file
23
pages/cart/components/cart-empty/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
Component({
|
||||
properties: {
|
||||
imgUrl: {
|
||||
type: String,
|
||||
value:
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/template/empty-cart.png',
|
||||
},
|
||||
tip: {
|
||||
type: String,
|
||||
value: '购物车是空的',
|
||||
},
|
||||
btnText: {
|
||||
type: String,
|
||||
value: '去首页',
|
||||
},
|
||||
},
|
||||
data: {},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.triggerEvent('handleClick');
|
||||
},
|
||||
},
|
||||
});
|
6
pages/cart/components/cart-empty/index.json
Normal file
6
pages/cart/components/cart-empty/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"t-image": "/components/webp-image/index"
|
||||
}
|
||||
}
|
6
pages/cart/components/cart-empty/index.wxml
Normal file
6
pages/cart/components/cart-empty/index.wxml
Normal file
@ -0,0 +1,6 @@
|
||||
<view class="cart-empty">
|
||||
<t-image t-class="cart-img" src="{{imgUrl}}" />
|
||||
<view class="tip">{{tip}}</view>
|
||||
<view class="btn" bind:tap="handleClick">{{btnText}}</view>
|
||||
</view>
|
||||
|
33
pages/cart/components/cart-empty/index.wxss
Normal file
33
pages/cart/components/cart-empty/index.wxss
Normal file
@ -0,0 +1,33 @@
|
||||
.cart-empty {
|
||||
padding: 64rpx 0rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
height: calc(100vh - 100rpx);
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.cart-empty .cart-img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.cart-empty .tip {
|
||||
font-size: 28rpx;
|
||||
line-height: 40rpx;
|
||||
color: #999;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
.cart-empty .btn {
|
||||
width: 240rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 36rpx;
|
||||
text-align: center;
|
||||
line-height: 72rpx;
|
||||
border: 2rpx solid #fa4126;
|
||||
color: #fa4126;
|
||||
background-color: transparent;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
166
pages/cart/components/cart-group/index.js
Normal file
166
pages/cart/components/cart-group/index.js
Normal file
@ -0,0 +1,166 @@
|
||||
import Toast from 'tdesign-miniprogram/toast/index';
|
||||
|
||||
const shortageImg =
|
||||
'https://cdn-we-retail.ym.tencent.com/miniapp/cart/shortage.png';
|
||||
|
||||
Component({
|
||||
isSpecsTap: false, // 标记本次点击事件是否因为点击specs触发(由于底层goods-card组件没有catch specs点击事件,只能在此处加状态来避免点击specs时触发跳转商品详情)
|
||||
externalClasses: ['wr-class'],
|
||||
properties: {
|
||||
storeGoods: {
|
||||
type: Array,
|
||||
observer(storeGoods) {
|
||||
for (const store of storeGoods) {
|
||||
for (const activity of store.promotionGoodsList) {
|
||||
for (const goods of activity.goodsPromotionList) {
|
||||
goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
|
||||
}
|
||||
}
|
||||
for (const goods of store.shortageGoodsList) {
|
||||
goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({ _storeGoods: storeGoods });
|
||||
},
|
||||
},
|
||||
invalidGoodItems: {
|
||||
type: Array,
|
||||
observer(invalidGoodItems) {
|
||||
invalidGoodItems.forEach((goods) => {
|
||||
goods.specs = goods.specInfo.map((item) => item.specValue); // 目前仅展示商品已选规格的值
|
||||
});
|
||||
this.setData({ _invalidGoodItems: invalidGoodItems });
|
||||
},
|
||||
},
|
||||
thumbWidth: { type: null },
|
||||
thumbHeight: { type: null },
|
||||
},
|
||||
|
||||
data: {
|
||||
shortageImg,
|
||||
isShowSpecs: false,
|
||||
currentGoods: {},
|
||||
isShowToggle: false,
|
||||
_storeGoods: [],
|
||||
_invalidGoodItems: [],
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 删除商品
|
||||
deleteGoods(e) {
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
this.triggerEvent('delete', { goods });
|
||||
},
|
||||
|
||||
// 清空失效商品
|
||||
clearInvalidGoods() {
|
||||
this.triggerEvent('clearinvalidgoods');
|
||||
},
|
||||
|
||||
// 选中商品
|
||||
selectGoods(e) {
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
this.triggerEvent('selectgoods', {
|
||||
goods,
|
||||
isSelected: !goods.isSelected,
|
||||
});
|
||||
},
|
||||
|
||||
changeQuantity(num, goods) {
|
||||
this.triggerEvent('changequantity', {
|
||||
goods,
|
||||
quantity: num,
|
||||
});
|
||||
},
|
||||
changeStepper(e) {
|
||||
const { value } = e.detail;
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
let num = value;
|
||||
if (value > goods.stack) {
|
||||
num = goods.stack;
|
||||
}
|
||||
this.changeQuantity(num, goods);
|
||||
},
|
||||
|
||||
input(e) {
|
||||
const { value } = e.detail;
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
const num = value;
|
||||
this.changeQuantity(num, goods);
|
||||
},
|
||||
|
||||
overlimit(e) {
|
||||
const text =
|
||||
e.detail.type === 'minus'
|
||||
? '该商品数量不能减少了哦'
|
||||
: '同一商品最多购买999件';
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: text,
|
||||
});
|
||||
},
|
||||
|
||||
// 去凑单/再逛逛
|
||||
gotoBuyMore(e) {
|
||||
const { promotion, storeId = '' } = e.currentTarget.dataset;
|
||||
this.triggerEvent('gocollect', { promotion, storeId });
|
||||
},
|
||||
|
||||
// 选中门店
|
||||
selectStore(e) {
|
||||
const { storeIndex } = e.currentTarget.dataset;
|
||||
const store = this.data.storeGoods[storeIndex];
|
||||
const isSelected = !store.isSelected;
|
||||
if (store.storeStockShortage && isSelected) {
|
||||
Toast({
|
||||
context: this,
|
||||
selector: '#t-toast',
|
||||
message: '部分商品库存不足',
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.triggerEvent('selectstore', {
|
||||
store,
|
||||
isSelected,
|
||||
});
|
||||
},
|
||||
|
||||
// 展开/收起切换
|
||||
showToggle() {
|
||||
this.setData({
|
||||
isShowToggle: !this.data.isShowToggle,
|
||||
});
|
||||
},
|
||||
|
||||
// 展示规格popup
|
||||
specsTap(e) {
|
||||
this.isSpecsTap = true;
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
this.setData({
|
||||
isShowSpecs: true,
|
||||
currentGoods: goods,
|
||||
});
|
||||
},
|
||||
|
||||
hideSpecsPopup() {
|
||||
this.setData({
|
||||
isShowSpecs: false,
|
||||
});
|
||||
},
|
||||
|
||||
goGoodsDetail(e) {
|
||||
if (this.isSpecsTap) {
|
||||
this.isSpecsTap = false;
|
||||
return;
|
||||
}
|
||||
const { goods } = e.currentTarget.dataset;
|
||||
this.triggerEvent('goodsclick', { goods });
|
||||
},
|
||||
|
||||
gotoCoupons() {
|
||||
wx.navigateTo({ url: '/pages/coupon/coupon-list/index' });
|
||||
},
|
||||
},
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user