1
0
Code Issues Pull Requests Packages Projects Releases Wiki Activity GitHub Gitee

通过微信开发者工具 商城模板 创建新小程序

This commit is contained in:
2023-03-06 23:52:24 +08:00
parent ada464a8cc
commit c21ff901d5
393 changed files with 52952 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
Component({
externalClasses: ['title-class', 'icon-class', 'number-class'],
options: {
multipleSlots: true,
},
properties: {
orderTagInfos: {
type: Array,
value: [],
},
title: {
type: String,
value: '我的订单',
},
desc: {
type: String,
value: '全部订单',
},
isTop: {
type: Boolean,
value: true,
},
classPrefix: {
type: String,
value: 'wr',
},
},
methods: {
onClickItem(e) {
this.triggerEvent('onClickItem', e.currentTarget.dataset.item);
},
onClickTop() {
this.triggerEvent('onClickTop', {});
},
},
});

View File

@@ -0,0 +1,9 @@
{
"component": true,
"usingComponents": {
"t-cell": "tdesign-miniprogram/cell/cell",
"t-cell-group": "tdesign-miniprogram/cell-group/cell-group",
"t-badge": "tdesign-miniprogram/badge/badge",
"t-icon": "tdesign-miniprogram/icon/icon"
}
}

View File

@@ -0,0 +1,37 @@
<view class="order-group">
<t-cell-group wx:if="{{isTop}}">
<t-cell
t-class="order-group__top"
t-class-left="order-group__left"
t-class-title="order-group__top__title"
t-class-note="order-group__top__note"
title="{{title}}"
note="{{desc}}"
bordered="{{false}}"
arrow
bind:tap="onClickTop"
/>
</t-cell-group>
<view class="order-group__content">
<view
class="order-group__item"
wx:for="{{orderTagInfos}}"
wx:for-item="item"
wx:key="index"
data-item="{{item}}"
bindtap="onClickItem"
>
<view class="order-group__item__icon icon-class">
<t-badge count="{{item.orderNum}}" max-count="{{99}}" color="#FF4646">
<t-icon
prefix="{{classPrefix}}"
name="{{item.iconName}}"
size="56rpx"
customStyle="background-image: -webkit-linear-gradient(90deg, #6a6a6a 0%,#929292 100%);-webkit-background-clip: text;-webkit-text-fill-color: transparent;"
/>
</t-badge>
</view>
<view class="order-group__item__title title-class">{{item.title}}</view>
</view>
</view>
</view>

View File

@@ -0,0 +1,56 @@
.order-group {
margin-bottom: 24rpx;
background-color: #ffffff;
border-radius: 16rpx 16rpx 0 0;
}
.order-group .order-group__top {
padding: 24rpx 18rpx 24rpx 32rpx;
border-radius: 16rpx 16rpx 0 0;
}
.order-group__top___title {
font-size: 32rpx;
line-height: 48rpx;
font-weight: bold;
}
.order-group__top__note {
font-size: 28rpx;
}
.order-group__content {
overflow: hidden;
width: 100%;
height: 164rpx;
display: flex;
background-color: #fff;
border-radius: 0 0 16rpx 16rpx;
}
.order-group__item {
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex: 1;
}
.order-group__item:first-child {
border-radius: 0 0 0 16rpx;
}
.order-group__item:last-child {
border-radius: 0 0 16rpx 0;
}
.order-group__item__title {
font-size: 24rpx;
color: #666;
line-height: 32rpx;
}
.order-group__item__icon {
margin-bottom: 20rpx;
width: 56rpx;
height: 56rpx;
position: relative;
}
.order-group__top__title {
font-weight: bold;
}
.order-group .order-group__left {
margin-right: 0;
}

View File

@@ -0,0 +1,124 @@
import { getPermission } from '../../../../utils/getPermission';
import { phoneRegCheck } from '../../../../utils/util';
import Toast from 'tdesign-miniprogram/toast/index';
import { addressParse } from '../../../../utils/addressParse';
import { resolveAddress, rejectAddress } from '../../address/list/util';
Component({
externalClasses: ['t-class'],
properties: {
title: {
type: String,
},
navigateUrl: {
type: String,
},
navigateEvent: {
type: String,
},
isCustomStyle: {
type: Boolean,
value: false,
},
isDisabledBtn: {
type: Boolean,
value: false,
},
isOrderSure: {
type: Boolean,
value: false,
},
},
methods: {
getWxLocation() {
if (this.properties.isDisabledBtn) return;
getPermission({ code: 'scope.address', name: '通讯地址' }).then(() => {
wx.chooseAddress({
success: async (options) => {
const { provinceName, cityName, countyName, detailInfo, userName, telNumber } = options;
if (!phoneRegCheck(telNumber)) {
Toast({
context: this,
selector: '#t-toast',
message: '请填写正确的手机号',
});
return;
}
const target = {
name: userName,
phone: telNumber,
countryName: '中国',
countryCode: 'chn',
detailAddress: detailInfo,
provinceName: provinceName,
cityName: cityName,
districtName: countyName,
isDefault: false,
isOrderSure: this.properties.isOrderSure,
};
try {
const { provinceCode, cityCode, districtCode } = await addressParse(provinceName, cityName, countyName);
const params = Object.assign(target, {
provinceCode,
cityCode,
districtCode,
});
if (this.properties.isOrderSure) {
this.onHandleSubmit(params);
} else if (this.properties.navigateUrl != '') {
const { navigateEvent } = this.properties;
this.triggerEvent('navigate');
wx.navigateTo({
url: this.properties.navigateUrl,
success: function (res) {
res.eventChannel.emit(navigateEvent, params);
},
});
} else {
this.triggerEvent('change', params);
}
} catch (error) {
wx.showToast({ title: '地址解析出错,请稍后再试', icon: 'none' });
}
},
fail(err) {
console.warn('未选择微信收货地址', err);
},
});
});
},
async queryAddress(addressId) {
try {
const { data } = await apis.userInfo.queryAddress({ addressId });
return data.userAddressVO;
} catch (err) {
console.error('查询地址错误', err);
throw err;
}
},
findPage(pageRouteUrl) {
const currentRoutes = getCurrentPages().map((v) => v.route);
return currentRoutes.indexOf(pageRouteUrl);
},
async onHandleSubmit(params) {
try {
const orderPageDeltaNum = this.findPage('pages/order/order-confirm/index');
if (orderPageDeltaNum > -1) {
wx.navigateBack({ delta: 1 });
resolveAddress(params);
return;
}
} catch (err) {
rejectAddress(params);
console.error(err);
}
},
},
});

View File

@@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"t-cell": "tdesign-miniprogram/cell/cell",
"t-icon": "tdesign-miniprogram/icon/icon",
"t-toast": "tdesign-miniprogram/toast/toast"
}
}

View File

@@ -0,0 +1,16 @@
<view class="wx-address t-class" bind:tap="getWxLocation">
<block wx:if="{{isCustomStyle}}">
<view class="wx-address-custom">
<t-icon prefix="wr" t-class="weixin" color="#0ABF5B" name="wechat" size="48rpx" />
<text>{{title}}</text>
</view>
<slot />
</block>
<block wx:else>
<t-cell title="{{title}}" title-class="cell__title" wr-class="cell" border="{{false}}">
<t-icon t-class="weixin" slot="icon" color="#0ABF5B" name="logo-windows" size="48rpx" />
<t-icon slot="right-icon" name="chevron-right" class="custom-icon" color="#bbb" />
</t-cell>
</block>
</view>
<t-toast id="t-toast" />

View File

@@ -0,0 +1,19 @@
.wx-address .weixin {
display: inline-block;
font-size: 48rpx !important;
margin-right: 20rpx;
font-weight: normal;
}
.wx-address .cell {
padding: 32rpx 30rpx;
border-radius: 8rpx;
}
.wx-address .cell__title {
font-size: 30rpx;
color: #333333;
}
.wx-address-custom {
display: flex;
align-items: center;
font-size: 32rpx;
}

View File

@@ -0,0 +1,46 @@
Component({
options: {
addGlobalClass: true,
multipleSlots: true,
},
properties: {
address: {
type: Object,
value: {},
},
customIcon: {
type: String,
value: 'edit-1',
},
extraSpace: {
type: Boolean,
value: true,
},
isDrawLine: {
type: Boolean,
value: true,
},
},
externalClasses: [
'item-wrapper-class',
'title-class',
'default-tag-class',
'normal-tag-class',
'address-info-class',
'delete-class',
],
methods: {
onDelete(e) {
const { item } = e.currentTarget.dataset;
this.triggerEvent('onDelete', item);
},
onSelect(e) {
const { item } = e.currentTarget.dataset;
this.triggerEvent('onSelect', item);
},
onEdit(e) {
const { item } = e.currentTarget.dataset;
this.triggerEvent('onEdit', item);
},
},
});

View File

@@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-tag": "tdesign-miniprogram/tag/tag",
"t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell"
}
}

View File

@@ -0,0 +1,30 @@
<wxs module="phoneReg">
var toHide = function(array) { var mphone = array.substring(0, 3) + '****' + array.substring(7); return mphone; }
module.exports.toHide = toHide;
</wxs>
<view class="address-item-wrapper item-wrapper-class">
<t-swipe-cell class="swipe-out">
<view class="address {{isDrawLine ? 'draw-line' : ''}}" bindtap="onSelect" data-item="{{address}}">
<view class="address-left" wx:if="{{extraSpace}}">
<t-icon wx:if="{{address.checked}}" name="check" color="#FA4126" class-prefix="{{classPrefix}}" size="46rpx" />
</view>
<view class="address-content">
<view class="title title-class">
<text class="text-style">{{address.name}}</text>
<text>{{phoneReg.toHide(address.phoneNumber || '')}}</text>
</view>
<view class="label-adds">
<text class="adds address-info-class">
<text wx:if="{{address.isDefault === 1}}" class="tag tag-default default-tag-class">默认</text>
<text wx:if="{{address.tag}}" class="tag tag-primary normal-tag-class">{{address.tag}}</text>
<text class="address-text">{{address.address}}</text>
</text>
</view>
</view>
<view catch:tap="onEdit" data-item="{{address}}" class="address-edit">
<t-icon name="{{customIcon}}" class-prefix="{{classPrefix}}" size="46rpx" color="#BBBBBB" />
</view>
</view>
<view slot="right" class="swipe-right-del delete-class" bindtap="onDelete" data-item="{{address}}"> 删除 </view>
</t-swipe-cell>
</view>

View File

@@ -0,0 +1,103 @@
.address-item-wrapper {
overflow: hidden;
}
.address-item-wrapper .swipe-out .wr-swiper-cell {
margin-top: 20rpx;
}
.address-item-wrapper .swipe-out .swipe-right-del {
display: flex;
justify-content: center;
align-items: center;
width: 144rpx;
height: 100%;
background-color: #fa4126;
color: #fff;
font-size: 28rpx;
line-height: 40rpx;
}
.address-item-wrapper .draw-line {
position: relative;
}
.address-item-wrapper .draw-line::after {
content: '';
position: absolute;
bottom: 0;
left: 32rpx;
width: 200%;
height: 2rpx;
transform: scale(0.5);
transform-origin: 0 0;
box-sizing: border-box;
border-bottom: #e5e5e5 2rpx solid;
}
.address-item-wrapper .address {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx;
background-color: #fff;
}
.address-item-wrapper .address .address-edit {
padding: 20rpx 0 20rpx 46rpx;
}
.address-item-wrapper .address .address-left {
width: 80rpx;
display: flex;
justify-content: center;
}
.address-item-wrapper .address .address-content {
display: flex;
flex-direction: column;
flex: 1;
}
.address-item-wrapper .address .address-content .title {
font-size: 32rpx;
line-height: 48rpx;
margin-bottom: 16rpx;
color: #333333;
font-weight: bold;
display: flex;
}
.address-item-wrapper .address .address-content .title .text-style {
margin-right: 8rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 280rpx;
}
.address-item-wrapper .address .address-content .label-adds {
display: flex;
}
.address-item-wrapper .address .address-content .label-adds .adds {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
color: #999999;
}
.address-item-wrapper .address .address-content .label-adds .tag {
display: inline-block;
padding: 0rpx 8rpx;
min-width: 40rpx;
height: 32rpx;
border-radius: 18rpx;
font-size: 20rpx;
line-height: 32rpx;
text-align: center;
margin-right: 8rpx;
vertical-align: text-top;
}
.address-item-wrapper .address .address-content .label-adds .tag-default {
background: #ffece9;
color: #fa4126;
}
.address-item-wrapper .address .address-content .label-adds .tag-primary {
background: #f0f1ff;
color: #5a66ff;
}
.address-item-wrapper .address .address-content .label-adds .address-text {
font-size: 28rpx;
line-height: 40rpx;
color: #999999;
}

View File

@@ -0,0 +1,73 @@
Component({
properties: {
show: {
type: Boolean,
observer(show) {
if (!show) return;
this.updateDivisions();
},
},
title: {
type: String,
value: '',
},
value: {
type: String,
value: '',
observer() {
if (!this.data.show) return;
this.updateDivisions();
},
},
pickerOptions: {
type: Array,
value: [],
observer() {
if (!this.data.show) return;
this.updateDivisions();
},
},
headerVisible: {
type: Boolean,
value: true,
},
},
data: {
pickerValue: [],
},
methods: {
updateDivisions() {
const { pickerOptions, value } = this.data;
const index = (pickerOptions || []).findIndex(
(item) => item.code === value,
);
setTimeout(() => {
this.setData({ pickerValue: index >= 0 ? [index] : [0] });
}, 0);
},
getAreaByIndex(indexes) {
const { pickerOptions } = this.data;
return pickerOptions[indexes.toString()];
},
onChange(e) {
const currentValue = e.detail.value;
const target = this.getAreaByIndex(currentValue);
if (target === null) return;
this.setData({ pickerValue: currentValue });
this.triggerEvent('change', { value: target.code, target: target });
},
onConfirm() {
const target = this.getAreaByIndex(this.data.pickerValue);
this.triggerEvent('confirm', { value: target?.code, target });
},
onClose() {
this.triggerEvent('close');
},
},
});

View File

@@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"t-popup": "tdesign-miniprogram/popup/popup"
}
}

View File

@@ -0,0 +1,21 @@
<t-popup visible="{{show}}" placement="bottom">
<view class="city-picker-box" slot="content">
<view wx:if="{{headerVisible}}" class="city-picker-header city-picker-more">
<view class="btn" hover-class="btn__active" catch:tap="onClose">取消</view>
<view wx:if="{{title}}" class="title">{{title}}</view>
<view class="btn primary" hover-class="btn__active" catch:tap="onConfirm">确定</view>
</view>
<view wx:else class="city-picker-header">
<view wx:if="{{title}}" class="title">{{title}}</view>
</view>
<picker-view class="picker" indicator-class="picker-center-row" value="{{pickerValue}}" bind:change="onChange">
<picker-view-column class="picker-column">
<view wx:for="{{ pickerOptions }}" wx:key="code">{{ item.name }}</view>
</picker-view-column>
</picker-view>
<view class="city-picker-footer" wx:if="{{!headerVisible}}">
<view class="btn" hover-class="btn__active" catch:tap="onClose">取消</view>
<view class="btn primary" hover-class="btn__active" catch:tap="onConfirm">确定</view>
</view>
</view>
</t-popup>

View File

@@ -0,0 +1,102 @@
.city-picker-container {
opacity: 0;
position: fixed;
top: 100vh;
left: 0;
right: 0;
height: 100vh;
z-index: 100;
}
.city-picker-container.show {
top: 0;
opacity: 1;
}
.city-picker-container.show .city-picker-box {
bottom: 0;
}
.city-picker-shadow {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.65);
}
.city-picker-header {
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-size: 32rpx;
color: #333333;
}
.city-picker-more {
display: flex;
justify-content: space-between;
align-items: center;
}
.city-picker-footer {
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.city-picker-footer .btn {
width: 330rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
color: #666666;
font-size: 32rpx;
position: relative;
}
.city-picker-footer .btn__active {
opacity: 0.5;
}
.city-picker-footer .btn::after {
display: block;
content: ' ';
position: absolute;
left: -50%;
right: -50%;
top: -50%;
bottom: -50%;
transform: scale(0.5);
border: 1rpx solid #999999;
border-radius: 16rpx;
}
.city-picker-footer .btn.primary {
color: #fa550f;
}
.city-picker-footer .btn.primary::after {
border-color: #fa550f;
}
.picker-column:not(:first-child) {
margin-left: 40rpx;
}
.city-picker-box {
position: absolute;
bottom: -100%;
transition: 0.3s bottom ease-in-out;
left: 0;
right: 0;
z-index: 100;
background-color: #fff;
padding: 0 30rpx;
color: #333333;
font-size: 34rpx;
border-radius: 20rpx 20rpx 0 0;
padding-bottom: env(safe-area-inset-bottom);
}
.show .city-picker-shadow {
display: block;
}
.picker {
height: 300rpx;
margin: 50rpx 0;
line-height: 88rpx;
text-align: center;
}
/* 似乎小程序picker-view的bugindicator-class仅height生效其他诸如line-height、text-align等放到父class中设置 */
.picker-center-row {
height: 88rpx;
}

View File

@@ -0,0 +1,35 @@
const AuthStepType = {
ONE: 1,
TWO: 2,
THREE: 3,
};
Component({
options: {
multipleSlots: true,
},
properties: {
currAuthStep: {
type: Number,
value: AuthStepType.ONE,
},
userInfo: {
type: Object,
value: {},
},
isNeedGetUserInfo: {
type: Boolean,
value: false,
},
},
data: {
defaultAvatarUrl:
'https://cdn-we-retail.ym.tencent.com/miniapp/usercenter/icon-user-center-avatar@2x.png',
AuthStepType,
},
methods: {
gotoUserEditPage() {
this.triggerEvent('gotoUserEditPage');
},
},
});

View File

@@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-avatar": "tdesign-miniprogram/avatar/avatar"
}
}

View File

@@ -0,0 +1,34 @@
<view class="user-center-card">
<!-- 未登录的情况 -->
<block wx:if="{{currAuthStep === AuthStepType.ONE}}">
<view class="user-center-card__header" bind:tap="gotoUserEditPage">
<t-avatar image="{{userInfo.avatarUrl || defaultAvatarUrl}}" class="user-center-card__header__avatar" />
<view class="user-center-card__header__name">{{'请登录'}}</view>
</view>
</block>
<!-- 已登录但未授权用户信息情况 -->
<block wx:if="{{currAuthStep === AuthStepType.TWO}}">
<view class="user-center-card__header">
<t-avatar image="{{userInfo.avatarUrl || defaultAvatarUrl}}" class="user-center-card__header__avatar" />
<view class="user-center-card__header__name">{{userInfo.nickName || '微信用户'}}</view>
<!-- 需要授权用户信息通过slot添加弹窗 -->
<view class="user-center-card__header__transparent" wx:if="{{isNeedGetUserInfo}}">
<slot name="getUserInfo" />
</view>
<!-- 不需要授权用户信息仍然触发gotoUserEditPage事件 -->
<view class="user-center-card__header__transparent" bind:tap="gotoUserEditPage" wx:else></view>
</view>
</block>
<!-- 已登录且已经授权用户信息的情况 -->
<block wx:if="{{currAuthStep === AuthStepType.THREE}}">
<view class="user-center-card__header" bind:tap="gotoUserEditPage">
<t-avatar
t-class="avatar"
mode="aspectFill"
class="user-center-card__header__avatar"
image="{{userInfo.avatarUrl || defaultAvatarUrl}}"
/>
<view class="user-center-card__header__name">{{userInfo.nickName || '微信用户'}}</view>
</view>
</block>
</view>

View File

@@ -0,0 +1,48 @@
.user-center-card {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 480rpx;
background-image: url('https://cdn-we-retail.ym.tencent.com/miniapp/template/user-center-bg-v1.png');
background-size: cover;
background-repeat: no-repeat;
padding: 0 24rpx;
}
.user-center-card__header {
margin-top: 192rpx;
margin-bottom: 48rpx;
height: 96rpx;
line-height: 48rpx;
display: flex;
justify-content: flex-start;
align-items: center;
color: #333;
position: relative;
}
.user-center-card__header__avatar {
width: 96rpx;
height: 96rpx;
border-radius: 48rpx;
overflow: hidden;
}
.user-center-card__header__name {
font-size: 36rpx;
line-height: 48rpx;
color: #333;
font-weight: bold;
margin-left: 24rpx;
margin-right: 16rpx;
}
.user-center-card__header__transparent {
position: absolute;
left: 0;
top: 0;
background-color: transparent;
height: 100%;
width: 100%;
}
.user-center-card__icon {
line-height: 96rpx;
}