├── README.md ├── components ├── upload-image │ ├── upload-image.wxss │ ├── upload-image.json │ ├── upload-image.wxml │ └── upload-image.js ├── navigation-bar │ ├── navigation-bar.wxss │ ├── navigation-bar.json │ ├── navigation-bar.js │ └── navigation-bar.wxml ├── scroll-y │ ├── scroll-y.json │ ├── scroll-y.wxss │ ├── scroll-y.wxml │ └── scroll-y.js ├── tab-nav-roll │ ├── tab-nav-roll.json │ ├── tab-nav-roll.wxml │ ├── tab-nav-roll.wxss │ └── tab-nav-roll.js ├── login-authorization │ ├── login-authorization.json │ ├── login-authorization.wxml │ ├── login-authorization.js │ └── login-authorization.wxss ├── picker │ ├── picker.json │ ├── picker.wxml │ ├── picker.wxss │ └── picker.js └── turntable │ ├── turntable.json │ ├── turntable.wxss │ ├── turntable.wxml │ └── turntable.js ├── pages ├── activity │ ├── activity.wxss │ ├── activity.json │ ├── activity.wxml │ └── activity.js ├── logs │ ├── logs.json │ ├── logs.wxss │ ├── logs.wxml │ └── logs.js ├── index │ ├── index.json │ ├── index.wxss │ ├── index.wxml │ └── index.js ├── mine │ ├── mine.json │ ├── mine.js │ ├── mine.wxss │ └── mine.wxml ├── login │ ├── login.json │ ├── login.wxml │ ├── login.wxss │ └── login.js ├── edit-card │ ├── edit-card.json │ ├── edit-card.wxss │ ├── edit-card.js │ └── edit-card.wxml ├── client-pool │ ├── client-pool.json │ ├── client-pool.wxss │ ├── client-pool.wxml │ └── client-pool.js ├── message │ ├── message.json │ ├── message.wxml │ ├── message.wxss │ └── message.js ├── goods │ ├── goods.json │ ├── goods.wxml │ ├── goods.wxss │ └── goods.js └── home │ ├── home.json │ ├── home.js │ ├── home.wxss │ └── home.wxml ├── WeChat_applet.zip ├── image ├── home │ ├── btn1.png │ ├── btn2.png │ ├── btn3.png │ └── edit.png ├── mine │ ├── bg_1.jpg │ ├── icon_erwei.png │ ├── user_icon1.png │ ├── user_icon2.png │ ├── user_icon3.png │ └── user_icon4.png ├── common │ ├── bus.png │ ├── finish.png │ ├── praise.png │ ├── icon_add.png │ ├── icon_right.png │ ├── praiseing.gif │ ├── shopcard.jpg │ ├── shopcard_1.png │ ├── underline.png │ ├── unpraise.png │ ├── pull_refresh.gif │ └── select_black.png ├── login │ └── defPic.png ├── message │ └── tip.png ├── customer │ ├── btn_call.png │ └── bot_icon1.png └── tabbar │ ├── home_checked.png │ ├── msg_checked.png │ ├── center_checked.png │ ├── client_checked.png │ ├── goods_checked.png │ ├── goods_uncheck.png │ ├── home_unchecked.png │ ├── msg_unchecked.png │ ├── center_unchecked.png │ └── client_unchecked.png ├── sitemap.json ├── .gitignore ├── utils ├── tools.js ├── request.js ├── publicData.js ├── util.js └── WxValidate.js ├── api └── loginApi.js ├── project.config.json ├── assets ├── moduleLess │ └── login-authorization │ │ └── login-authorization.less └── less │ ├── style.less │ ├── message │ └── message.less │ └── goods │ └── goods.less ├── app.json ├── js └── common.js ├── app.js └── app.wxss /README.md: -------------------------------------------------------------------------------- 1 | # WeChat_couponents -------------------------------------------------------------------------------- /components/upload-image/upload-image.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/navigation-bar/navigation-bar.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/scroll-y/scroll-y.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /pages/activity/activity.wxss: -------------------------------------------------------------------------------- 1 | .zhuanpan{ 2 | width: 50%; 3 | } -------------------------------------------------------------------------------- /components/tab-nav-roll/tab-nav-roll.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /components/upload-image/upload-image.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /components/navigation-bar/navigation-bar.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /components/login-authorization/login-authorization.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true 3 | } -------------------------------------------------------------------------------- /WeChat_applet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/WeChat_applet.zip -------------------------------------------------------------------------------- /components/picker/picker.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /components/upload-image/upload-image.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /image/home/btn1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/home/btn1.png -------------------------------------------------------------------------------- /image/home/btn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/home/btn2.png -------------------------------------------------------------------------------- /image/home/btn3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/home/btn3.png -------------------------------------------------------------------------------- /image/home/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/home/edit.png -------------------------------------------------------------------------------- /image/mine/bg_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/bg_1.jpg -------------------------------------------------------------------------------- /pages/logs/logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "查看启动日志", 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /components/turntable/turntable.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } 5 | -------------------------------------------------------------------------------- /image/common/bus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/bus.png -------------------------------------------------------------------------------- /image/login/defPic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/login/defPic.png -------------------------------------------------------------------------------- /image/message/tip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/message/tip.png -------------------------------------------------------------------------------- /image/common/finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/finish.png -------------------------------------------------------------------------------- /image/common/praise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/praise.png -------------------------------------------------------------------------------- /components/upload-image/upload-image.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: {}, 3 | properties: {}, 4 | methods: {} 5 | }) -------------------------------------------------------------------------------- /image/common/icon_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/icon_add.png -------------------------------------------------------------------------------- /image/common/icon_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/icon_right.png -------------------------------------------------------------------------------- /image/common/praiseing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/praiseing.gif -------------------------------------------------------------------------------- /image/common/shopcard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/shopcard.jpg -------------------------------------------------------------------------------- /image/common/shopcard_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/shopcard_1.png -------------------------------------------------------------------------------- /image/common/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/underline.png -------------------------------------------------------------------------------- /image/common/unpraise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/unpraise.png -------------------------------------------------------------------------------- /image/customer/btn_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/customer/btn_call.png -------------------------------------------------------------------------------- /image/mine/icon_erwei.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/icon_erwei.png -------------------------------------------------------------------------------- /image/mine/user_icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/user_icon1.png -------------------------------------------------------------------------------- /image/mine/user_icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/user_icon2.png -------------------------------------------------------------------------------- /image/mine/user_icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/user_icon3.png -------------------------------------------------------------------------------- /image/mine/user_icon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/mine/user_icon4.png -------------------------------------------------------------------------------- /components/navigation-bar/navigation-bar.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | data: {}, 3 | properties: {}, 4 | methods: {} 5 | }) -------------------------------------------------------------------------------- /image/common/pull_refresh.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/pull_refresh.gif -------------------------------------------------------------------------------- /image/common/select_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/common/select_black.png -------------------------------------------------------------------------------- /image/customer/bot_icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/customer/bot_icon1.png -------------------------------------------------------------------------------- /image/tabbar/home_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/home_checked.png -------------------------------------------------------------------------------- /image/tabbar/msg_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/msg_checked.png -------------------------------------------------------------------------------- /image/tabbar/center_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/center_checked.png -------------------------------------------------------------------------------- /image/tabbar/client_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/client_checked.png -------------------------------------------------------------------------------- /image/tabbar/goods_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/goods_checked.png -------------------------------------------------------------------------------- /image/tabbar/goods_uncheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/goods_uncheck.png -------------------------------------------------------------------------------- /image/tabbar/home_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/home_unchecked.png -------------------------------------------------------------------------------- /image/tabbar/msg_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/msg_unchecked.png -------------------------------------------------------------------------------- /image/tabbar/center_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/center_unchecked.png -------------------------------------------------------------------------------- /image/tabbar/client_unchecked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZRH86/WeChat_couponents/HEAD/image/tabbar/client_unchecked.png -------------------------------------------------------------------------------- /pages/activity/activity.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "zhuanpan": "/components/turntable/turntable" 4 | } 5 | } -------------------------------------------------------------------------------- /pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {}, 3 | "enablePullDownRefresh": true, 4 | "backgroundTextStyle": "dark" 5 | } -------------------------------------------------------------------------------- /pages/mine/mine.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "我的", 3 | "enablePullDownRefresh": false, 4 | "backgroundTextStyle": "dark" 5 | } -------------------------------------------------------------------------------- /pages/logs/logs.wxss: -------------------------------------------------------------------------------- 1 | .log-list { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 40rpx; 5 | } 6 | .log-item { 7 | margin: 10rpx; 8 | } 9 | -------------------------------------------------------------------------------- /pages/login/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "登录", 3 | "usingComponents": {}, 4 | "enablePullDownRefresh": false, 5 | "backgroundTextStyle": "dark" 6 | } -------------------------------------------------------------------------------- /pages/edit-card/edit-card.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "编辑名片", 3 | "usingComponents": {}, 4 | "enablePullDownRefresh": false, 5 | "backgroundTextStyle": "dark" 6 | } -------------------------------------------------------------------------------- /sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /pages/logs/logs.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{index + 1}}.{{key}}. {{log}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /pages/client-pool/client-pool.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "客户池", 3 | "usingComponents": { 4 | "picker-element": "../../components/picker/picker" 5 | }, 6 | "enablePullDownRefresh": false, 7 | "backgroundTextStyle": "dark" 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | /target/ 5 | /server/dist/ 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | package-lock.json 10 | 11 | # Editor directories and files 12 | .idea 13 | .vscode 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | -------------------------------------------------------------------------------- /pages/message/message.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "消息", 3 | "usingComponents": { 4 | "scroll-y": "../../components/scroll-y/scroll-y", 5 | "turntable": "../../components/turntable/turntable" 6 | }, 7 | "enablePullDownRefresh": false, 8 | "backgroundTextStyle": "dark" 9 | } -------------------------------------------------------------------------------- /pages/goods/goods.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "商品", 3 | "usingComponents": { 4 | "tab-nav-roll": "../../components/tab-nav-roll/tab-nav-roll", 5 | "scroll-y": "../../components/scroll-y/scroll-y" 6 | }, 7 | "enablePullDownRefresh": false, 8 | "backgroundTextStyle": "dark" 9 | } -------------------------------------------------------------------------------- /pages/logs/logs.js: -------------------------------------------------------------------------------- 1 | //logs.js 2 | const util = require('../../utils/util.js') 3 | 4 | Page({ 5 | data: { 6 | logs: [] 7 | }, 8 | onLoad: function () { 9 | // this.setData({ 10 | // logs: (wx.getStorageSync('logs') || []).map(log => { 11 | // return util.formatTime(new Date(log)) 12 | // }) 13 | // }) 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /utils/tools.js: -------------------------------------------------------------------------------- 1 | function _typeof(obj) { 2 | return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); 3 | } 4 | function isString(obj) { //是否字符串 5 | return _typeof(obj) === 'string' 6 | } 7 | function isPlainObject(obj) { 8 | return _typeof(obj) === 'object'; 9 | } 10 | module.exports = { 11 | isString, 12 | isPlainObject 13 | } -------------------------------------------------------------------------------- /pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | /**index.wxss**/ 2 | .userinfo { 3 | display: flex; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | 8 | .userinfo-avatar { 9 | width: 128rpx; 10 | height: 128rpx; 11 | margin: 20rpx; 12 | border-radius: 50%; 13 | } 14 | 15 | .userinfo-nickname { 16 | color: #aaa; 17 | } 18 | 19 | .usermotto { 20 | margin-top: 200px; 21 | } -------------------------------------------------------------------------------- /pages/home/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "~~~", 3 | "usingComponents": { 4 | "tab-nav-roll": "../../components/tab-nav-roll/tab-nav-roll", 5 | "scroll-y": "../../components/scroll-y/scroll-y", 6 | "login-authorization": "../../components/login-authorization/login-authorization" 7 | }, 8 | "enablePullDownRefresh": false, 9 | "backgroundTextStyle": "dark" 10 | } -------------------------------------------------------------------------------- /api/loginApi.js: -------------------------------------------------------------------------------- 1 | import request from '../utils/request' 2 | 3 | const url = 'https://www.easy-mock.com/mock' 4 | 5 | const homeApi = { 6 | login(dataObj) { 7 | console.log(dataObj) 8 | return request.networkpost({ 9 | url: `${url}/5d6874546d1ba0766849df36/example/shishi`, 10 | headers: '', 11 | data: dataObj, 12 | }) 13 | } 14 | } 15 | 16 | export default homeApi -------------------------------------------------------------------------------- /pages/mine/mine.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | entrance: [ 4 | [ 5 | {title: '我的名片', icon: '../../image/mine/user_icon1.png'}, 6 | {title: '我的方案', icon: '../../image/mine/user_icon2.png'}, 7 | {title: '我的活动', icon: '../../image/mine/user_icon4.png'} 8 | ], [ 9 | {title: '我的名片', icon: '../../image/mine/user_icon1.png'}, 10 | {title: '我的方案', icon: '../../image/mine/user_icon2.png'} 11 | ] 12 | ] 13 | }, 14 | onShow() { 15 | 16 | } 17 | }) -------------------------------------------------------------------------------- /components/tab-nav-roll/tab-nav-roll.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{item.name}} 4 | 5 |
6 |
-------------------------------------------------------------------------------- /pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | {{motto}} 13 | 14 | 15 | -------------------------------------------------------------------------------- /components/scroll-y/scroll-y.wxss: -------------------------------------------------------------------------------- 1 | .scroll-view { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | } 8 | 9 | .icon-refresh { 10 | width: 100rpx; 11 | height: 100rpx; 12 | } 13 | 14 | .pull-refresh { 15 | height: 140rpx; 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | transition: all .5s ease-in-out; 20 | overflow: hidden; 21 | } 22 | 23 | .chu { 24 | height: 110rpx; 25 | } 26 | 27 | .jin { 28 | height: 0rpx; 29 | } 30 | 31 | .f-color-666 { 32 | color: #666; 33 | } 34 | 35 | .fs24 { 36 | font-size: 24rpx; 37 | } -------------------------------------------------------------------------------- /components/navigation-bar/navigation-bar.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{ navigationBarTitle }} 12 | 13 | 14 | -------------------------------------------------------------------------------- /components/scroll-y/scroll-y.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{pull.pullText}} 6 | 7 | 8 | 9 | 10 | {{push.pullText}} 11 | 12 | 13 | -------------------------------------------------------------------------------- /pages/login/login.wxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 19 | 20 | -------------------------------------------------------------------------------- /components/login-authorization/login-authorization.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | -------------------------------------------------------------------------------- /pages/edit-card/edit-card.wxss: -------------------------------------------------------------------------------- 1 | .edit-card-title{ 2 | background: #f5f5f5; 3 | padding: 0 50rpx; 4 | line-height: 3.5em; 5 | } 6 | .basic-info{ 7 | display: flex; 8 | align-items: center; 9 | padding-left: 50rpx; 10 | padding-right: 50rpx; 11 | } 12 | .h90{ 13 | height: 90rpx; 14 | border-bottom: 2rpx solid #f5f5f5; 15 | } 16 | .basic-info-label{ 17 | width: 100rpx; 18 | color: #333; 19 | } 20 | .basic-info-input{ 21 | flex: 1; 22 | } 23 | .placeholder-color{ 24 | color: #ccc; 25 | } 26 | .image-list{ 27 | display: flex; 28 | justify-content: space-between; 29 | flex-wrap: wrap; 30 | } 31 | .wh{ 32 | width: 100%; 33 | height: 200rpx; 34 | } 35 | .save{ 36 | width: 100%; 37 | height: 80rpx; 38 | line-height: 80rpx; 39 | border-radius: 10rpx; 40 | color: #fff; 41 | background: linear-gradient(to right, #ddbf93, #b08351); 42 | } -------------------------------------------------------------------------------- /pages/activity/activity.wxml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 22 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": false, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "coverView": true, 13 | "autoAudits": true, 14 | "checkInvalidKey": true, 15 | "checkSiteMap": true, 16 | "uploadWithSourceMap": true, 17 | "babelSetting": { 18 | "ignore": [], 19 | "disablePlugins": [], 20 | "outputPath": "" 21 | } 22 | }, 23 | "compileType": "miniprogram", 24 | "libVersion": "2.9.3", 25 | "appid": "wxc15b8be1227941c4", 26 | "projectname": "weixin", 27 | "debugOptions": { 28 | "hidedInDevtools": [] 29 | }, 30 | "isGameTourist": false, 31 | "simulatorType": "wechat", 32 | "simulatorPluginLibVersion": {}, 33 | "condition": { 34 | "search": { 35 | "current": -1, 36 | "list": [] 37 | }, 38 | "conversation": { 39 | "current": -1, 40 | "list": [] 41 | }, 42 | "game": { 43 | "currentL": -1, 44 | "list": [] 45 | }, 46 | "miniprogram": { 47 | "current": -1, 48 | "list": [] 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /components/tab-nav-roll/tab-nav-roll.wxss: -------------------------------------------------------------------------------- 1 | .trigger-number{ 2 | position: relative; 3 | height: 80rpx; 4 | white-space: nowrap; 5 | } 6 | .trigger-number-item{ 7 | display: inline-block; 8 | text-align: center; 9 | line-height: 80rpx; 10 | padding-left: 20rpx; 11 | padding-right: 20rpx; 12 | } 13 | .trigger-number-item2{ 14 | width: 50%; 15 | } 16 | .trigger-number-item3{ 17 | width: 30%; 18 | } 19 | .trigger-number-item-text{ 20 | position: relative; 21 | display: inline; 22 | } 23 | .tab-bottom-line{ 24 | height: 4rpx; 25 | background: #bb7d41; 26 | position: absolute; 27 | left: 0; 28 | top: 75rpx; 29 | } 30 | /* .active{ 31 | background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHMAAAALCAYAAABMMrJKAAAA1UlEQVRYhe2VYQ7CIAyFa+L9/+xAnsSjtM8gBQqiydRtwHjJ0kI2SPrt5V3utwU0sAD4R8RUIXFVQmVf2a19L8xpv3xPiu/hewj0bBBB0t1wI95+zNcRMT6HZyBKHHYJMcEDK8Ri/Q5c2Isg7Q+zI0CrgWBCnQEdMCoQg+tML5w58pML04+BHGLc2x+gVfcwc0dUhv8CkgtHKtCKA+05aa33BPdp34K6hHmmHFyjbmCeNQfXqHGYMwfXqEmYMwe/UzMwZw7+rkNhzhz8rw6AOXNwExHRA6NCWTurLNEkAAAAAElFTkSuQmCC) 0rpx 25rpx no-repeat; 32 | } */ -------------------------------------------------------------------------------- /components/picker/picker.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{cancelText}} 7 | 8 | {{titleText}} 9 | 10 | {{sureText}} 11 | 12 | 13 | 14 | 15 | 16 | 17 | {{isUseKeywordOfShow?itemIn[keyWordsOfShow]:itemIn}} 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /pages/login/login.wxss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 100%; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: center; 7 | justify-content: space-sbetween; 8 | } 9 | 10 | .logo { 11 | width: 240rpx; 12 | height: 240rpx; 13 | margin-top: 60rpx; 14 | } 15 | 16 | .logo image { 17 | width: 100%; 18 | height: 100%; 19 | } 20 | 21 | .user-info { 22 | width: 100%; 23 | margin-top: 80rpx; 24 | display: flex; 25 | flex-direction: column; 26 | justify-content: center; 27 | align-items: center; 28 | } 29 | 30 | .user-info-form { 31 | width: 75%; 32 | } 33 | 34 | .user-info-item { 35 | margin-bottom: 20rpx; 36 | box-sizing: border-box; 37 | } 38 | 39 | .login-title { 40 | font-size: 32rpx; 41 | color: #ccc; 42 | } 43 | 44 | input { 45 | width: 100%; 46 | height: 80rpx; 47 | border-bottom: 1rpx solid #eee; 48 | padding: 10rpx 20rpx; 49 | } 50 | 51 | .placeholder { 52 | color: #eee; 53 | font-size: 20rpx; 54 | } 55 | 56 | .login-button { 57 | margin-top: 50rpx; 58 | } 59 | 60 | button { 61 | height: 80rpx; 62 | line-height: 80rpx; 63 | background: linear-gradient(to right, #ddbf93, #b08351); 64 | color: #fff; 65 | font-size: 32rpx; 66 | } 67 | 68 | button::after { 69 | border: none; 70 | } -------------------------------------------------------------------------------- /pages/mine/mine.wxss: -------------------------------------------------------------------------------- 1 | .container-mine { 2 | background: #f5f5f5; 3 | } 4 | 5 | .mine-info { 6 | position: relative; 7 | width: 100%; 8 | height: 360rpx; 9 | } 10 | 11 | .mine-bg { 12 | width: 100%; 13 | height: 360rpx; 14 | opacity: .4; 15 | } 16 | 17 | .mine-info-head { 18 | position: absolute; 19 | top: 0; 20 | left: 0; 21 | right: 0; 22 | height: 360rpx; 23 | background: rgba(0, 0, 0, .3); 24 | display: flex; 25 | flex-direction: column; 26 | justify-content: center; 27 | align-items: center; 28 | } 29 | 30 | .mine-info-head-image { 31 | width: 120rpx; 32 | height: 120rpx; 33 | border-radius: 500rpx; 34 | border: 4rpx solid #fff; 35 | } 36 | 37 | .qr-code { 38 | position: absolute; 39 | top: 30rpx; 40 | right: 0; 41 | width: 140rpx; 42 | height: 60rpx; 43 | } 44 | .entrance-list-item{ 45 | display: flex; 46 | justify-content: space-between; 47 | align-items: center; 48 | background: #fff; 49 | border-bottom: 2rpx solid #f5f5f5; 50 | } 51 | .entrance-list-item-title{ 52 | display: flex; 53 | align-items: center; 54 | } 55 | .entrance-list-item-image{ 56 | width: 60rpx; 57 | height: 60rpx; 58 | } 59 | .log-out-button{ 60 | width: 70%; 61 | background: linear-gradient(to right, #ddbf93, #b08351); 62 | color: #fff; 63 | } 64 | .log-out-button::after{ 65 | border: none; 66 | } -------------------------------------------------------------------------------- /components/login-authorization/login-authorization.js: -------------------------------------------------------------------------------- 1 | import {ossImgShow1} from '../../utils/util' 2 | Component({ 3 | data: { 4 | loginBoxImg: ossImgShow1('Marketing/NameCard/Authorization/loginBox.png'), 5 | isshowModal: false, 6 | animationMask: {}, 7 | animationDialog: {} 8 | }, 9 | properties: {}, 10 | methods: { 11 | showModal() { 12 | this.setData({ 13 | isshowModal: true 14 | }); 15 | setTimeout(() => { 16 | this._animationExport(1, 0); 17 | }, 100); 18 | }, 19 | hideModal() { 20 | this._animationExport(0, -75); 21 | setTimeout(() => { 22 | this.setData({ 23 | isshowModal: false 24 | }); 25 | }, 200); 26 | }, 27 | _animationExport(opacity, translateY) { 28 | let animation = wx.createAnimation({ 29 | duration: 200, 30 | timingFunction: 'linear' 31 | }); 32 | animation.opacity(opacity).step(); 33 | this.setData({ 34 | animationMask: animation.export() 35 | }); 36 | animation.opacity(opacity).translateY(translateY).step(); 37 | this.setData({ 38 | animationDialog: animation.export() 39 | }); 40 | }, 41 | onGotUserInfo(e) { 42 | console.log(e) 43 | } 44 | } 45 | }); -------------------------------------------------------------------------------- /assets/moduleLess/login-authorization/login-authorization.less: -------------------------------------------------------------------------------- 1 | @import "../../less/style.less"; 2 | .login-mask{ 3 | position: fixed; 4 | top: 0; 5 | bottom: 0; 6 | .width(100%); 7 | .bg(rgba(0, 0, 0, .5)); 8 | z-index: 99; 9 | .login-tip { 10 | position: absolute; 11 | top: 50%; 12 | left: 50%; 13 | transform: translate(-50%, -50%); 14 | .width(70%); 15 | .bg(#fff); 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | border-radius: 10rpx; 21 | .login-tip-content { 22 | display: flex; 23 | flex-direction: column; 24 | justify-content: center; 25 | align-items: center; 26 | .padding-1(20rpx, 30rpx); 27 | .login-tip-text { 28 | .lh(); 29 | .fs(30rpx); 30 | } 31 | .login-image { 32 | .width(400 rpx); 33 | } 34 | } 35 | } 36 | .login-tip-btn{ 37 | display: flex; 38 | width: 100%; 39 | .button{ 40 | position: relative; 41 | flex: 1; 42 | display: flex; 43 | justify-content: center; 44 | align-items: center; 45 | .heigth(80rpx); 46 | .color(#666); 47 | border: 1rpx solid #eee; 48 | button{ 49 | position: absolute; 50 | left: 0; 51 | right: 0; 52 | top: 0; 53 | bottom: 0; 54 | opacity: 0; 55 | } 56 | } 57 | .active{ 58 | .color(#b08351); 59 | border-left: 1rpx solid #eee; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /components/login-authorization/login-authorization.wxss: -------------------------------------------------------------------------------- 1 | .login-mask { 2 | position: fixed; 3 | top: 0; 4 | bottom: 0; 5 | width: 100%; 6 | background: rgba(0, 0, 0, 0.5); 7 | z-index: 99; 8 | } 9 | .login-mask .login-tip { 10 | position: absolute; 11 | top: 50%; 12 | left: 50%; 13 | transform: translate(-50%, -50%); 14 | width: 70%; 15 | background: #fff; 16 | display: flex; 17 | flex-direction: column; 18 | justify-content: center; 19 | align-items: center; 20 | border-radius: 10rpx; 21 | } 22 | .login-mask .login-tip .login-tip-content { 23 | display: flex; 24 | flex-direction: column; 25 | justify-content: center; 26 | align-items: center; 27 | padding: 20rpx 30rpx; 28 | } 29 | .login-mask .login-tip .login-tip-content .login-tip-text { 30 | line-height: 1.5em; 31 | font-size: 30rpx; 32 | } 33 | .login-mask .login-tip .login-tip-content .login-image { 34 | width: 400 rpx; 35 | } 36 | .login-mask .login-tip-btn { 37 | display: flex; 38 | width: 100%; 39 | } 40 | .login-mask .login-tip-btn .button { 41 | position: relative; 42 | flex: 1; 43 | display: flex; 44 | justify-content: center; 45 | align-items: center; 46 | height: 80rpx; 47 | color: #666; 48 | border: 1rpx solid #eee; 49 | } 50 | .login-mask .login-tip-btn .button .get-user-info { 51 | position: absolute; 52 | left: 0; 53 | right: 0; 54 | top: 0; 55 | bottom: 0; 56 | opacity: 0; 57 | } 58 | .login-mask .login-tip-btn .active { 59 | color: #b08351; 60 | border-left: 1rpx solid #eee; 61 | } 62 | -------------------------------------------------------------------------------- /pages/message/message.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 客户名 12 | {{item.date}} 13 | 14 | 我对商品有意向,请联系我!我对商品有意向,请联系我!我对商品有意向,请联系我! 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 微信提醒剩余121点我增加 25 | 26 | -------------------------------------------------------------------------------- /pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | motto: 'Hello World', 8 | userInfo: {}, 9 | hasUserInfo: false, 10 | canIUse: wx.canIUse('button.open-type.getUserInfo') 11 | }, 12 | //事件处理函数 13 | bindViewTap: function () { 14 | wx.navigateTo({ 15 | url: '../logs/logs' 16 | }) 17 | }, 18 | onLoad: function () { 19 | /** 20 | * 获取用户登录信息 21 | * 1、获取到-跳转home 22 | * 2、未获取到-跳转login进行登录 23 | */ 24 | if(!app.globalData.hasUserInfo) { 25 | wx.switchTab({ 26 | url: '../home/home' 27 | }) 28 | } else { 29 | wx.reLaunch({ 30 | url: '../login/login' 31 | }) 32 | } 33 | // if (app.globalData.userInfo) { 34 | // this.setData({ 35 | // userInfo: app.globalData.userInfo, 36 | // hasUserInfo: true 37 | // }) 38 | // } else if (this.data.canIUse) { 39 | // // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 40 | // // 所以此处加入 callback 以防止这种情况 41 | // app.userInfoReadyCallback = res => { 42 | // this.setData({ 43 | // userInfo: res.userInfo, 44 | // hasUserInfo: true 45 | // }) 46 | // } 47 | // } else { 48 | // // 在没有 open-type=getUserInfo 版本的兼容处理 49 | // wx.getUserInfo({ 50 | // success: res => { 51 | // app.globalData.userInfo = res.userInfo 52 | // this.setData({ 53 | // userInfo: res.userInfo, 54 | // hasUserInfo: true 55 | // }) 56 | // } 57 | // }) 58 | // } 59 | }, 60 | getUserInfo: function (e) { 61 | app.globalData.userInfo = e.detail.userInfo 62 | this.setData({ 63 | userInfo: e.detail.userInfo, 64 | hasUserInfo: true 65 | }) 66 | }, 67 | login() { 68 | wx.navigateTo({ 69 | url: '../login/login' 70 | }) 71 | } 72 | }) 73 | -------------------------------------------------------------------------------- /components/picker/picker.wxss: -------------------------------------------------------------------------------- 1 | .full-box { 2 | position: fixed; 3 | left: 0; 4 | right: 0; 5 | bottom: 0; 6 | top: 0; 7 | z-index: 9999; 8 | opacity: 0; 9 | background: rgba(0, 0, 0, .4); 10 | transition: all .4s ease-in-out 0; 11 | pointer-events: none; 12 | } 13 | 14 | .full-box.cur { 15 | opacity: 1; 16 | pointer-events: auto 17 | } 18 | 19 | .modal { 20 | position: absolute; 21 | width: 100%; 22 | height: 50%; 23 | bottom: -50%; 24 | left: 0; 25 | background: transparent; 26 | transition: all .4s ease-in-out 0; 27 | } 28 | 29 | .picker { 30 | position: absolute; 31 | width: 100%; 32 | height: 235px; 33 | bottom: -235px; 34 | left: 0; 35 | background: #fff; 36 | display: flex; 37 | flex-direction: column; 38 | transition: all .4s ease-in-out 0; 39 | } 40 | 41 | .cur .picker { 42 | bottom: 0; 43 | } 44 | 45 | .cur .modal { 46 | bottom: 50%; 47 | } 48 | 49 | .picker-line { 50 | display: flex; 51 | justify-content: center; 52 | align-items: center; 53 | } 54 | 55 | .picker-header { 56 | height: 20%; 57 | box-sizing: border-box; 58 | padding: 0 20rpx; 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | border-bottom: 1px solid #eeeeee; 63 | } 64 | 65 | .picker-header view { 66 | height: 100%; 67 | display: flex; 68 | justify-content: center; 69 | align-items: center; 70 | } 71 | 72 | .picker-header view text { 73 | font-size: 36rpx; 74 | } 75 | 76 | .picker-content { 77 | flex-grow: 1; 78 | } 79 | 80 | .line1 { 81 | overflow: hidden; 82 | text-overflow: ellipsis; 83 | white-space: nowrap; 84 | lines: 1 85 | } -------------------------------------------------------------------------------- /assets/less/style.less: -------------------------------------------------------------------------------- 1 | //颜色 2 | @main: #b08351; 3 | @ccc: #ccc; 4 | @f5f5f5: #f5f5f5; 5 | 6 | // 盒子宽高 7 | .size(@w, @h) { width: @w; height: @h} 8 | 9 | // 高度 10 | .heigth(@h) { height: @h} 11 | 12 | // 宽度 13 | .width(@w) {width: @w;} 14 | 15 | // 行高 16 | .lh(@lh: 1.5em) { line-height: @lh;} 17 | 18 | // 内填充(上下左右) 19 | .padding(@p) { padding: @p; } 20 | 21 | // 内填充你(左右 or 上下) 22 | .padding-1(@lr: 0, @tb: 0) { padding: @lr @tb; } 23 | 24 | // 外填充(上下左右) 25 | .margin(@m) { margin: @m; } 26 | 27 | // 内填充你(左右 or 上下) 28 | .margin-1(@lr: 0, @tb: 0) { margin: @lr @tb; } 29 | 30 | // 文字、图片居中 31 | .center(text-x) {text-align: center;} 32 | .center(text-y) {display: table-cell; vertical-align: middle;} 33 | 34 | // 字体大小 35 | .fs(@fs) {font-size: @fs;} 36 | 37 | // 字体颜色,包括连接与非连接 38 | .color(@color) { color: @color;} 39 | 40 | // 背景颜色 41 | .bg(@bg) {background: @bg} 42 | 43 | // 背景渐变 44 | .bg-gradient( @c1: #eee, @c2: #999, @direction: right) { background: linear-gradient(to @direction, @c1, @c2);} 45 | 46 | // 元素垂直水平居中 47 | .center() { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);} 48 | 49 | // 文本渐变 50 | .font-gradient(@c1: #eee, @c2: #999, @direction: right){ 51 | background: linear-gradient(to @direction, @c1, @c2); 52 | -webkit-background-clip: text; 53 | color: transparent; 54 | -webkit-text-fill-color: transparent; 55 | text-fill-color: transparent; 56 | } 57 | 58 | // 禁止换行,文本溢出省略号(一行) 59 | .ellipsis() { 60 | white-space: normal; // 设置文字在一行显示,不能换行 61 | word-wrap: break-word; 62 | word-break: break-all; 63 | -o-text-overflow: ellipsis; 64 | -ms-text-overflow: ellipsis; 65 | text-overflow: ellipsis; // 规定当文本溢出时,显示省略符号来代表被修剪的文本 66 | } 67 | 68 | // 文本溢出省略号显示(多行) 69 | .ellipsis-mult(@n: 3) { display: -webkit-box; overflow: hidden; -webkit-line-clamp: @n; -webkit-box-orient: vertical;} -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/login/login", 5 | "pages/home/home", 6 | "pages/goods/goods", 7 | "pages/client-pool/client-pool", 8 | "pages/message/message", 9 | "pages/mine/mine", 10 | "pages/edit-card/edit-card", 11 | "pages/activity/activity" 12 | ], 13 | "window": { 14 | "backgroundTextStyle": "light", 15 | "navigationBarBackgroundColor": "#fff", 16 | "navigationBarTitleText": "WeChat", 17 | "navigationBarTextStyle": "black" 18 | }, 19 | "sitemapLocation": "sitemap.json", 20 | "tabBar": { 21 | "color": "#ccc", 22 | "selectedColor": "#b08351", 23 | "borderStyle": "black", 24 | "list": [ 25 | { 26 | "selectedIconPath": "image/tabbar/home_checked.png", 27 | "iconPath": "image/tabbar/home_unchecked.png", 28 | "pagePath": "pages/home/home", 29 | "text": "首页" 30 | }, 31 | { 32 | "selectedIconPath": "image/tabbar/goods_checked.png", 33 | "iconPath": "image/tabbar/goods_uncheck.png", 34 | "pagePath": "pages/activity/activity", 35 | "text": "商品" 36 | }, 37 | { 38 | "selectedIconPath": "image/tabbar/client_checked.png", 39 | "iconPath": "image/tabbar/client_unchecked.png", 40 | "pagePath": "pages/client-pool/client-pool", 41 | "text": "客户" 42 | }, 43 | { 44 | "selectedIconPath": "image/tabbar/msg_checked.png", 45 | "iconPath": "image/tabbar/msg_unchecked.png", 46 | "pagePath": "pages/message/message", 47 | "text": "消息" 48 | }, 49 | { 50 | "selectedIconPath": "image/tabbar/center_checked.png", 51 | "iconPath": "image/tabbar/center_unchecked.png", 52 | "pagePath": "pages/mine/mine", 53 | "text": "我的" 54 | } 55 | ] 56 | } 57 | } -------------------------------------------------------------------------------- /pages/mine/mine.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 姜欣欣 8 | (设计顾问) 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {{value.title}} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /components/scroll-y/scroll-y.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | multipleSlots: true, // 在组建定义时的选项中启用多slot支持 4 | }, 5 | /** 6 | * 组件的属性列表 7 | */ 8 | properties: { 9 | listLength: { 10 | type: Number, 11 | value: 0 12 | }, 13 | pull: { 14 | type: Object, 15 | value: {} 16 | }, 17 | push: { 18 | type: Object, 19 | value: {} 20 | } 21 | }, 22 | pageLifetimes: { 23 | show() { 24 | this.setData({ 25 | pull: this.properties.pull, 26 | push: this.properties.push, 27 | }) 28 | }, 29 | }, 30 | /** 31 | * 组件的初始数据 32 | */ 33 | data: { 34 | pull: {}, 35 | push: {}, 36 | slideStart: [], 37 | moveTime: 0, 38 | }, 39 | created() { 40 | 41 | }, 42 | ready() { 43 | 44 | }, 45 | attached() { 46 | 47 | }, 48 | methods: { 49 | touchstart(e) { 50 | this.setData({ 51 | slideStart: e.touches[0] 52 | }) 53 | }, 54 | touchmove(e) { 55 | let moveTime = new Date().getTime(); 56 | if (moveTime - this.data.moveTime <= 2000) { 57 | return 58 | } else { 59 | this.setData({ 60 | moveTime: moveTime 61 | }) 62 | } 63 | let slideStart = this.data.slideStart; 64 | let slideMove = e.touches[0]; 65 | let startX = slideStart.pageX; 66 | let startY = slideStart.pageY; 67 | let moveEndX = slideMove.pageX; 68 | let moveEndY = slideMove.pageY; 69 | let X = moveEndX - startX; 70 | let Y = moveEndY - startY; 71 | if (Math.abs(Y) > Math.abs(X) && Y > 0) { 72 | console.log("top 2 bottom"); 73 | this.pullRefresh() 74 | } else if (Math.abs(Y) > Math.abs(X) && Y < 0) { 75 | console.log("bottom 2 top"); 76 | this.loadMore() 77 | } 78 | }, 79 | /**下拉刷新 */ 80 | pullRefresh(e) { 81 | this.triggerEvent('refresh', {refresh: true}) // 将num通过参数的形式传递给父组件 82 | }, 83 | /**上拉加载更多 */ 84 | loadMore(e) { 85 | this.triggerEvent('toload', {toload: true}) // 将num通过参数的形式传递给父组件 86 | } 87 | } 88 | }) -------------------------------------------------------------------------------- /assets/less/message/message.less: -------------------------------------------------------------------------------- 1 | @import "../style.less"; 2 | 3 | .message{ 4 | .message-item { 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | border-bottom: 2rpx solid #f5f5f5; 9 | .message-head { 10 | position: relative; 11 | image { 12 | width: 100rpx; 13 | height: 100rpx; 14 | border-radius: 500rpx; 15 | box-shadow: 2rpx 6rpx 10rpx #ccc; 16 | } 17 | .unread { 18 | position: absolute; 19 | top: 5rpx; 20 | right: 20rpx; 21 | width: 20rpx; 22 | height: 20rpx; 23 | border-radius: 500rpx; 24 | background: #E70012; 25 | } 26 | } 27 | .message-referral { 28 | flex: 1; 29 | width: 250rpx; 30 | .message-referral-1 { 31 | display: flex; 32 | justify-content: space-between; 33 | align-items: center; 34 | .message-referral-name { 35 | width: 310rpx; 36 | } 37 | } 38 | } 39 | .message-icon-right { 40 | width: 30rpx; 41 | display: flex; 42 | align-items: center; 43 | justify-content: flex-end; 44 | } 45 | } 46 | } 47 | .message-tip{ 48 | position: fixed; 49 | right: 50rpx; 50 | bottom: 10%; 51 | .size(190rpx, 190rpx); 52 | image{ 53 | .size(100%, auto); 54 | } 55 | .message-tip-text{ 56 | position: absolute; 57 | top: 0; 58 | left: 0; 59 | .size(100%, 140rpx); 60 | .color(#fff); 61 | .fs(22rpx); 62 | text-align: center; 63 | display: flex; 64 | flex-direction: column; 65 | justify-content: center; 66 | align-items: center; 67 | view{ 68 | display: flex; 69 | .lh(40rpx); 70 | view{ 71 | .fs(28rpx); 72 | position: relative; 73 | top: -.2em; 74 | font-weight: 700; 75 | .font-gradient(orange, #00a700, bottom); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /pages/edit-card/edit-card.js: -------------------------------------------------------------------------------- 1 | import WxValidate from '../../utils/WxValidate'; 2 | Page({ 3 | data: { 4 | basicInfo: { 5 | tel: '', 6 | post: '', 7 | weChat: '', 8 | specialPlane: '', 9 | email: '', 10 | intro: '' 11 | } 12 | }, 13 | onLoad() { 14 | this.initValidate() 15 | }, 16 | initValidate() { 17 | const rules = { 18 | tel: { 19 | required: true, 20 | tel: true, 21 | }, post: { 22 | required: true, 23 | }, weChat: { 24 | required: true, 25 | }, specialPlane: { 26 | required: true, 27 | }, email: { 28 | required: true, 29 | email: true 30 | } 31 | }; 32 | const messages = { 33 | tel: { 34 | required: '请输入手机号', 35 | tel: '请输入正确格式手机号', 36 | }, post: { 37 | required: '请输入职位', 38 | }, weChat: { 39 | required: '请输入微信号', 40 | }, specialPlane: { 41 | required: '请输入座机号', 42 | }, email: { 43 | required: '请输入电子邮箱', 44 | email: '请输入正确格式电子邮箱', 45 | } 46 | }; 47 | this.WxValidate = new WxValidate(rules, messages) 48 | }, 49 | formChange(val) { 50 | let obj = {} 51 | obj[`basicInfo.${val.currentTarget.dataset.val}`]= val.detail.value 52 | this.setData(obj) 53 | }, 54 | submitForm(e) { 55 | const params = e.detail.value 56 | if (!this.WxValidate.checkForm(params)) { 57 | const error = this.WxValidate.errorList[0] 58 | this.showModal(error) 59 | return false 60 | } 61 | }, 62 | showModal(error) { 63 | wx.showToast({ 64 | title: error.msg, 65 | icon: 'none', 66 | duration: 2000 67 | }) 68 | }, 69 | }) -------------------------------------------------------------------------------- /pages/goods/goods.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | nav-{{item + 1}} 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | {{item.title}} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | -------------------------------------------------------------------------------- /pages/login/login.js: -------------------------------------------------------------------------------- 1 | import WxValidate from '../../utils/WxValidate'; 2 | import LoginApi from '../../api/loginApi' 3 | Page({ 4 | data: { 5 | userInfo: { 6 | userName: '', 7 | password: '', 8 | } 9 | }, onLoad() { 10 | this.initValidate() 11 | }, initValidate() { 12 | const rules = { 13 | userName: { 14 | required: true, 15 | rangelength: [2, 20], 16 | }, 17 | password: { 18 | required: true, 19 | rangelength: [6, 16], 20 | } 21 | } 22 | const messages = { 23 | userName: { 24 | required: '请输入账号', 25 | rangelength: '请输入2~4位字符账号' 26 | }, 27 | password: { 28 | required: '请输入密码', 29 | rangelength: '请输入6~16位字符密码' 30 | }, 31 | 32 | } 33 | // 创建实例对象 34 | this.WxValidate = new WxValidate(rules, messages) 35 | /** 36 | * 也可以自定义验证规则 37 | */ 38 | // this.WxValidate.addMethod('assistance', (value, param) => { 39 | // return this.WxValidate.optional(value) || (value.length >= 1 && value.length <= 2) 40 | // }, '请勾选 《顺风男服务协议》') 41 | }, bindUserNameInput(e) { // 获取账号、赋值 42 | this.data.userInfo.userName = e.detail.value 43 | }, bindPasswordInput(e) { // 获取密码、赋值 44 | this.data.userInfo.password = e.detail.value 45 | }, login(params) { // 登录,暂存在本地存储 46 | LoginApi.login(params).then(res => { 47 | console.log('登录返回值', res) 48 | wx.setStorage({ 49 | key: "userInfo", 50 | data: JSON.stringify(res.data) 51 | }) 52 | console.log(res.data, res.data.token) 53 | wx.setStorage({ 54 | key: "token", 55 | data: res.data.token 56 | }) 57 | wx.switchTab({ 58 | url: '../home/home' 59 | }) 60 | }) 61 | }, submitForm(e) { 62 | /** 63 | * 表单提交 64 | */ 65 | const params = e.detail.value 66 | if (!this.WxValidate.checkForm(params)) { 67 | const error = this.WxValidate.errorList[0] 68 | this.showModal(error) 69 | return false 70 | } 71 | /** 72 | * 验证成功 73 | */ 74 | this.login(params); 75 | }, showModal(error) { 76 | wx.showToast({ 77 | title: error.msg, 78 | icon: 'none', 79 | duration: 2000 80 | }) 81 | }, tologin() { 82 | 83 | }, 84 | }) -------------------------------------------------------------------------------- /pages/message/message.wxss: -------------------------------------------------------------------------------- 1 | .message .message-item { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | border-bottom: 2rpx solid #f5f5f5; 6 | } 7 | .message .message-item .message-head { 8 | position: relative; 9 | } 10 | .message .message-item .message-head image { 11 | width: 100rpx; 12 | height: 100rpx; 13 | border-radius: 500rpx; 14 | box-shadow: 2rpx 6rpx 10rpx #ccc; 15 | } 16 | .message .message-item .message-head .unread { 17 | position: absolute; 18 | top: 5rpx; 19 | right: 20rpx; 20 | width: 20rpx; 21 | height: 20rpx; 22 | border-radius: 500rpx; 23 | background: #E70012; 24 | } 25 | .message .message-item .message-referral { 26 | flex: 1; 27 | width: 250rpx; 28 | } 29 | .message .message-item .message-referral .message-referral-1 { 30 | display: flex; 31 | justify-content: space-between; 32 | align-items: center; 33 | } 34 | .message .message-item .message-referral .message-referral-1 .message-referral-name { 35 | width: 310rpx; 36 | } 37 | .message .message-item .message-icon-right { 38 | width: 30rpx; 39 | display: flex; 40 | align-items: center; 41 | justify-content: flex-end; 42 | } 43 | .message-tip { 44 | position: fixed; 45 | right: 50rpx; 46 | bottom: 10%; 47 | width: 190rpx; 48 | height: 190rpx; 49 | } 50 | .message-tip image { 51 | width: 100%; 52 | height: auto; 53 | } 54 | .message-tip .message-tip-text { 55 | position: absolute; 56 | top: 0; 57 | left: 0; 58 | width: 100%; 59 | height: 140rpx; 60 | color: #fff; 61 | font-size: 22rpx; 62 | text-align: center; 63 | display: flex; 64 | flex-direction: column; 65 | justify-content: center; 66 | align-items: center; 67 | } 68 | .message-tip .message-tip-text view { 69 | display: flex; 70 | line-height: 40rpx; 71 | } 72 | .message-tip .message-tip-text view view { 73 | font-size: 28rpx; 74 | position: relative; 75 | top: -0.2em; 76 | font-weight: 700; 77 | background: linear-gradient(to bottom, orange, #00a700); 78 | -webkit-background-clip: text; 79 | color: transparent; 80 | -webkit-text-fill-color: transparent; 81 | text-fill-color: transparent; 82 | } 83 | -------------------------------------------------------------------------------- /components/tab-nav-roll/tab-nav-roll.js: -------------------------------------------------------------------------------- 1 | Component({ 2 | options: { 3 | addGlobalClass: true, // 4 | multipleSlots: true, // 在组建定义时的选项中启用多slot支持 5 | }, 6 | /** 7 | * 组件的属性列表 8 | */ 9 | properties: { 10 | tabData: { // 属性名 11 | type: Array, 12 | value: 'BBBBB' 13 | }, 14 | tabType: { 15 | type: String, 16 | value: '' 17 | } 18 | }, 19 | /** 20 | * 组件的初始数据 21 | */ 22 | data: { 23 | activeType: '', 24 | scrollLeft: '0', 25 | lineWidth: 20, 26 | eleLeft: 0, 27 | animationLine: {} 28 | }, 29 | pageLifetimes: { 30 | show() { 31 | this.data.activeType = this.properties.tabType 32 | }, 33 | }, 34 | created() { 35 | 36 | }, 37 | ready() { 38 | this.queryElement('.active') 39 | }, 40 | attached() { 41 | 42 | }, 43 | methods: { 44 | queryElement(ele, X) { 45 | let _this = this; 46 | let query = wx.createSelectorQuery().in(this); 47 | query.select(ele).boundingClientRect() 48 | query.exec(function (res) { 49 | console.log(res) 50 | _this.setData({ 51 | lineWidth: res[0].width, 52 | eleLeft: res[0].left 53 | }) 54 | _this._animationExport(X ? X : _this.data.eleLeft - 22) 55 | }) 56 | }, 57 | _animationExport(X) { 58 | console.log('X->', X) 59 | let animation = wx.createAnimation({ 60 | duration: 200, 61 | timingFunction: 'linear' 62 | }); 63 | animation.left(X).step(); 64 | this.setData({ 65 | animationLine: animation.export() 66 | }) 67 | console.log('animation->', this.data.animationLine) 68 | }, 69 | tabChange(e) { 70 | let itemData = e.currentTarget.dataset['item'] 71 | this.setData({ activeType: itemData.type }) 72 | let winWidth = wx.getSystemInfoSync().windowWidth 73 | console.log(e.currentTarget.dataset['index'] * (winWidth / 4) - (winWidth / 4)) 74 | this.setData({scrollLeft: `${e.currentTarget.dataset['index'] * (winWidth / 4) - (winWidth / 4)}`}) 75 | this.triggerEvent('increment', {itemData: itemData}) // 将num通过参数的形式传递给父组件 76 | this.queryElement('.active', e.currentTarget.dataset['index'] * (winWidth / 4) - (winWidth / 4)) 77 | } 78 | } 79 | }) 80 | -------------------------------------------------------------------------------- /utils/request.js: -------------------------------------------------------------------------------- 1 | let token = wx.getStorageSync('token') 2 | console.log('TOKEN', token) 3 | 4 | function networkpost(dataObj) { 5 | let promise = new Promise((resolve, reject) => { 6 | wx.request({ 7 | url: dataObj.url, 8 | header: { 9 | 'Content-Type': 'application/json', 10 | 'token': token 11 | }, 12 | data: dataObj.data, 13 | method: 'POST', 14 | success: function (res) { // 请求成功 15 | //自行处理返回结果 16 | console.log('返回结果:') 17 | console.log(res.data) 18 | // dataObj.app.netWorkData.result = res.data 19 | resolve(res.data); 20 | }, 21 | fail: function (res) { // 请求失败 22 | wx.showToast({ 23 | title: '网络错误,请稍后再试', 24 | icon: 'none', 25 | duration: 2000 26 | }) 27 | reject({ success: false }); 28 | }, 29 | }) 30 | }); 31 | return promise; 32 | } 33 | //get请求 34 | function networkget(dataObj) { 35 | let promise = new Promise((resolve, reject) => { 36 | wx.request({ 37 | url: dataObj.url, 38 | header: { 39 | 'Content-Type': 'application/json', 40 | 'token': token 41 | }, 42 | data: dataObj.params, 43 | method: 'GET', 44 | success: function (res) { 45 | if (res.statusCode == 200) { 46 | resolve({ bool: true }); 47 | } else { 48 | reject({ bool: false }); 49 | } 50 | //返回结果自行处理 51 | console.log('返回结果:') 52 | console.log(res.data) 53 | // dataObj.app.netWorkData.result = res.data 54 | }, 55 | fail: function (res) { // 请求失败 56 | wx.showToast({ 57 | title: '网络错误,请稍后再试', 58 | icon: 'none', 59 | duration: 2000 60 | }) 61 | reject({ bool: false }); 62 | }, 63 | }) 64 | }); 65 | return promise; 66 | } 67 | module.exports = { 68 | networkget, 69 | networkpost 70 | } -------------------------------------------------------------------------------- /js/common.js: -------------------------------------------------------------------------------- 1 | const VerifyFactory = function (type, str) { } 2 | VerifyFactory.prototype = { 3 | character: function (str, mixLength, maxLength) { // 任意字符-限制长度 4 | if(str.length < mixLength) { 5 | return {bool: false, msg: `最少输入${mixLength}位`}; 6 | } else if(str.length > maxLength) { 7 | return {bool: false, msg: `最多输入${maxLength}位`}; 8 | } else { 9 | return {bool: true, msg: ``}; 10 | } 11 | }, 12 | email: function (str) { // 邮箱 13 | return (function () { 14 | var reg = /^(\w)+(\.\w+)*@(\w)+((\.\w{2,3}){1,3})$/; 15 | return reg.test(str); 16 | })(str); 17 | }, 18 | phone: function (str) { // 手机号 19 | return (function (str) { 20 | var reg = /^1[3|4|5|7|8][0-9]{9}$/; 21 | return reg.test(str); 22 | })(str); 23 | }, 24 | certno: function (str) { // 身份证号 25 | return (function () { 26 | var reg = /(^\d{15}$)|(^\d{17}([0-9]|X)$)/; 27 | return reg.test(str); 28 | })(str); 29 | }, 30 | password: function (str) { // 6-16位:字母或者数字 31 | return (function () { 32 | if (str.length < 6) { 33 | return '请输入6-16位密码'; 34 | } else if (str.length > 16) { 35 | return '请输入6-16位密码'; 36 | } else { 37 | const reg = /^[a-zA-Z0-9]{6,16}$/; 38 | return reg.test(str) == true ? true : '请输入正确格式'; 39 | } 40 | })(str); 41 | }, 42 | confirmPwd: function (str1, str2) { // 确认密码 43 | return (function () { 44 | return (str1 == str2); 45 | })(str1, str2); 46 | }, 47 | code: function (user, curr) { // 图片验证码 48 | return (function (user, curr) { 49 | var curr = curr.toLowerCase(); 50 | var reg = /^[a-zA-Z]{4}$/; 51 | if (reg.test(user)) { // 验证码格式正确判断是否相符 52 | var usertest = user.toLowerCase(); 53 | return (usertest == curr) ? 2 : 1; 54 | } else { 55 | return 0; // 验证码格式不对 56 | } 57 | })(user, curr); 58 | }, 59 | dynamic: function (str) { // 动态验证码 -- 6位数字 60 | return (function () { 61 | var reg = /^[0-9]{6}$/; 62 | return reg.test(str); 63 | })(str); 64 | } 65 | } 66 | 67 | module.exports = { 68 | VerifyFactory: VerifyFactory 69 | } -------------------------------------------------------------------------------- /components/turntable/turntable.wxss: -------------------------------------------------------------------------------- 1 | /* components/zhuanpan/zhuanpan.wxss */ 2 | 3 | .canvas-container { 4 | margin: 0 auto; 5 | position: relative; 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | } 10 | 11 | .img-container { 12 | margin: 0 auto; 13 | position: absolute; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | left: 0; 18 | top: 0; 19 | z-index:10; 20 | } 21 | 22 | .gb-wheel-run { 23 | box-shadow: 0 0 5rpx 0rpx rgba(0, 0, 0, 0.98); 24 | width: 500rpx; 25 | height: 500rpx; 26 | border-radius: 50%; 27 | border: 30rpx solid #f1ecec; 28 | box-sizing: border-box; 29 | position: absolute; 30 | left: 27rpx; 31 | top: -19rpx; 32 | opacity: 0.7; 33 | } 34 | 35 | .gb-wheel-content { 36 | position: relative; 37 | margin: 0 auto; 38 | z-index: 2; 39 | width: 660rpx; 40 | height: 660rpx; 41 | border-radius: 50%; 42 | border: 20rpx solid #f1ecec; 43 | box-shadow: 0 0 5rpx 0rpx rgba(0, 0, 0, 0.98); 44 | opacity: 0.7; 45 | overflow: hidden; 46 | } 47 | 48 | .canvas-list { 49 | position: absolute; 50 | left: 0; 51 | top: 0; 52 | width: inherit; 53 | height: inherit; 54 | z-index: 8; 55 | } 56 | 57 | .canvas-item2 { 58 | position: absolute; 59 | left: 0px; 60 | top: 0; 61 | width: 660rpx; 62 | height: 328rpx; 63 | color: #e4370e; 64 | font-weight: bold; 65 | transform-origin: 330rpx 330rpx; 66 | overflow: hidden; 67 | } 68 | 69 | .canvas-item2-after { 70 | position: absolute; 71 | top: 0; 72 | left: 0; 73 | width: 330rpx; 74 | height: 330rpx; 75 | transform-origin: 330rpx 330rpx; 76 | opacity: 1; 77 | } 78 | 79 | .gb-wheel-list { 80 | position: absolute; 81 | left: 0; 82 | top: 0; 83 | width: 100%; 84 | height: 100%; 85 | z-index: 9; 86 | } 87 | 88 | .gb-wheel-item { 89 | position: absolute; 90 | left: 0; 91 | top: 0; 92 | width: 100%; 93 | height: 100%; 94 | color: #fff; 95 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.6); 96 | } 97 | 98 | .gb-wheel-icontent { 99 | position: relative; 100 | display: block; 101 | padding-top: 50rpx; 102 | margin: 0 auto; 103 | text-align: center; 104 | transform-origin: 50% 328rpx; 105 | } 106 | -------------------------------------------------------------------------------- /components/turntable/turntable.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{item.name}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /pages/message/message.js: -------------------------------------------------------------------------------- 1 | import {timeCycle} from '../../utils/util' 2 | Page({ 3 | data: { 4 | messageList: [ 5 | {createTime: '2019-11-12 16:33'}, 6 | {createTime: '2019-11-12 14:55'}, 7 | ], 8 | pull: { 9 | isLoading: false, 10 | loading: '../../image/common/pull_refresh.gif', 11 | pullText: '正在加载' 12 | }, 13 | push: { 14 | isLoading: false, 15 | loading: '../../image/common/pull_refresh.gif', 16 | pullText: '-上拉加载更多-' 17 | }, 18 | slideStart: [], 19 | moveTime: 0, 20 | }, 21 | onLoad() { 22 | this.tranMessageList() 23 | }, 24 | tranMessageList() { 25 | let data = this.data.messageList.map(item => { 26 | item.date = timeCycle(item.createTime, '/'); 27 | return item; 28 | }) 29 | this.setData({ 30 | messageList: data 31 | }) 32 | }, 33 | refresh(e) { 34 | console.log('刷新', e) 35 | this.setData({ 36 | 'pull.isLoading': true, 37 | 'pull.loading': '../../image/common/pull_refresh.gif', 38 | 'pull.pullText': '正在加载', 39 | }) 40 | setTimeout(() => { 41 | this.setData({ 42 | 'pull.loading': '../../image/common/finish.png', 43 | 'pull.pullText': '刷新完成' 44 | }) 45 | this.tranMessageList() 46 | }, 4000) 47 | setTimeout(() => { 48 | this.setData({ 49 | 'pull.isLoading': false, 50 | }) 51 | console.log('+++++ 刷新完成 +++++') 52 | }, 6000) 53 | }, 54 | toload(e) { 55 | console.log('加载', e), 56 | this.setData({ 57 | 'push.isLoading': true, 58 | 'push.pullText': '正在加载', 59 | 'push.loading': '../../image/common/pull_refresh.gif', 60 | }) 61 | if (this.data.messageList.length < 30) { 62 | setTimeout(() => { 63 | let data = this.data.messageList.concat([ 64 | {createTime: '2019-11-12 16:33'}, 65 | {createTime: '2019-11-12 14:55'}, 66 | ]) 67 | this.setData({ 68 | messageList: data, 69 | 'push.isLoading': false, 70 | 'push.pullText': '- 上拉加载更多 -', 71 | 'push.loading': '../../image/common/finish.png', 72 | }) 73 | this.tranMessageList() 74 | console.log('===== 加载完成 =====') 75 | }, 2000) 76 | } 77 | }, 78 | /**跳转客户详情 */ 79 | toCustomerDetails() { 80 | 81 | } 82 | }) -------------------------------------------------------------------------------- /pages/client-pool/client-pool.wxss: -------------------------------------------------------------------------------- 1 | .client-pool { 2 | position: relative; 3 | flex: 1; 4 | } 5 | .client-pool-search { 6 | position: fixed; 7 | top: 0; 8 | left: 0; 9 | width: 100%; 10 | box-sizing: border-box; 11 | background: #fff; 12 | z-index: 99; 13 | } 14 | .client-pool-search-body { 15 | display: flex; 16 | align-items: center; 17 | height: 70rpx; 18 | background: #f5f5f5; 19 | } 20 | 21 | .client-pool-search-body input { 22 | flex: 1; 23 | } 24 | 25 | .client-pool-search-condition { 26 | display: flex; 27 | justify-content: space-between; 28 | align-items: center; 29 | border-bottom: 2rpx solid #f5f5f5; 30 | } 31 | 32 | .client-pool-search-condition-left { 33 | display: flex; 34 | } 35 | 36 | .select-black { 37 | width: 24rpx; 38 | height: 12rpx; 39 | } 40 | 41 | .praise-view { 42 | display: flex; 43 | justify-content: center; 44 | align-items: center; 45 | width: 100rpx; 46 | height: 100rpx; 47 | } 48 | 49 | .praise { 50 | width: 100rpx; 51 | height: 100rpx; 52 | } 53 | 54 | .praise-mini { 55 | width: 40rpx; 56 | height: 35rpx; 57 | } 58 | 59 | .client-pool-list { 60 | position: absolute; 61 | top: 0rpx; 62 | left: 0; 63 | right: 0; 64 | bottom: 0; 65 | } 66 | 67 | .scroll-view { 68 | position: absolute; 69 | box-sizing: border-box; 70 | } 71 | .placeholder{ 72 | height: 180rpx; 73 | width: 100%; 74 | } 75 | .client-pool-list-item { 76 | position: relative; 77 | width: 100%; 78 | padding-right: 130rpx; 79 | display: flex; 80 | align-items: center; 81 | border-bottom: 2rpx solid #f5f5f5; 82 | box-sizing: border-box; 83 | } 84 | 85 | .client-pool-list-item-img { 86 | width: 100rpx; 87 | } 88 | 89 | .client-pool-list-item-img image { 90 | width: 100rpx; 91 | height: 100rpx; 92 | border-radius: 500rpx; 93 | border: 4rpx solid #fff; 94 | box-shadow: 2rpx 10rpx 20rpx #ccc; 95 | } 96 | 97 | .client-pool-list-item-info { 98 | flex: 1; 99 | width: 250rpx; 100 | } 101 | 102 | .client-pool-list-item-info-data { 103 | display: flex; 104 | } 105 | 106 | .client-pool-list-item-info-time { 107 | width: 200rpx; 108 | } 109 | 110 | .client-pool-list-item-info-source { 111 | width: 220rpx; 112 | } 113 | 114 | .client-pool-list-item-status { 115 | position: absolute; 116 | right: 0; 117 | top: 0; 118 | bottom: 0; 119 | width: 130rpx; 120 | display: flex; 121 | align-items: center; 122 | justify-content: flex-end; 123 | } 124 | 125 | .client-pool-list-item-status>.status { 126 | background: #E70012; 127 | border-radius: 500rpx; 128 | } 129 | 130 | .pull-refresh { 131 | height: 140rpx; 132 | display: flex; 133 | justify-content: center; 134 | align-items: center; 135 | transition: all .5s ease-in-out; 136 | overflow: hidden; 137 | } 138 | 139 | .chu { 140 | height: 110rpx; 141 | } 142 | 143 | .jin { 144 | height: 0rpx; 145 | } -------------------------------------------------------------------------------- /pages/home/home.js: -------------------------------------------------------------------------------- 1 | import util from '../../utils/util' 2 | import {cluesType} from '../../utils/publicData' 3 | import {toDescribe} from '../../utils/util' 4 | Page({ 5 | data: { 6 | triggerNumber: [ 7 | {title: '客户总量', num: '2312'}, 8 | {title: '名片转发数', num: '32'}, 9 | {title: '转介绍浏览人数', num: '2'}, 10 | {title: '邀请新人数', num: '435'}, 11 | ], 12 | tabData: cluesType, 13 | tabType: 'page_businesscard', 14 | clueData: [ 15 | {createTime: '2019-11-12 16:33'}, 16 | {createTime: '2019-11-12 14:55'} 17 | ], 18 | pull: { 19 | isLoading: false, 20 | loading: '../../image/common/pull_refresh.gif', 21 | pullText: '正在加载' 22 | }, 23 | push: { 24 | isLoading: false, 25 | loading: '../../image/common/pull_refresh.gif', 26 | pullText: '-上拉加载更多-' 27 | }, 28 | }, 29 | homeTabChange(e) { 30 | this.setData({ tabType: e.detail.itemData.type }) 31 | }, 32 | time() { 33 | let newData = this.data.clueData.map(item => { 34 | item.time = util.timeCycle(item.createTime) 35 | return item 36 | }) 37 | this.setData({ clueData: newData}) 38 | }, 39 | toEditCard() { 40 | wx.navigateTo({ 41 | url: '/pages/edit-card/edit-card' 42 | }) 43 | }, 44 | refresh(e) { 45 | console.log('刷新', e) 46 | this.setData({ 47 | 'pull.isLoading': true, 48 | 'pull.loading': '../../image/common/pull_refresh.gif', 49 | 'pull.pullText': '正在加载', 50 | }) 51 | setTimeout(() => { 52 | this.setData({ 53 | 'pull.loading': '../../image/common/finish.png', 54 | 'pull.pullText': '刷新完成' 55 | }) 56 | }, 4000) 57 | setTimeout(() => { 58 | this.setData({ 59 | 'pull.isLoading': false, 60 | }) 61 | console.log('+++++ 刷新完成 +++++') 62 | }, 6000) 63 | }, 64 | toload(e) { 65 | console.log('加载', e), 66 | this.setData({ 67 | 'push.isLoading': true, 68 | 'push.pullText': '正在加载', 69 | 'push.loading': '../../image/common/pull_refresh.gif', 70 | }) 71 | if (this.data.clueData.length < 30) { 72 | setTimeout(() => { 73 | let data = this.data.clueData.concat([ 74 | {createTime: '2019-11-12 16:33'}, 75 | {createTime: '2019-11-12 14:55'}, 76 | ]) 77 | this.setData({ 78 | clueData: data, 79 | 'push.isLoading': false, 80 | 'push.pullText': '- 上拉加载更多 -', 81 | 'push.loading': '../../image/common/finish.png', 82 | }) 83 | console.log('===== 加载完成 =====') 84 | }, 2000) 85 | } 86 | }, 87 | /**跳转客户详情 */ 88 | toCustomerDetails() { 89 | 90 | }, 91 | click() { 92 | this.selectComponent('#login_authorization').showModal() 93 | }, 94 | onShow() { 95 | this.time() 96 | } 97 | }) -------------------------------------------------------------------------------- /utils/publicData.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 来源 3 | */ 4 | const sourceData = [ 5 | { key: '', label: '全部' }, 6 | { key: 'search', label: '搜索' }, 7 | { key: 'scan_designer_card', label: '扫设计顾问名片' }, 8 | { key: 'scan_designer_ab', label: ' 扫设计顾问ab券活动码' }, 9 | { key: 'scan_openid_ab ', label: '扫用户ab券活动码' }, 10 | { key: 'share_imagetext ', label: '分享方案页面' }, 11 | { key: 'share_card_designer ', label: '分享设计顾问名片' }, 12 | { key: 'share_ab ', label: '分享ab券的活动页面' }, 13 | { key: 'share_other ', label: '分享其他页面' } 14 | ]; 15 | /** 16 | * 新旧用户 17 | */ 18 | const cateData = [ 19 | {key: '', label: '全部'}, 20 | {key: '0', label: '新用户'}, 21 | {key: '1', label: '有联系方式'}, 22 | ]; 23 | /** 24 | * 线索类型 25 | */ 26 | const cluesType = [ 27 | {name: '全部', type: ''}, 28 | {name: '查看名片', type: 'page_businesscard'}, 29 | {name: '复制微信', type: 'btn_businesscard_copywechat'}, 30 | {name: '保存电话', type: 'btn_businesscard_savephonenumber'}, 31 | {name: '收藏方案', type: 'btn_plan_like'}, 32 | {name: '找你设计', type: 'btn_plan_design'}, 33 | {name: '拨打手机', type: 'btn_businesscard_mobilephone'}, 34 | {name: '拨打座机', type: 'btn_businesscard_telephone'}, 35 | {name: '复制邮箱', type: 'btn_businesscard_copyemail'}, 36 | {name: '分享方案', type: 'btn_planlist_share'}, 37 | {name: '分享名片', type: 'btn_businesscard_sharecard'}, 38 | {name: 'AB券转发', type: 'btn_invitedgift_invite'}, 39 | ]; 40 | /** 41 | * 商品列表 42 | */ 43 | const goodsList = [ 44 | {title: '单人沙发', like: 1, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/EAD670176 D1882/common/SM_IMAGE/SM_001.jpg'}, 45 | {title: '双人沙发', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/11M9007U212301/common/SM_IMAGE/SM_001.jpg?x-oss-process=image/resize,m_pad,h_500,w_500,color_FFFFFF'}, 46 | {title: '早安床头柜', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/CACLA-016-063/common/SM_IMAGE/SM_001.jpg'}, 47 | {title: '单人沙发', like: 1, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/EAD670176 D1882/common/SM_IMAGE/SM_001.jpg'}, 48 | {title: '双人沙发', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/11M9007U212301/common/SM_IMAGE/SM_001.jpg?x-oss-process=image/resize,m_pad,h_500,w_500,color_FFFFFF'}, 49 | {title: '早安床头柜', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/CACLA-016-063/common/SM_IMAGE/SM_001.jpg'}, 50 | {title: '单人沙发', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/EAD670176 D1882/common/SM_IMAGE/SM_001.jpg'}, 51 | {title: '双人沙发', like: 1, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/11M9007U212301/common/SM_IMAGE/SM_001.jpg?x-oss-process=image/resize,m_pad,h_500,w_500,color_FFFFFF'}, 52 | {title: '早安床头柜', like: 0, goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/CACLA-016-063/common/SM_IMAGE/SM_001.jpg'} 53 | ]; 54 | 55 | module.exports = { 56 | sourceData, 57 | cateData, 58 | cluesType, 59 | goodsList 60 | }; -------------------------------------------------------------------------------- /utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | const timeCycle = (d, sign1 = '-') => { 18 | const time = d.replace(/\-/g, '/'); 19 | const date = new Date(time); 20 | const nowDate = new Date(); 21 | const dateTime = date.getTime(); 22 | const nowDateTime = nowDate.getTime(); 23 | const year = date.getFullYear() 24 | const month = date.getMonth() + 1 25 | const day = date.getDate() 26 | const hour = date.getHours() 27 | const minute = date.getMinutes() 28 | const second = date.getSeconds() 29 | if (nowDateTime - dateTime < 300000) { 30 | return '刚刚' 31 | } else if (nowDateTime - dateTime < 86400000) { 32 | return `${hour}:${minute}` 33 | } else if (nowDateTime - dateTime < 2592000000) { 34 | return `${month}${sign1}${day} ${hour}:${minute}` 35 | } else { 36 | return `${year}${sign1}${month}${sign1}${day} ${hour}:${minute}` 37 | } 38 | } 39 | /**转换时间为多久前 */ 40 | const howLongAgo = d => { 41 | const time = d.replace(/\-/g, '/') 42 | const date = new Date(time); 43 | const nowDate = new Date(); 44 | const oldTimestamp = date.getTime(); 45 | const nowTimestamp = nowDate.getTime(); 46 | const minute = 60 * 1000; // 1分钟 47 | const hour = 60 * minute; // 1小时 48 | const day = 24 * hour; // 1天 49 | const month = 31 * day; // 月 50 | const year = 12 * month; // 年 51 | const timeDiff = nowTimestamp - oldTimestamp; 52 | let r = 0; 53 | if (timeDiff > year) { 54 | r = (timeDiff / year); 55 | return r.toFixed(0) + "年前"; 56 | } 57 | if (timeDiff > month) { 58 | r = (timeDiff / month); 59 | return r.toFixed(0) + "个月前"; 60 | } 61 | if (timeDiff > day) { 62 | r = (timeDiff / day); 63 | return r.toFixed(0) + "天前"; 64 | } 65 | if (timeDiff > hour) { 66 | r = (timeDiff / hour); 67 | return r.toFixed(0) + "小时前"; 68 | } 69 | if (timeDiff > minute) { 70 | r = (timeDiff / minute); 71 | return r.toFixed(0) + "分钟前"; 72 | } 73 | return "刚刚"; 74 | } 75 | /** 76 | * 数组对象过滤 77 | * @param {array} array 需要转换的数组对象 78 | * @param {code} code 要转换的值 79 | * @param {key} key 判断的属性 80 | * @param {value} value 返回的属性 81 | */ 82 | const toDescribe = (array = [], code = "", key = "", value = "") => { 83 | for (let i = 0; i <= array.length; i++) { 84 | if (array[i]) { 85 | if (array[i][key] === code) { 86 | return array[i][value] 87 | } 88 | } 89 | } 90 | } 91 | 92 | /** 93 | * oss路径拼接 94 | * @url 需要拼接的路径 95 | */ 96 | const ossImgShow1 = (url) => { 97 | return 'https://mkmarketing-oss.markorhome.com/' + url + "?x-oss-process=style/mk_sm&r=" + new Date().getTime(); 98 | } 99 | 100 | module.exports = { 101 | formatTime: formatTime, 102 | formatNumber: formatNumber, 103 | timeCycle: timeCycle, 104 | howLongAgo: howLongAgo, 105 | toDescribe: toDescribe, 106 | ossImgShow1: ossImgShow1 107 | } 108 | -------------------------------------------------------------------------------- /assets/less/goods/goods.less: -------------------------------------------------------------------------------- 1 | @import "../style.less"; 2 | .goods-container{ 3 | display: flex; 4 | .goods-nav{ 5 | position: absolute; 6 | left: 0; 7 | right: 150rpx; 8 | top: 0; 9 | bottom: 0; 10 | .size(150rpx, 100%); 11 | border-right: 2rpx solid #eee; 12 | .goods-nav-item{ 13 | .lh(3em); 14 | .fs(26rpx); 15 | .color(#999); 16 | display: flex; 17 | .goods-nav-item-left{ 18 | .size(10rpx, 3em); 19 | } 20 | } 21 | .goods-nav-item-active{ 22 | .goods-nav-item-left{ 23 | .bg-gradient(#ddbf93, #b08351); 24 | } 25 | .bg(rgba(176, 131, 81, .5)); 26 | .color(#fff); 27 | } 28 | } 29 | .goods { 30 | flex: 1; 31 | display: flex; 32 | flex-wrap: wrap; 33 | position: absolute; 34 | top: 0; 35 | bottom: 0; 36 | right: 0; 37 | left: 150rpx; 38 | .scroll-view { 39 | .goods-item { 40 | width: 50%; 41 | display: inline-block; 42 | box-sizing: border-box; 43 | .goods-item-img{ 44 | display: flex; 45 | justify-content: center; 46 | .goods-img { 47 | .size(95%, auto); 48 | } 49 | } 50 | .goods-shop { 51 | display: flex; 52 | justify-content: space-between; 53 | align-items: center; 54 | .shop-card { 55 | .size(60rpx, 60rpx) 56 | } 57 | .red{ 58 | .color(red); 59 | } 60 | } 61 | } 62 | } 63 | } 64 | .bus { 65 | width: 100rpx; 66 | height: 100rpx; 67 | position: fixed; 68 | left: 80%; 69 | top: 80%; 70 | background: rgba(120, 188, 255, 0.6); 71 | border: 1rpx solid rgba(0, 116, 255, 0.61); 72 | border-radius: 50%; 73 | image { 74 | width: 80rpx; 75 | height: 80rpx; 76 | position: absolute; 77 | left: 50%; 78 | top: 50%; 79 | transform: translate(-50%, -50%); 80 | } 81 | .count { 82 | display: block; 83 | height: 40rpx; 84 | line-height: 40rpx; 85 | font-size: 24rpx; 86 | background: #ff4611; 87 | padding: 0 12rpx; 88 | border-radius: 20rpx; 89 | color: #fff; 90 | position: absolute; 91 | left: 68rpx; 92 | top: 0; 93 | } 94 | } 95 | .scale { 96 | background: rgba(120, 188, 255, 0.3); 97 | border: 1rpx solid rgba(0, 116, 255, 0.4); 98 | image { 99 | transform: scale(1.2); 100 | } 101 | } 102 | .good_box { 103 | width: 80rpx; 104 | height: 80rpx; 105 | position: fixed; 106 | border-radius: 50%; 107 | overflow: hidden; 108 | left: 50%; 109 | top: 50%; 110 | z-index: +99; 111 | border: 2rpx solid rgba(0, 116, 255, 0.61); 112 | background: rgba(120, 188, 255, 0.2); 113 | image { 114 | display: block; 115 | width: 100%; 116 | height: 100%; 117 | } 118 | } 119 | .goods_hover { 120 | transform: scale(0.95); 121 | } 122 | } 123 | 124 | @keyframes mymove { 125 | 0% { 126 | transform: rotate(50deg); 127 | } 128 | 25% { 129 | transform: rotate(100deg); 130 | } 131 | 50% { 132 | transform: rotate(150deg); 133 | } 134 | 75% { 135 | transform: rotate(200deg); 136 | } 137 | 100% { 138 | transform: rotate(360deg); 139 | } 140 | } -------------------------------------------------------------------------------- /pages/goods/goods.wxss: -------------------------------------------------------------------------------- 1 | .goods-container { 2 | display: flex; 3 | } 4 | .goods-container .goods-nav { 5 | position: absolute; 6 | left: 0; 7 | right: 150rpx; 8 | top: 0; 9 | bottom: 0; 10 | width: 150rpx; 11 | height: 100%; 12 | border-right: 2rpx solid #eee; 13 | } 14 | .goods-container .goods-nav .goods-nav-item { 15 | line-height: 3em; 16 | font-size: 26rpx; 17 | color: #999; 18 | display: flex; 19 | } 20 | .goods-container .goods-nav .goods-nav-item .goods-nav-item-left { 21 | width: 10rpx; 22 | height: 3em; 23 | } 24 | .goods-container .goods-nav .goods-nav-item-active { 25 | background: rgba(176, 131, 81, 0.5); 26 | color: #fff; 27 | } 28 | .goods-container .goods-nav .goods-nav-item-active .goods-nav-item-left { 29 | background: linear-gradient(to right, #ddbf93, #b08351); 30 | } 31 | .goods-container .goods { 32 | flex: 1; 33 | display: flex; 34 | flex-wrap: wrap; 35 | position: absolute; 36 | top: 0; 37 | bottom: 0; 38 | right: 0; 39 | left: 150rpx; 40 | } 41 | .goods-container .goods .scroll-view .goods-item { 42 | width: 50%; 43 | display: inline-block; 44 | box-sizing: border-box; 45 | } 46 | .goods-container .goods .scroll-view .goods-item .goods-item-img { 47 | display: flex; 48 | justify-content: center; 49 | } 50 | .goods-container .goods .scroll-view .goods-item .goods-item-img .goods-img { 51 | width: 95%; 52 | height: auto; 53 | } 54 | .goods-container .goods .scroll-view .goods-item .goods-shop { 55 | display: flex; 56 | justify-content: space-between; 57 | align-items: center; 58 | } 59 | .goods-container .goods .scroll-view .goods-item .goods-shop .shop-card { 60 | width: 60rpx; 61 | height: 60rpx; 62 | } 63 | .goods-container .goods .scroll-view .goods-item .goods-shop .red { 64 | color: red; 65 | } 66 | .goods-container .bus { 67 | width: 100rpx; 68 | height: 100rpx; 69 | position: fixed; 70 | left: 80%; 71 | top: 80%; 72 | background: rgba(120, 188, 255, 0.6); 73 | border: 1rpx solid rgba(0, 116, 255, 0.61); 74 | border-radius: 50%; 75 | } 76 | .goods-container .bus image { 77 | width: 80rpx; 78 | height: 80rpx; 79 | position: absolute; 80 | left: 50%; 81 | top: 50%; 82 | transform: translate(-50%, -50%); 83 | } 84 | .goods-container .bus .count { 85 | display: block; 86 | height: 40rpx; 87 | line-height: 40rpx; 88 | font-size: 24rpx; 89 | background: #ff4611; 90 | padding: 0 12rpx; 91 | border-radius: 20rpx; 92 | color: #fff; 93 | position: absolute; 94 | left: 68rpx; 95 | top: 0; 96 | } 97 | .goods-container .scale { 98 | background: rgba(120, 188, 255, 0.3); 99 | border: 1rpx solid rgba(0, 116, 255, 0.4); 100 | } 101 | .goods-container .scale image { 102 | transform: scale(1.2); 103 | } 104 | .goods-container .good_box { 105 | width: 80rpx; 106 | height: 80rpx; 107 | position: fixed; 108 | border-radius: 50%; 109 | overflow: hidden; 110 | left: 50%; 111 | top: 50%; 112 | z-index: 99; 113 | border: 2rpx solid rgba(0, 116, 255, 0.61); 114 | background: rgba(120, 188, 255, 0.2); 115 | } 116 | .goods-container .good_box image { 117 | display: block; 118 | width: 100%; 119 | height: 100%; 120 | } 121 | .goods-container .goods_hover { 122 | transform: scale(0.95); 123 | } 124 | @keyframes mymove { 125 | 0% { 126 | transform: rotate(50deg); 127 | } 128 | 25% { 129 | transform: rotate(100deg); 130 | } 131 | 50% { 132 | transform: rotate(150deg); 133 | } 134 | 75% { 135 | transform: rotate(200deg); 136 | } 137 | 100% { 138 | transform: rotate(360deg); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /pages/home/home.wxss: -------------------------------------------------------------------------------- 1 | .home-container { 2 | position: absolute; 3 | top: 0; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | background: #f5f5f5 url('https://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/NameCard/source/image/sales_banner.jpg') no-repeat; 8 | background-size: 100% auto; 9 | overflow: hidden; 10 | } 11 | 12 | .home { 13 | /* height: 200rpx; */ 14 | display: flex; 15 | flex-direction: column; 16 | } 17 | 18 | .home-header { 19 | width: 100%; 20 | height: 350rpx; 21 | } 22 | 23 | .home-header-item { 24 | width: 90%; 25 | height: 320rpx; 26 | margin-top: 40rpx; 27 | background: #fff; 28 | border-radius: 10rpx; 29 | box-sizing: border-box; 30 | box-shadow: 2rpx 10rpx 20rpx #ccc; 31 | } 32 | 33 | .user-info { 34 | position: relative; 35 | display: flex; 36 | } 37 | 38 | .user-info-head { 39 | box-sizing: border-box; 40 | } 41 | 42 | .user-info-head image { 43 | width: 130rpx; 44 | height: 130rpx; 45 | border-radius: 500rpx; 46 | border: 4rpx solid #fff; 47 | box-shadow: 2rpx 10rpx 20rpx #ccc; 48 | } 49 | 50 | .user-name { 51 | line-height: 80rpx; 52 | } 53 | 54 | .user-post { 55 | line-height: 40rpx; 56 | -webkit-background-clip: text; 57 | -webkit-text-fill-color: transparent; 58 | background-image: linear-gradient(90deg, #ddbf93, #b08351); 59 | } 60 | 61 | .edit-info { 62 | width: 150rpx; 63 | height: 50rpx; 64 | position: absolute; 65 | top: -30rpx; 66 | right: -30rpx; 67 | } 68 | 69 | .trigger-number { 70 | display: flex; 71 | border-top: 2rpx solid #eee; 72 | } 73 | 74 | .trigger-number-item { 75 | flex: 1; 76 | } 77 | 78 | .home-shortcut { 79 | display: flex; 80 | } 81 | 82 | .home-shortcut-item { 83 | flex: 1; 84 | } 85 | 86 | .home-shortcut-item image { 87 | width: 100%; 88 | height: 110rpx; 89 | } 90 | 91 | .home-clue-nav { 92 | position: relative; 93 | border-bottom: 2rpx solid #ccc; 94 | } 95 | 96 | .scroll-view { 97 | position: absolute; 98 | top: 570rpx; 99 | bottom: 0; 100 | width: 100%; 101 | flex: 1; 102 | } 103 | 104 | .home-clue-list-item { 105 | display: flex; 106 | background: #fff; 107 | border-radius: 10rpx; 108 | box-shadow: 2rpx 10rpx 20rpx #eee; 109 | } 110 | 111 | .home-clue-list-item-img image { 112 | width: 100rpx; 113 | height: 100rpx; 114 | border-radius: 500rpx; 115 | border: 3rpx solid #fff; 116 | box-shadow: 2rpx 10rpx 20rpx #eee; 117 | box-sizing: border-box; 118 | } 119 | 120 | .home-clue-list-item-info { 121 | position: relative; 122 | flex: 1; 123 | } 124 | 125 | .icon-right { 126 | position: absolute; 127 | top: 50%; 128 | right: 10rpx; 129 | transform: translateY(-50%); 130 | width: 15rpx; 131 | height: 30rpx; 132 | } 133 | 134 | .home-clue-list-item-info-msg { 135 | line-height: 2em; 136 | } 137 | 138 | .shishi-bg { 139 | width: 100%; 140 | height: 400rpx; 141 | position: relative; 142 | } 143 | 144 | .shishi-bg::after { 145 | content: ''; 146 | width: 120%; 147 | height: 300rpx; 148 | position: absolute; 149 | left: 50%; 150 | top: 0; 151 | transform: translateX(-50%); 152 | border-radius: 0 0 20% 20%; 153 | background: rgb(116, 116, 255); 154 | } 155 | 156 | .shishi-bg-li { 157 | position: absolute; 158 | top: 50rpx; 159 | left: 50%; 160 | transform: translateX(-50%); 161 | width: 85%; 162 | height: 350rpx; 163 | background: blue; 164 | border-radius: 30rpx; 165 | z-index: 999; 166 | } -------------------------------------------------------------------------------- /pages/edit-card/edit-card.wxml: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 7 | 基本信息 8 | 9 | 手机 10 | 11 | 12 | 职位 13 | 14 | 15 | 微信 16 | 17 | 18 | 座机 19 | 20 | 21 | 邮箱 22 | 23 | 24 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 |
-------------------------------------------------------------------------------- /pages/home/home.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 17 | 18 | {{item.num}} 19 | 20 | 21 | {{item.title}} 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | {{item.time}} 46 | 47 | 48 | 49 | 50 | 51 | 52 | 客户名 53 | 查看了你的名片,沟通从此刻开始。 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch () { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | this.screenSize(); 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 25 | // 所以此处加入 callback 以防止这种情况 26 | if (this.userInfoReadyCallback) { 27 | this.userInfoReadyCallback(res) 28 | } 29 | } 30 | }) 31 | } 32 | } 33 | }), 34 | wx.getStorage({ 35 | key: 'userInfo', 36 | success: (res) => { 37 | if (res.data) { 38 | this.globalData.userInfo = res.data 39 | this.globalData.hasUserInfo = true 40 | } 41 | } 42 | }) 43 | }, 44 | screenSize () { 45 | var that = this; 46 | // 获取屏幕宽高 47 | wx.getSystemInfo({ 48 | success(res) { 49 | var ww = res.windowWidth; 50 | var hh = res.windowHeight; 51 | that.globalData.ww = ww; 52 | that.globalData.hh = hh; 53 | } 54 | }) 55 | }, 56 | bezier (points, times) { 57 | // 0、以3个控制点为例,点A,B,C,AB上设置点D,BC上设置点E,DE连线上设置点F,则最终的贝塞尔曲线是点F的坐标轨迹。 58 | // 1、计算相邻控制点间距。 59 | // 2、根据完成时间,计算每次执行时D在AB方向上移动的距离,E在BC方向上移动的距离。 60 | // 3、时间每递增100ms,则D,E在指定方向上发生位移, F在DE上的位移则可通过AD/AB = DF/DE得出。 61 | // 4、根据DE的正余弦值和DE的值计算出F的坐标。 62 | // 邻控制AB点间距 63 | var bezier_points = []; 64 | var points_D = []; 65 | var points_E = []; 66 | const DIST_AB = Math.sqrt(Math.pow(points[1]['x'] - points[0]['x'], 2) + Math.pow(points[1]['y'] - points[0]['y'], 2)); 67 | // 邻控制BC点间距 68 | const DIST_BC = Math.sqrt(Math.pow(points[2]['x'] - points[1]['x'], 2) + Math.pow(points[2]['y'] - points[1]['y'], 2)); 69 | // D每次在AB方向上移动的距离 70 | const EACH_MOVE_AD = DIST_AB / times; 71 | // E每次在BC方向上移动的距离 72 | const EACH_MOVE_BE = DIST_BC / times; 73 | // 点AB的正切 74 | const TAN_AB = (points[1]['y'] - points[0]['y']) / (points[1]['x'] - points[0]['x']); 75 | // 点BC的正切 76 | const TAN_BC = (points[2]['y'] - points[1]['y']) / (points[2]['x'] - points[1]['x']); 77 | // 点AB的弧度值 78 | const RADIUS_AB = Math.atan(TAN_AB); 79 | // 点BC的弧度值 80 | const RADIUS_BC = Math.atan(TAN_BC); 81 | // 每次执行 82 | for (var i = 1; i <= times; i++) { 83 | // AD的距离 84 | var dist_AD = EACH_MOVE_AD * i; 85 | // BE的距离 86 | var dist_BE = EACH_MOVE_BE * i; 87 | // D点的坐标 88 | var point_D = {}; 89 | point_D['x'] = dist_AD * Math.cos(RADIUS_AB) + points[0]['x']; 90 | point_D['y'] = dist_AD * Math.sin(RADIUS_AB) + points[0]['y']; 91 | points_D.push(point_D); 92 | // E点的坐标 93 | var point_E = {}; 94 | point_E['x'] = dist_BE * Math.cos(RADIUS_BC) + points[1]['x']; 95 | point_E['y'] = dist_BE * Math.sin(RADIUS_BC) + points[1]['y']; 96 | points_E.push(point_E); 97 | // 此时线段DE的正切值 98 | var tan_DE = (point_E['y'] - point_D['y']) / (point_E['x'] - point_D['x']); 99 | // tan_DE的弧度值 100 | var radius_DE = Math.atan(tan_DE); 101 | // 地市DE的间距 102 | var dist_DE = Math.sqrt(Math.pow((point_E['x'] - point_D['x']), 2) + Math.pow((point_E['y'] - point_D['y']), 2)); 103 | // 此时DF的距离 104 | var dist_DF = (dist_AD / DIST_AB) * dist_DE; 105 | // 此时DF点的坐标 106 | var point_F = {}; 107 | point_F['x'] = dist_DF * Math.cos(radius_DE) + point_D['x']; 108 | point_F['y'] = dist_DF * Math.sin(radius_DE) + point_D['y']; 109 | bezier_points.push(point_F); 110 | } 111 | return { 112 | 'bezier_points': bezier_points 113 | }; 114 | }, 115 | globalData: { 116 | userInfo: null, 117 | hasUserInfo: false 118 | } 119 | }) -------------------------------------------------------------------------------- /pages/client-pool/client-pool.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 来源 25 | 26 | 31 | 32 | 33 | 34 | 35 | 分类 36 | 37 | 38 | 39 | 40 | 41 | 共108名顾客 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | {{pull.pullText}} 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | wang... 58 | 59 | {{item.date}}活跃 60 | 来源: 你是扫码进来的吗 61 | 62 | 63 | 64 | New 65 | 手机号 66 | 67 | 68 | 69 | 70 | 71 | 72 | {{push.pullText}} 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | @import "./assets/wxss/icon.wxss"; 3 | page { 4 | height: 100%; 5 | /* background-color:rgb(220, 253, 171); */ 6 | } 7 | 8 | .container { 9 | width: 100%; 10 | height: 100%; 11 | display: flex; 12 | flex-direction: column; 13 | /* align-items: center; */ 14 | /* justify-content: space-sbetween; */ 15 | /* padding: 200rpx 0; */ 16 | box-sizing: border-box; 17 | } 18 | 19 | .fs16 { 20 | font-size: 16rpx; 21 | } 22 | 23 | .fs20 { 24 | font-size: 20rpx; 25 | } 26 | 27 | .fs22 { 28 | font-size: 22rpx; 29 | } 30 | 31 | .fs24 { 32 | font-size: 24rpx; 33 | } 34 | 35 | .fs26 { 36 | font-size: 26rpx; 37 | } 38 | 39 | .fs28 { 40 | font-size: 28rpx; 41 | } 42 | 43 | .fs30 { 44 | font-size: 30rpx; 45 | } 46 | 47 | .fs32 { 48 | font-size: 32rpx; 49 | } 50 | 51 | .fs34 { 52 | font-size: 34rpx; 53 | } 54 | 55 | .fs36 { 56 | font-size: 36rpx; 57 | } 58 | 59 | .fs38 { 60 | font-size: 38rpx; 61 | } 62 | 63 | .fs40 { 64 | font-size: 40rpx; 65 | } 66 | 67 | .f-color-fff { 68 | color: #fff; 69 | } 70 | 71 | .f-color-ccc { 72 | color: #ccc; 73 | } 74 | 75 | .f-color-666 { 76 | color: #666; 77 | } 78 | 79 | .f-color-999 { 80 | color: #999; 81 | } 82 | 83 | .f-color-f5 { 84 | color: #f5f5f5; 85 | } 86 | 87 | .f-color-main { 88 | color: #b08351; 89 | } 90 | 91 | .pt6 { 92 | padding-top: 6rpx; 93 | } 94 | 95 | .pr6 { 96 | padding-right: 6rpx; 97 | } 98 | 99 | .pb6 { 100 | padding-bottom: 6rpx; 101 | } 102 | 103 | .pl6 { 104 | padding-left: 6rpx; 105 | } 106 | 107 | .pt10 { 108 | padding-top: 10rpx; 109 | } 110 | 111 | .pr10 { 112 | padding-right: 10rpx; 113 | } 114 | 115 | .pb10 { 116 | padding-bottom: 10rpx; 117 | } 118 | 119 | .pl10 { 120 | padding-left: 10rpx; 121 | } 122 | 123 | .pt30 { 124 | padding-top: 30rpx; 125 | } 126 | 127 | .pr30 { 128 | padding-right: 30rpx; 129 | } 130 | 131 | .pb30 { 132 | padding-bottom: 30rpx; 133 | } 134 | 135 | .pl30 { 136 | padding-left: 30rpx; 137 | } 138 | 139 | .pt20 { 140 | padding-top: 20rpx; 141 | } 142 | 143 | .pr20 { 144 | padding-right: 20rpx; 145 | } 146 | 147 | .pb20 { 148 | padding-bottom: 20rpx; 149 | } 150 | 151 | .pl20 { 152 | padding-left: 20rpx; 153 | } 154 | 155 | .pt40 { 156 | padding-top: 40rpx; 157 | } 158 | 159 | .pr40 { 160 | padding-right: 40rpx; 161 | } 162 | 163 | .pb40 { 164 | padding-bottom: 40rpx; 165 | } 166 | 167 | .pl40 { 168 | padding-left: 40rpx; 169 | } 170 | 171 | .mt10 { 172 | margin-top: 10rpx; 173 | } 174 | 175 | .mr10 { 176 | margin-right: 10rpx; 177 | } 178 | 179 | .mb10 { 180 | margin-bottom: 10rpx; 181 | } 182 | 183 | .ml10 { 184 | margin-left: 10rpx; 185 | } 186 | 187 | .mt30 { 188 | margin-top: 30rpx; 189 | } 190 | 191 | .mr30 { 192 | margin-right: 30rpx; 193 | } 194 | 195 | .mb30 { 196 | margin-bottom: 30rpx; 197 | } 198 | 199 | .ml30 { 200 | margin-left: 30rpx; 201 | } 202 | 203 | .mt20 { 204 | margin-top: 20rpx; 205 | } 206 | 207 | .mr20 { 208 | margin-right: 20rpx; 209 | } 210 | 211 | .mb20 { 212 | margin-bottom: 20rpx; 213 | } 214 | 215 | .ml20 { 216 | margin-left: 20rpx; 217 | } 218 | 219 | .mt40 { 220 | margin-top: 40rpx; 221 | } 222 | 223 | .mr40 { 224 | margin-right: 40rpx; 225 | } 226 | 227 | .mb40 { 228 | margin-bottom: 40rpx; 229 | } 230 | 231 | .ml40 { 232 | margin-left: 40rpx; 233 | } 234 | 235 | .lh1-5 { 236 | line-height: 1.5em; 237 | } 238 | 239 | .lh2 { 240 | line-height: 2em; 241 | } 242 | 243 | .lh2-5 { 244 | line-height: 2.5em; 245 | } 246 | 247 | .lh3 { 248 | line-height: 3em; 249 | } 250 | 251 | .lh3-5 { 252 | line-height: 3.5em; 253 | } 254 | 255 | .lh4 { 256 | line-height: 4em; 257 | } 258 | 259 | 260 | /* 单行省略 */ 261 | 262 | .uniline { 263 | overflow: hidden; 264 | text-overflow: ellipsis; 265 | white-space: nowrap; 266 | } 267 | 268 | 269 | /* 多行省略 */ 270 | 271 | .multi-line { 272 | display: -webkit-box; 273 | -webkit-box-orient: vertical; 274 | -webkit-line-clamp: 2; 275 | overflow: hidden; 276 | } 277 | 278 | .multi-line-3 { 279 | -webkit-line-clamp: 3; 280 | } 281 | 282 | .multi-line-4 { 283 | -webkit-line-clamp: 4; 284 | } 285 | 286 | .flex-center-center { 287 | display: flex; 288 | flex-direction: column; 289 | justify-content: center; 290 | align-items: center; 291 | } 292 | 293 | 294 | /* 下划线 */ 295 | 296 | .underline { 297 | text-decoration: underline; 298 | color: #647D9A; 299 | } 300 | 301 | 302 | /* 选择图片 */ 303 | 304 | .select-image { 305 | position: relative; 306 | width: 30%; 307 | height: 0; 308 | padding-bottom: 30%; 309 | border: 2rpx dashed transparent; 310 | background: linear-gradient(white, white) padding-box, repeating-linear-gradient(-45deg, #ccc 0, #ccc 0.25em, white 0, white 0.6em); 311 | } 312 | 313 | .icon_add { 314 | position: absolute; 315 | top: 50%; 316 | left: 50%; 317 | transform: translate(-50%, -50%); 318 | width: 100rpx; 319 | height: 100rpx; 320 | } 321 | 322 | .icon-right { 323 | width: 14rpx; 324 | height: 28rpx; 325 | } 326 | 327 | .icon-refresh { 328 | width: 100rpx; 329 | height: 100rpx; 330 | } 331 | 332 | .z-index-1 { 333 | z-index: -1; 334 | } 335 | 336 | /* 隐藏滚动条 */ 337 | ::-webkit-scrollbar { 338 | width: 0; 339 | height: 0; 340 | color: transparent; 341 | } -------------------------------------------------------------------------------- /pages/goods/goods.js: -------------------------------------------------------------------------------- 1 | var app = getApp() 2 | import { goodsList } from '../../utils/publicData' 3 | Page({ 4 | data: { 5 | navActive: 5, 6 | goodsList: goodsList, 7 | selectGoods: { 8 | url: '', 9 | bool: false, 10 | left: '', 11 | top: '' 12 | }, 13 | imgUrls: [ 14 | '../../images/banner1.jpg', 15 | '../../images/banner2.jpg', 16 | '../../images/banner3.jpg' 17 | ], 18 | pull: { 19 | isLoading: false, 20 | loading: '../../image/common/pull_refresh.gif', 21 | pullText: '正在加载' 22 | }, 23 | push: { 24 | isLoading: false, 25 | loading: '../../image/common/pull_refresh.gif', 26 | pullText: '-上拉加载更多-' 27 | }, 28 | indicatorDots: false, 29 | autoplay: false, 30 | interval: 5000, 31 | duration: 500, 32 | goods_list: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 33 | hideCount: false, 34 | count: 0, 35 | needAni: false, 36 | hide_good_box: true 37 | }, 38 | onLoad() { 39 | var that = this; 40 | this.busPos = {}; 41 | this.busPos['x'] = app.globalData.ww * 0.8; 42 | this.busPos['y'] = app.globalData.hh * 0.8; 43 | }, 44 | tabSelect(e) { 45 | this.setData({ 46 | navActive: e.target.dataset.index 47 | }) 48 | }, 49 | refresh(e) { 50 | console.log('刷新', e); 51 | this.setData({ 52 | 'pull.isLoading': true, 53 | 'pull.loading': '../../image/common/pull_refresh.gif', 54 | 'pull.pullText': '正在加载', 55 | }); 56 | setTimeout(() => { 57 | this.setData({ 58 | 'pull.loading': '../../image/common/finish.png', 59 | 'pull.pullText': '刷新完成' 60 | }) 61 | }, 4000); 62 | setTimeout(() => { 63 | this.setData({ 64 | 'pull.isLoading': false, 65 | }); 66 | console.log('+++++ 刷新完成 +++++') 67 | }, 6000) 68 | }, 69 | toload(e) { 70 | console.log('加载', e); 71 | this.setData({ 72 | 'push.isLoading': true, 73 | 'push.pullText': '正在加载', 74 | 'push.loading': '../../image/common/pull_refresh.gif', 75 | }); 76 | if (this.data.goodsList.length < 30) { 77 | setTimeout(() => { 78 | let data = this.data.goodsList.concat([ 79 | {title: '单人沙发', goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/EAD670176 D1882/common/SM_IMAGE/SM_001.jpg'}, 80 | {title: '双人沙发', goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/11M9007U212301/common/SM_IMAGE/SM_001.jpg?x-oss-process=image/resize,m_pad,h_500,w_500,color_FFFFFF'}, 81 | {title: '早安床头柜', goodsImg: 'http://mkmarketing.oss-cn-hangzhou.aliyuncs.com/Marketing/namecard/product/image/CACLA-016-063/common/SM_IMAGE/SM_001.jpg'} 82 | ]); 83 | this.setData({ 84 | goodsList: data, 85 | 'push.isLoading': false, 86 | 'push.pullText': '- 上拉加载更多 -', 87 | 'push.loading': '../../image/common/finish.png', 88 | }); 89 | console.log('===== 加载完成 =====') 90 | }, 2000) 91 | } 92 | }, 93 | busAnimation() { 94 | that.setData({ 95 | needAni: true 96 | }); 97 | setTimeout(() => { 98 | that.setData({ 99 | needAni: false 100 | }); 101 | }, 500); 102 | }, 103 | touchOnGoods (e) { 104 | if (!this.data.hide_good_box) return; 105 | this.finger = {}; 106 | var topPoint = {}; 107 | this.finger['x'] = e.touches["0"].clientX > app.globalData.ww - 75 ? app.globalData.ww - 80 : e.touches["0"].clientX; 108 | this.finger['y'] = e.touches["0"].clientY; 109 | if (this.finger['y'] < this.busPos['y']) { 110 | topPoint['y'] = this.finger['y'] - 150; 111 | } else { 112 | topPoint['y'] = this.busPos['y'] - 150; 113 | } 114 | topPoint['x'] = Math.abs(this.finger['x'] - this.busPos['x']) / 2 + this.finger['x']; 115 | this.linePos = app.bezier([this.finger, topPoint, this.busPos], 30); 116 | this.startAnimation(); 117 | }, 118 | startAnimation () { 119 | var index = 0, 120 | that = this, 121 | bezier_points = that.linePos['bezier_points']; 122 | this.setData({ 123 | hide_good_box: false, 124 | bus_x: that.finger['x'], 125 | bus_y: that.finger['y'] 126 | }); 127 | this.timer = setInterval(() => { 128 | index++; 129 | that.setData({ 130 | bus_x: bezier_points[index]['x'], 131 | bus_y: bezier_points[index]['y'] 132 | }); 133 | if (index >= 28) { 134 | clearInterval(that.timer); 135 | that.setData({ 136 | hide_good_box: true, 137 | hideCount: false, 138 | count: that.data.count += 1 139 | }) 140 | } 141 | }, 33); 142 | }, 143 | giveLike(e) { 144 | let ind = e.target.dataset.ind; 145 | let key = `goodsList[${ind}].like`; 146 | this.setData({ 147 | [key]: !this.data.goodsList[ind].like 148 | }); 149 | } 150 | }); -------------------------------------------------------------------------------- /pages/client-pool/client-pool.js: -------------------------------------------------------------------------------- 1 | import { howLongAgo } from '../../utils/util' 2 | import { sourceData, cateData } from '../../utils/publicData' 3 | Page({ 4 | data: { 5 | praise: false, 6 | sourceData: sourceData, 7 | cateData: cateData, 8 | clientCondition: { 9 | data: { 10 | searchValue: '', 11 | sourceValue: '', 12 | cateValue: '', 13 | }, 14 | pageNum: 1, 15 | pageSize: 10 16 | }, 17 | cluesData: [], 18 | pull: { 19 | isLoading: false, 20 | loading: '../../image/common/pull_refresh.gif', 21 | pullText: '正在刷新' 22 | }, 23 | push: { 24 | isLoading: false, 25 | loading: '../../image/common/pull_refresh.gif', 26 | pullText: '-上拉加载更多-' 27 | }, 28 | slideStart: 0, 29 | moveTime: 0, 30 | isShow_01: false, 31 | picker_01_data:[], 32 | }, 33 | onLoad() { 34 | this.loadMore() 35 | }, 36 | /**搜索框内容改变 */ 37 | searchChange(e) { 38 | this.setData({ 39 | 'clientCondition.data.searchValue': e.detail.value 40 | }) 41 | }, 42 | /**点击键盘搜索按钮触发 */ 43 | bindconfirm(e) { 44 | console.log('搜索', e) 45 | }, 46 | /**清空搜索框内容 */ 47 | clearSearchValue() { 48 | this.setData({ 49 | 'clientCondition.data.searchValue': '' 50 | }) 51 | }, 52 | /**滚动选择器选择来源、类别 */ 53 | bindPickerChange(e) { 54 | if (e.target.dataset.type == 'source') { 55 | this.setData({ 56 | 'clientCondition.data.sourceValue': this.data.sourceData[e.detail.value].key 57 | }) 58 | } else if (e.target.dataset.type == 'cate') { 59 | this.setData({ 60 | 'clientCondition.data.cateValue': this.data.cateData[e.detail.value].key 61 | }) 62 | } 63 | }, 64 | bindpraise() { 65 | if (this.data.praise === false) { 66 | this.setData({ 67 | 'praise': 2 68 | }) 69 | setTimeout(() => { 70 | this.setData({ 71 | 'praise': true 72 | }) 73 | }, 1000) 74 | } else { 75 | this.setData({ 76 | 'praise': 2 77 | }) 78 | setTimeout(() => { 79 | this.setData({ 80 | 'praise': false 81 | }) 82 | }, 1000) 83 | } 84 | }, 85 | tranTime() { 86 | let data = this.data.cluesData.map(item => { 87 | item.date = howLongAgo(item.time) 88 | return item 89 | }) 90 | this.setData({ 91 | cluesData: data 92 | }) 93 | }, 94 | /**触发下拉刷新 */ 95 | touchstart(e) { 96 | this.setData({ 97 | slideStart: e.touches[0] 98 | }) 99 | console.log('开始', e) 100 | }, 101 | touchmove(e) { 102 | let moveTime = new Date().getTime(); 103 | if (moveTime - this.data.moveTime <= 2000) { 104 | return 105 | } else { 106 | this.setData({ 107 | moveTime: moveTime 108 | }) 109 | } 110 | let slideStart = this.data.slideStart; 111 | let slideMove = e.touches[0]; 112 | let startX = slideStart.pageX; 113 | let startY = slideStart.pageY; 114 | let moveEndX = slideMove.pageX; 115 | let moveEndY = slideMove.pageY; 116 | let X = moveEndX - startX; 117 | let Y = moveEndY - startY; 118 | if (Math.abs(Y) > Math.abs(X) && Y > 0) { 119 | console.log("top 2 bottom"); 120 | this.pullRefresh() 121 | } else if (Math.abs(Y) > Math.abs(X) && Y < 0) { 122 | console.log("bottom 2 top"); 123 | this.loadMore() 124 | } 125 | }, 126 | /**下拉刷新 */ 127 | pullRefresh(e) { 128 | this.setData({ 129 | 'pull.isLoading': true, 130 | 'pull.loading': '../../image/common/pull_refresh.gif', 131 | 'pull.pullText': '正在刷新~' 132 | }) 133 | setTimeout(() => { 134 | this.setData({ 135 | 'pull.loading': '../../image/common/finish.png', 136 | 'pull.pullText': '刷新完成' 137 | }) 138 | }, 4000) 139 | setTimeout(() => { 140 | this.setData({ 141 | 'pull.isLoading': false, 142 | }) 143 | }, 6000) 144 | }, 145 | /**上拉加载更多 */ 146 | loadMore() { 147 | this.setData({ 148 | 'push.isLoading': true, 149 | 'push.pullText': '正在加载', 150 | 'push.loading': '../../image/common/pull_refresh.gif', 151 | }) 152 | if (this.data.cluesData.length < 30) { 153 | setTimeout(() => { 154 | let data = this.data.cluesData.concat([ 155 | { time: '2019-11-20 15:50' }, 156 | { time: '2018-06-20 15:32' } 157 | ]) 158 | this.setData({ 159 | cluesData: data, 160 | 'push.isLoading': false, 161 | 'push.pullText': '- 上拉加载更多 -', 162 | 'push.loading': '../../image/common/finish.png', 163 | }) 164 | this.tranTime() 165 | }, 2000) 166 | } 167 | }, 168 | /**跳转客户详情 */ 169 | toCustomerDetails() { 170 | 171 | }, 172 | myPickerChange(e) { 173 | console.log('自定义组件选择的结果', e.detail) 174 | this.setData({ 175 | address: e.detail 176 | }) 177 | }, 178 | showPicker_01() { 179 | this.setData({ 180 | isShow_01: true, 181 | }) 182 | }, 183 | sureCallBack_01(e) { 184 | let data = e.detail 185 | this.setData({ 186 | isShow_01: false, 187 | picker_01_data: e.detail.choosedData, 188 | picker_01_index: JSON.stringify(e.detail.choosedIndexArr) 189 | }) 190 | console.log(this.data.picker_01_data, this.data.picker_01_index) 191 | }, 192 | cancleCallBack_01() { 193 | this.setData({ 194 | isShow_01: false, 195 | }) 196 | }, 197 | }) -------------------------------------------------------------------------------- /pages/activity/activity.js: -------------------------------------------------------------------------------- 1 | Page({ 2 | data: { 3 | size: 400,//转盘大小, 4 | musicflg: false, //声音 5 | fastJuedin: true,//快速决定 6 | repeat: true,//不重复抽取 7 | probability: true,// 概率 8 | s_awards: '',//结果 9 | option: '标题', 10 | //转盘的总数据,想添加多个可以往这数组里添加一条格式一样的数据 11 | zhuanpanArr: [ 12 | { 13 | id: 0, 14 | option: '我帅吗?',//转盘的标题名称 15 | awards: [ 16 | { 17 | id: 0, // id递增 18 | name: "帅", // 选项名 超过9个字时字体会变小点 大于13个数时会隐藏掉超出的 19 | color: '#FFA827', // 选项的背景颜色 20 | probability: 200 // 概率 0代表永远也转不到这个选项,数字越大概率也就越大,data中的probability属性设置为true时是才生效, 这属性也必须填写,不填写会出错 21 | }, 22 | { 23 | id: 1, 24 | name: "很帅", 25 | color: '#AA47BC', 26 | probability: 10 27 | }, 28 | { 29 | id: 2, 30 | name: "贼帅", 31 | color: '#42A5F6', 32 | probability: 10 33 | }, 34 | { 35 | id: 3, 36 | name: "非常帅", 37 | color: '#66BB6A', 38 | probability: 10 39 | }, 40 | { 41 | id: 4, 42 | name: "超级帅", 43 | color: '#FFA500', 44 | probability: 100 45 | }, 46 | { 47 | id: 5, 48 | name: "宇宙无敌第一帅", 49 | color: '#FF4500', 50 | probability: 0 51 | }, 52 | { 53 | id: 6, 54 | name: "你最美", 55 | color: '#AA47BC', 56 | probability: 10 57 | } 58 | ] 59 | } 60 | ], 61 | //更改数据可以更改这属性,格式要像下面这样写才行 62 | awardsConfig: { 63 | option: '我帅吗?',//转盘的标题名称 64 | awards: [ 65 | { 66 | id: 0, // id递增 67 | name: "帅帅帅", // 选项名 超过9个字时字体会变小点 大于13个数时会隐藏掉超出的 68 | color: '#FFA827', // 选项的背景颜色 69 | probability: 100 // 概率 0代表永远也转不到这个选项,数字越大概率也就越大,data中的probability属性设置为true时是才生效, 这属性也必须填写,不填写会出错 70 | }, 71 | { 72 | id: 1, 73 | name: "很帅", 74 | color: '#AA47BC', 75 | probability: 10 76 | }, 77 | { 78 | id: 2, 79 | name: "贼帅", 80 | color: '#42A5F6', 81 | probability: 10 82 | }, 83 | { 84 | id: 3, 85 | name: "非常帅", 86 | color: '#66BB6A', 87 | probability: 10 88 | }, 89 | { 90 | id: 4, 91 | name: "超级帅", 92 | color: '#FFA500', 93 | probability: 100 94 | }, 95 | { 96 | id: 5, 97 | name: "宇宙无敌第一帅", 98 | color: '#FF4500', 99 | probability: 0 100 | }, 101 | { 102 | id: 6, 103 | name: "你最美", 104 | color: '#AA47BC', 105 | probability: 10 106 | }, 107 | ] 108 | } 109 | }, 110 | 111 | //接收当前转盘初始化时传来的参数 112 | getData(e) { 113 | this.setData({ 114 | option: e.detail.option 115 | }) 116 | }, 117 | 118 | //接收当前转盘结束后的答案选项 119 | getAwards(e) { 120 | wx.showToast({ 121 | title: e.detail, 122 | icon: 'none' 123 | }) 124 | this.setData({ 125 | s_awards: e.detail, 126 | }) 127 | }, 128 | 129 | //开始转动或者结束转动 130 | startZhuan(e) { 131 | this.setData({ 132 | zhuanflg: e.detail ? true : false 133 | }) 134 | }, 135 | 136 | //切换转盘选项 137 | switchZhuanpan(e) { 138 | //当转盘停止时才执行切换转盘 139 | if (!this.data.zhuanflg) { 140 | var idx = e.currentTarget.dataset.idx, zhuanpanArr = this.data.zhuanpanArr, obj = {}; 141 | for (let i in zhuanpanArr) { 142 | if (this.data.option != zhuanpanArr[i].option && zhuanpanArr[i].id == idx) { 143 | obj.option = zhuanpanArr[i].option; 144 | obj.awards = zhuanpanArr[i].awards; 145 | this.setData({ 146 | awardsConfig: obj //其实默认要更改当前转盘的数据要传个这个对象,才有效果 147 | }) 148 | break; 149 | } 150 | } 151 | } 152 | }, 153 | 154 | //转盘声音 155 | switch1Change1(e) { 156 | var value = e.detail.value; 157 | if (this.data.zhuanflg) { 158 | wx.showToast({ 159 | title: '当转盘停止转动后才有效', 160 | icon: 'none' 161 | }) 162 | return; 163 | } else { 164 | this.setData({ 165 | musicflg: value 166 | }) 167 | } 168 | }, 169 | 170 | //不重复抽取 171 | switch1Change2(e) { 172 | var value = e.detail.value; 173 | if (this.data.zhuanflg) { 174 | wx.showToast({ 175 | title: '当转盘停止转动后才有效', 176 | icon: 'none' 177 | }) 178 | return; 179 | } else { 180 | this.setData({ 181 | repeat: value 182 | }) 183 | } 184 | }, 185 | 186 | //快速决定 187 | switch1Change3(e) { 188 | var value = e.detail.value; 189 | if (this.data.zhuanflg) { 190 | wx.showToast({ 191 | title: '当转盘停止转动后才有效', 192 | icon: 'none' 193 | }) 194 | return; 195 | } else { 196 | this.setData({ 197 | fastJuedin: value 198 | }) 199 | } 200 | }, 201 | 202 | //概率 == 如果不重复抽取开启的话 概率是无效的 203 | switch1Change4(e) { 204 | var value = e.detail.value; 205 | if (this.data.zhuanflg) { 206 | wx.showToast({ 207 | title: '当转盘停止转动后才有效', 208 | icon: 'none' 209 | }) 210 | return; 211 | } else { 212 | this.setData({ 213 | probability: value 214 | }) 215 | } 216 | }, 217 | 218 | onLoad: function () { 219 | //实例化组件对象,这样有需要时就能调用组件内的方法 220 | this.zhuanpan = this.selectComponent("#zhuanpan"); 221 | 222 | //可以这样调用 示例:this.zhuanpan.switchZhuanpan(data); 223 | //上面这方法可用来切换转盘选项数据,参数可以看组件构造器中的switchZhuanpan方法 224 | } 225 | }) 226 | -------------------------------------------------------------------------------- /components/turntable/turntable.js: -------------------------------------------------------------------------------- 1 | // components/zhuanpan/zhuanpan.js 2 | //创建并返回内部 audio 上下文 innerAudioContext 对象 3 | const start = wx.createInnerAudioContext(); 4 | const mid = wx.createInnerAudioContext(); 5 | const stop = wx.createInnerAudioContext(); 6 | 7 | Component({ 8 | options: { 9 | multipleSlots: true // 在组件定义时的选项中启用多slot支持 10 | }, 11 | 12 | /** 13 | * 组件的属性列表 14 | * 用于组件自定义设置 组件的对外属性 15 | */ 16 | properties: { 17 | myProperty: { // 属性名 myProperty2: String, 简化的定义方式 18 | type: String, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型) 19 | value: '', // 属性默认 初始值(可选),如果未指定则会根据类型选择一个 20 | observer: function (newVal, oldVal, changedPath) { 21 | // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange' 22 | // 通常 newVal 就是新设置的数据, oldVal 是旧数据 23 | } 24 | }, 25 | 26 | probability: { 27 | type: Boolean, // 概率开关,默认false 随机 28 | value: false 29 | }, 30 | 31 | musicflg: { 32 | type: Boolean, // 转盘声音开关,默认true 33 | value: true 34 | }, 35 | 36 | fastJuedin: { 37 | type: Boolean, // 快速转动转盘的开关,默认false 38 | value: false 39 | }, 40 | 41 | repeat: { 42 | type: Boolean, // 重复抽取开关,默认false 43 | value: false 44 | }, 45 | 46 | size: { 47 | type: Number, // 转盘大小,传入宽度即可 48 | value: 600 49 | }, 50 | 51 | zhuanpanArr: { // 可以切换的转盘选项, 支持多个 52 | type: Array, 53 | value: [ 54 | { 55 | id: 0, 56 | option: '转盘的标题名称', 57 | awards: [ 58 | { 59 | id: 0, 60 | name: "最多17个选项", // 选项名 61 | color: 'red', // 选项的背景颜色 62 | probability: 10 // 概率 0代表永远也转不到这个选项,数字越大概率也就越大 63 | }, 64 | { 65 | id: 1, 66 | name: "选项最多填13字", // 超过9个字时字体会变小点 67 | color: 'green', 68 | probability: 10 69 | } 70 | ] 71 | } 72 | ] 73 | }, 74 | 75 | // 限制:最多17个选项, 单个选项最多填10-13个字,多余部分会隐藏 76 | awardsConfig: { // 默认的当前转盘选项 77 | type: Object, 78 | value: { 79 | option: '我的小决定?', 80 | awards: [ 81 | { 82 | id: 0, 83 | name: "最多17个选项", 84 | color: 'red', 85 | probability: 0 86 | }, 87 | { 88 | id: 1, 89 | name: "选项最多填13字", 90 | color: 'green', 91 | probability: 0 92 | } 93 | ], 94 | }, 95 | observer: function (newVal, oldVal, changedPath) { 96 | if (newVal) { 97 | this.switchZhuanpan(newVal, true); 98 | } 99 | } 100 | } 101 | 102 | }, 103 | 104 | /** 105 | * 私有数据,组件的初始数据 106 | * 可用于模版渲染 107 | */ 108 | data: { 109 | animationData: {}, // 转盘动画 110 | zhuanflg: false, // 转盘是否可以点击切换的标志位 111 | fastTime: 7600, // 转盘快速转动的时间 112 | slowTime: 3900, // 转盘慢速转动的时间 113 | runDegs: 0, // 转盘旋转了多少圈 114 | timer: null, // 清除转盘的时间clearTimeout(timer) 115 | block1: 'block', // 控制显示或隐藏转盘中心的图片 116 | block2: 'none', 117 | block3: 'none', 118 | block4: 'none' 119 | }, 120 | 121 | //组件生命周期函数,在组件实例进入页面节点树时执行,注意此时不能调用 setData 122 | created: function () { }, 123 | 124 | // 组件生命周期函数,在组件实例进入页面节点树时执行 125 | attached: function () { 126 | console.log('===============attached==============='); 127 | start.src = 'https://gamesdata.oss-cn-hangzhou.aliyuncs.com/xiaojueding/start.mp3'; // 转盘开始转动的音乐 128 | mid.src = 'https://gamesdata.oss-cn-hangzhou.aliyuncs.com/xiaojueding/mid.mp3'; // 快速决定时,转盘开始转动的音乐 129 | stop.src = 'https://gamesdata.oss-cn-hangzhou.aliyuncs.com/xiaojueding/stop.mp3'; // 转盘停止转动的音乐 130 | 131 | this.setData({ 132 | awardsConfig: this.data.zhuanpanArr[0] 133 | }) 134 | this.initAdards(); 135 | }, 136 | 137 | /** 138 | * 组件的方法列表 139 | * 更新属性和数据的方法与更新页面数据的方法类似 140 | */ 141 | methods: { 142 | /* 143 | * 公有方法 144 | */ 145 | //判断值是否为空 146 | isNull(str) { 147 | if (str == null || str == undefined || str == '') { 148 | return true; 149 | } else { 150 | return false; 151 | } 152 | }, 153 | 154 | //初始化数据 155 | initAdards() { 156 | var that = this, awardsConfig = that.data.awardsConfig; 157 | var t = awardsConfig.awards.length; // 选项长度 158 | var e = 1 / t, i = 360 / t, r = i - 90; 159 | 160 | for (var g = 0; g < t; g++) { 161 | awardsConfig.awards[g].item2Deg = g * i + 90 - i / 2 + "deg";//当前下标 * 360/长度 + 90 - 360/长度/2 162 | awardsConfig.awards[g].afterDeg = r + "deg"; 163 | awardsConfig.awards[g].opacity = '1'; 164 | } 165 | 166 | that.setData({ 167 | turnNum: e, // 页面的单位是turn 168 | awardsConfig: awardsConfig, 169 | }) 170 | 171 | that._change();//向父组件传出当前转盘的初始数据 172 | }, 173 | 174 | //重置转盘 175 | reset() { 176 | var that = this, awardsConfig = that.data.awardsConfig; 177 | var animation = wx.createAnimation({ 178 | duration: 1, 179 | timingFunction: "ease" 180 | }); 181 | that.animation = animation; 182 | animation.rotate(0).step(), that.data.runDegs = 0; 183 | 184 | that.setData({ 185 | animationData: animation.export(), 186 | block3: 'none', 187 | block4: 'block' 188 | }) 189 | 190 | for (let x in awardsConfig.awards) { 191 | awardsConfig.awards[x].opacity = '1'; 192 | } 193 | 194 | setTimeout(function () { 195 | that.setData({ 196 | block1: 'block', 197 | block4: 'none', 198 | awardsConfig: awardsConfig, 199 | }) 200 | }, 300) 201 | }, 202 | 203 | //父组件需要切换当前转盘的选项 204 | //如果有需要切换不同转盘的选项时,可以调用这方法 205 | //data: 转盘的数据 206 | //flag: 当转盘在转动过程中如果你想停止的话,可以传个true值,默认可不传 207 | switchZhuanpan(data, flag) { 208 | this.setData({ 209 | awardsConfig: data, 210 | block1: 'block', 211 | block1: 'none', 212 | block3: 'none', 213 | block4: 'none', 214 | zhuanflg: false, 215 | }) 216 | this.initAdards(); 217 | 218 | if (flag) { 219 | this.reset(); 220 | clearTimeout(this.data.timer); 221 | start.stop(); 222 | mid.stop(); 223 | stop.stop(); 224 | wx.removeStorageSync('repeatArr'); 225 | } 226 | }, 227 | 228 | 229 | 230 | /* 231 | * 内部私有方法建议以下划线开头 232 | * triggerEvent 用于触发事件,过triggerEvent来给父组件传递信息的 233 | * 写法: this.triggerEvent('cancelEvent', { num: 1 }) // 可以将num通过参数的形式传递给父组件 234 | */ 235 | 236 | // GO转盘开始转动 237 | _zhuan() { 238 | var that = this, awardsConfig = that.data.awardsConfig, runDegs = that.data.runDegs; 239 | //>>> 是无符号移位运算符 240 | var r = Math.random() * awardsConfig.awards.length >>> 0, runNum = 8; 241 | 242 | 243 | /*=============不重复抽取=============*/ 244 | if (that.data.repeat) { 245 | r = that._queryRepeat(r); 246 | } else { 247 | wx.removeStorageSync('repeatArr'); 248 | 249 | console.log('是否开启了概率???', that.data.probability); 250 | //开启概率 probability这属性必须要传个ture 251 | if (that.data.probability) { 252 | r = that._openProbability(); 253 | } 254 | } 255 | /*=============不重复抽取=============*/ 256 | 257 | 258 | console.log('当前答案选项的下标=====', r); 259 | setTimeout(function () { 260 | //转盘开始转动音乐 261 | that.data.musicflg ? that.data.fastJuedin ? mid.play() : start.play() : ''; 262 | 263 | //要转多少度deg 264 | runDegs = runDegs || 0, runDegs = runDegs + (360 - runDegs % 360) + (2160 - r * (360 / awardsConfig.awards.length)); 265 | 266 | var animation = wx.createAnimation({ 267 | duration: that.data.fastJuedin ? that.data.slowTime : that.data.fastTime, 268 | timingFunction: "ease" 269 | }); 270 | that.animation = animation; 271 | 272 | //这动画执行的是差值 273 | //如果第一次写rotate(360) 那么第二次再写rotate(360)将不起效果 274 | animation.rotate(runDegs).step(), 0 == r && (runDegs = 0); 275 | 276 | that.setData({ 277 | animationData: animation.export(), 278 | block1: 'none', 279 | block2: 'block', 280 | zhuanflg: true, 281 | }) 282 | 283 | that._setatZhuan(true); 284 | }, 100); 285 | 286 | that.setData({ 287 | timer: setTimeout(function () { 288 | //转盘停止后,答案区域高亮显示,其他区域增加透明度 289 | for (let x in awardsConfig.awards) { 290 | if (x != r) { 291 | awardsConfig.awards[x].opacity = '0.3'; 292 | } else { 293 | awardsConfig.awards[x].opacity = '1'; 294 | } 295 | } 296 | 297 | //转盘停止后的音乐 298 | !that.data.musicflg ? '' : stop.play(); 299 | 300 | that.setData({ 301 | animationData: {}, 302 | s_awards: awardsConfig.awards[r].name,//最终选中的结果 303 | awardsConfig: awardsConfig, 304 | block2: 'none', 305 | block3: 'block', 306 | zhuanflg: false, 307 | }) 308 | that._myAwards(); 309 | that._setatZhuan(false); 310 | }, that.data.fastJuedin ? that.data.slowTime : that.data.fastTime) 311 | }) 312 | }, 313 | 314 | 315 | // 开启概率 316 | // 传的数越大概率越大 317 | // 传入0的话就永远摇不到这个选项 318 | _openProbability() { 319 | var that = this, awards = that.data.awardsConfig.awards, arr = []; 320 | //5, 5, 20, 10 ,30 ,30, 0 321 | for (let i in awards) { 322 | if (awards[i].probability != 0) { 323 | for (var x = 0; x < awards[i].probability; x++) { 324 | //把当前的概率数字 以当前选项下标的形式 都添加都空数组中,然后随机这个数组 325 | arr.push(i); 326 | } 327 | } 328 | } 329 | var s = Math.floor(Math.random() * arr.length); 330 | return arr[s]; 331 | }, 332 | 333 | //不重复抽取 334 | //r:随机数 当前选项进行随机 335 | _queryRepeat(r) { 336 | var that = this, flag = true, repeatArr = wx.getStorageSync('repeatArr'), repeatArr2 = [], awardsConfig = that.data.awardsConfig; 337 | if (that.isNull(repeatArr)) { 338 | repeatArr2.push(r), wx.setStorageSync('repeatArr', repeatArr2); 339 | return r; 340 | } else { 341 | var len = awardsConfig.awards.length, r = Math.random() * len >>> 0; 342 | for (let i in repeatArr) { 343 | if (r == repeatArr[i]) { 344 | flag = false; 345 | if (repeatArr.length == len) { 346 | wx.removeStorageSync('repeatArr'); 347 | repeatArr2.push(r), wx.setStorageSync('repeatArr', repeatArr2); 348 | return r; 349 | } else { 350 | return that._queryRepeat();//递归调用 351 | } 352 | } 353 | } 354 | if (flag) { 355 | repeatArr.push(r), wx.setStorageSync('repeatArr', repeatArr); 356 | return r; 357 | } 358 | } 359 | }, 360 | 361 | //初始化数据时向外传的参 362 | _change() { 363 | this.triggerEvent('myData', this.data.awardsConfig);// 向父组件传出当前转盘的数组数据 364 | }, 365 | 366 | //当前转盘的结果 367 | _myAwards() { 368 | this.triggerEvent('myAwards', this.data.s_awards) 369 | }, 370 | 371 | //转盘开始转动或者结速转动后的要传的值 372 | _setatZhuan(e) { 373 | this.triggerEvent('startZhuan', e); 374 | }, 375 | 376 | } 377 | }) 378 | -------------------------------------------------------------------------------- /components/picker/picker.js: -------------------------------------------------------------------------------- 1 | // picker/picker.js 2 | import { isPlainObject } from '../../utils/tools' 3 | 4 | Component({ 5 | /** 6 | * 组件的属性列表 7 | */ 8 | properties: { 9 | scrollType: { 10 | type: String, 11 | value: 'normal'// "link": scroll间联动 "normal": scroll相互独立 12 | }, 13 | listData: { 14 | type: Array, 15 | value: [], 16 | observer: function (newVal) { 17 | if (newVal.length === 0 || this._compareDate()) return 18 | this._setTempData() 19 | const tempArr = [...new Array(newVal.length).keys()].map(() => 0) 20 | this.data.lastValue = this.data.tempValue = tempArr 21 | this._setDefault() 22 | 23 | // let {defaultPickData} = this.properties; 24 | // if(newVal.length === 0) return; 25 | // 26 | // this._setDefault(newVal, defaultPickData) 27 | } 28 | }, 29 | defaultPickData: { 30 | type: Array, 31 | value: [], 32 | observer: function (newVal) { 33 | if (newVal.length === 0 || this._compareDate()) return 34 | this._setTempData() 35 | this._setDefault() 36 | } 37 | }, 38 | keyWordsOfShow: { 39 | type: String, 40 | value: 'name' 41 | }, 42 | isShowPicker: { 43 | type: Boolean, 44 | value: false, 45 | observer: function (newVal) { 46 | if (newVal) { 47 | this._openPicker() 48 | } else { 49 | this._closePicker() 50 | } 51 | } 52 | }, 53 | titleText: {// 标题文案 54 | type: String, 55 | value: '标题' 56 | }, 57 | cancelText: {// 取消按钮文案 58 | type: String, 59 | value: '取消' 60 | }, 61 | sureText: {// 确定按钮文案 62 | type: String, 63 | value: '确定' 64 | }, 65 | pickerHeaderStyle: String, // 标题栏样式 view 66 | sureStyle: String, // 标题栏确定样式 text 67 | cancelStyle: String, // 标题栏取消样式 text 68 | titleStyle: String, // 标题栏标题样式 view 69 | maskStyle: String, // 设置蒙层的样式(详见picker-view) view 70 | indicatorStyle: String, // 设置选择器中间选中框的样式(详见picker-view) view 71 | chooseItemTextStyle: String// 设置picker列表文案样式 text 72 | }, 73 | 74 | /** 75 | * 组件的初始数据 76 | */ 77 | data: { 78 | columnsData: [], 79 | value: [], 80 | backData: [], 81 | height: 0, 82 | isOpen: false, 83 | isUseKeywordOfShow: false, 84 | scrollEnd: true, // 滚动是否结束 85 | lastValue: [], // 上次各个colum的选择索引 86 | tempValue: [], 87 | isFirstOpen: true, 88 | onlyKey: '', 89 | defaultPickDataTemp: '', 90 | listDataTemp: '' 91 | }, 92 | /** 93 | * 组件的方法列表 94 | */ 95 | methods: { 96 | tapModal() { 97 | this.properties.isShowPicker = false 98 | this._closePicker() 99 | }, 100 | cancle() { 101 | this.triggerEvent('cancle') 102 | this._closePicker() 103 | }, 104 | sure() { 105 | const { scrollEnd, tempValue } = this.data 106 | if (!scrollEnd) return 107 | const backData = this._getBackDataFromValue(tempValue) 108 | this.setData({ 109 | backData 110 | }) 111 | this.triggerEvent('sure', { 112 | choosedData: backData, 113 | choosedIndexArr: tempValue 114 | }) 115 | this._closePicker() 116 | }, 117 | _bindChange(e) { 118 | const { scrollType } = this.properties 119 | const { lastValue } = this.data 120 | let val = e.detail.value 121 | switch (scrollType) { 122 | case 'normal': 123 | this.data.tempValue = val.concat() 124 | this.data.tempValue = val.concat() 125 | break 126 | case 'link': 127 | // let column_02 = this._getColumnData(this.properties.listData[val[0]].children); 128 | // let column_03 = this._getColumnData(this.properties.listData[val[0]].children[val[1]].children); 129 | var tempArray = [] 130 | if (val.length > 1) { 131 | val.slice(0, val.length - 1).reduce((t, c, i) => { 132 | const v = t[c].children 133 | tempArray.push(this._getColumnData(v)) 134 | return v 135 | }, this.properties.listData) 136 | } 137 | // let columnsData = [this.data.columnsData[0],column_02,column_03]; 138 | var columnsData = [this.data.columnsData[0], ...tempArray] 139 | 140 | // 设置value关联 141 | var compareIndex = this._getScrollCompareIndex(lastValue, val) 142 | if (compareIndex > -1) { 143 | let tempI = 1 144 | while (val[compareIndex + tempI] !== undefined) { 145 | val[compareIndex + tempI] = 0 146 | tempI++ 147 | } 148 | } 149 | val = this._validate(val) 150 | this.data.lastValue = val.concat() 151 | this.data.tempValue = val.concat() 152 | this.setData({ 153 | columnsData 154 | // value: val 155 | }) 156 | } 157 | }, 158 | _validate(val) { 159 | const { columnsData } = this.data 160 | columnsData.forEach((v, i) => { 161 | if (columnsData[i].length - 1 < val[i]) { 162 | val[i] = columnsData[i].length - 1 163 | } 164 | }) 165 | this.setData({ 166 | value: val 167 | }) 168 | return val 169 | }, 170 | _bindpickend() { 171 | this.data.scrollEnd = true 172 | }, 173 | _bindpickstart() { 174 | this.data.scrollEnd = false 175 | }, 176 | _openPicker() { 177 | if (!this.data.isFirstOpen) { 178 | if (this.properties.listData.length !== 0) { 179 | this._setDefault(this._computedBackData(this.data.backData)) 180 | } 181 | } 182 | this.data.isFirstOpen = false 183 | this.setData({ 184 | isOpen: true 185 | }) 186 | }, 187 | _closePicker() { 188 | this.setData({ 189 | isOpen: false 190 | }) 191 | }, 192 | _getColumnData(arr) { 193 | return arr.map((v) => this._fomateObj(v)) 194 | }, 195 | _fomateObj(o) { 196 | const tempO = {} 197 | for (const k in o) { 198 | k !== 'children' && (tempO[k] = o[k]) 199 | } 200 | return tempO 201 | }, 202 | _getScrollCompareIndex(arr1, arr2) { 203 | let tempIndex = -1 204 | for (let i = 0, len = arr1.length; i < len; i++) { 205 | if (arr1[i] !== arr2[i]) { 206 | tempIndex = i 207 | break 208 | } 209 | } 210 | return tempIndex 211 | }, 212 | // 根据id获取索引 213 | _getIndexByIdOfObject(listData, idArr, key, arr) { 214 | if (!Array.isArray(listData)) return 215 | for (let i = 0, len = listData.length; i < len; i++) { 216 | if (listData[i][key] === idArr[arr.length][key]) { 217 | arr.push(i) 218 | return this._getIndexByIdOfObject(listData[i].children, idArr, key, arr) 219 | } 220 | } 221 | }, 222 | _setDefault(inBackData) { 223 | const { scrollType } = this.properties 224 | let { listData, defaultPickData } = this.properties 225 | 226 | const { lastValue } = this.data 227 | if (inBackData) { 228 | defaultPickData = inBackData 229 | } 230 | let backData = [] 231 | switch (scrollType) { 232 | case 'normal': 233 | if (isPlainObject(listData[0][0])) { 234 | this.setData({ 235 | isUseKeywordOfShow: true 236 | }) 237 | } 238 | if (Array.isArray(defaultPickData) && defaultPickData.length > 0) { 239 | backData = listData.map((v, i) => v[defaultPickData[i]]) 240 | this.data.tempValue = defaultPickData 241 | this.data.lastValue = defaultPickData 242 | } else { 243 | backData = listData.map((v) => v[0]) 244 | } 245 | this.setData({ 246 | columnsData: listData, 247 | backData: backData, 248 | value: defaultPickData 249 | }) 250 | break 251 | case 'link': 252 | // let column_01 = this._getColumnData(newVal); 253 | // let column_02 = this._getColumnData(newVal[0].children); 254 | // let column_03 = this._getColumnData(newVal[0].children[0].children); 255 | // let columnsData = [column_01,column_02,column_03]; 256 | var columnsData = [] 257 | // 如果默认值 258 | if (Array.isArray(defaultPickData) && defaultPickData.length > 0 && defaultPickData.every((v, i) => isPlainObject(v))) { 259 | const key = this.data.onlyKey = Object.keys(defaultPickData[0])[0] 260 | 261 | const arr = [] 262 | 263 | this._getIndexByIdOfObject(listData, defaultPickData, key, arr) 264 | 265 | defaultPickData = arr 266 | let tempI = 0 267 | do { 268 | lastValue.push(defaultPickData[tempI]) 269 | columnsData.push(this._getColumnData(listData)) 270 | listData = listData[defaultPickData[tempI]].children 271 | tempI++ 272 | } while (listData) 273 | backData = columnsData.map((v, i) => v[defaultPickData[i]]) 274 | // 如果没有默认值 275 | } else { 276 | this.data.onlyKey = this.properties.keyWordsOfShow || 'name' 277 | do { 278 | lastValue.push(0) 279 | columnsData.push(this._getColumnData(listData)) 280 | listData = listData[0].children 281 | } while (listData) 282 | backData = columnsData.map((v) => v[0]) 283 | } 284 | this.data.tempValue = defaultPickData 285 | this.data.lastValue = defaultPickData 286 | this.setData({ 287 | isUseKeywordOfShow: true, 288 | columnsData, 289 | backData 290 | }) 291 | setTimeout(() => { 292 | this.setData({ 293 | value: defaultPickData 294 | }) 295 | }, 0) 296 | break 297 | } 298 | }, 299 | _computedBackData(backData) { 300 | const { scrollType, listData } = this.properties 301 | const { onlyKey } = this.data 302 | if (scrollType === 'normal') { 303 | return backData.map((v, i) => listData[i].findIndex((vv, ii) => this._compareObj(v, vv))) 304 | } else { 305 | const t = backData.map((v, i) => { 306 | const o = {} 307 | o[onlyKey] = v[onlyKey] 308 | return o 309 | }) 310 | 311 | return t 312 | } 313 | }, 314 | _compareObj(o1, o2) { 315 | const { keyWordsOfShow } = this.properties 316 | if (typeof o1 !== 'object') { 317 | return o1 === o2 318 | } else { 319 | return o1[keyWordsOfShow] === o2[keyWordsOfShow] 320 | } 321 | }, 322 | _getBackDataFromValue(val) { 323 | let tempArr = [] 324 | if (val.length > 0) { 325 | tempArr = this.data.columnsData.reduce((t, v, i) => { 326 | return t.concat(v[val[i]]) 327 | }, []) 328 | } else { 329 | tempArr = this.data.columnsData.map((v, i) => v[0]) 330 | } 331 | return tempArr 332 | }, 333 | _compareDate() { // 完全相等返回true 334 | const { defaultPickDataTemp, listDataTemp } = this.data 335 | const { defaultPickData, listData } = this.properties 336 | 337 | return defaultPickDataTemp === defaultPickData && listDataTemp === listData 338 | }, 339 | _setTempData() { 340 | const { defaultPickData, listData } = this.properties 341 | this.data.defaultPickDataTemp = defaultPickData 342 | this.data.listDataTemp = listData 343 | } 344 | } 345 | }) -------------------------------------------------------------------------------- /utils/WxValidate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 表单验证 3 | * 4 | * @param {Object} rules 验证字段的规则 5 | * @param {Object} messages 验证字段的提示信息 6 | * 7 | */ 8 | class WxValidate { 9 | constructor(rules = {}, messages = {}) { 10 | Object.assign(this, { 11 | data: {}, 12 | rules, 13 | messages, 14 | }) 15 | this.__init() 16 | } 17 | 18 | /** 19 | * __init 20 | */ 21 | __init() { 22 | this.__initMethods() 23 | this.__initDefaults() 24 | this.__initData() 25 | } 26 | 27 | /** 28 | * 初始化数据 29 | */ 30 | __initData() { 31 | this.form = {} 32 | this.errorList = [] 33 | } 34 | 35 | /** 36 | * 初始化默认提示信息 37 | */ 38 | __initDefaults() { 39 | this.defaults = { 40 | messages: { 41 | required: '这是必填字段。', 42 | email: '请输入有效的电子邮件地址。', 43 | tel: '请输入11位的手机号码。', 44 | url: '请输入有效的网址。', 45 | date: '请输入有效的日期。', 46 | dateISO: '请输入有效的日期(ISO),例如:2009-06-23,1998/01/22。', 47 | number: '请输入有效的数字。', 48 | digits: '只能输入数字。', 49 | idcard: '请输入18位的有效身份证。', 50 | cardNo: '请正确输入银行卡号', 51 | equalTo: this.formatTpl('输入值必须和 {0} 相同。'), 52 | contains: this.formatTpl('输入值必须包含 {0}。'), 53 | minlength: this.formatTpl('最少要输入 {0} 个字符。'), 54 | maxlength: this.formatTpl('最多可以输入 {0} 个字符。'), 55 | rangelength: this.formatTpl('请输入长度在 {0} 到 {1} 之间的字符。'), 56 | min: this.formatTpl('请输入不小于 {0} 的数值。'), 57 | max: this.formatTpl('请输入不大于 {0} 的数值。'), 58 | range: this.formatTpl('请输入范围在 {0} 到 {1} 之间的数值。'), 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * 初始化默认验证方法 65 | */ 66 | __initMethods() { 67 | const that = this 68 | that.methods = { 69 | /** 70 | * 验证必填元素 71 | */ 72 | required(value, param) { 73 | if (!that.depend(param)) { 74 | return 'dependency-mismatch' 75 | } else if (typeof value === 'number') { 76 | value = value.toString() 77 | } else if (typeof value === 'boolean') { 78 | return !0 79 | } 80 | 81 | return value.length > 0 82 | }, 83 | /** 84 | * 验证电子邮箱格式 85 | */ 86 | email(value) { 87 | return that.optional(value) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value) 88 | }, 89 | /** 90 | * 验证手机格式 91 | */ 92 | tel(value) { 93 | return that.optional(value) || /^1[34578]\d{9}$/.test(value) 94 | }, 95 | /** 96 | * 验证URL格式 97 | */ 98 | url(value) { 99 | return that.optional(value) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(value) 100 | }, 101 | /** 102 | * 验证日期格式 103 | */ 104 | date(value) { 105 | return that.optional(value) || !/Invalid|NaN/.test(new Date(value).toString()) 106 | }, 107 | /** 108 | * 验证ISO类型的日期格式 109 | */ 110 | dateISO(value) { 111 | return that.optional(value) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value) 112 | }, 113 | /** 114 | * 验证十进制数字 115 | */ 116 | number(value) { 117 | return that.optional(value) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value) 118 | }, 119 | /** 120 | * 验证整数 121 | */ 122 | digits(value) { 123 | return that.optional(value) || /^\d+$/.test(value) 124 | }, 125 | /** 126 | * 验证身份证号码 127 | */ 128 | idcard(value) { 129 | return that.optional(value) || /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(value) 130 | }, 131 | /** 132 | * 银行卡 133 | */ 134 | cardNo(value) { 135 | return that.optional(value) || /^([1-9]{1})(\d{14}|\d{18})$/.test(value) 136 | }, 137 | /** 138 | * 验证两个输入框的内容是否相同 139 | */ 140 | equalTo(value, param) { 141 | return that.optional(value) || value === that.data[param] 142 | }, 143 | /** 144 | * 验证是否包含某个值 145 | */ 146 | contains(value, param) { 147 | return that.optional(value) || value.indexOf(param) >= 0 148 | }, 149 | /** 150 | * 验证最小长度 151 | */ 152 | minlength(value, param) { 153 | return that.optional(value) || value.length >= param 154 | }, 155 | /** 156 | * 验证最大长度 157 | */ 158 | maxlength(value, param) { 159 | return that.optional(value) || value.length <= param 160 | }, 161 | /** 162 | * 验证一个长度范围[min, max] 163 | */ 164 | rangelength(value, param) { 165 | return that.optional(value) || (value.length >= param[0] && value.length <= param[1]) 166 | }, 167 | /** 168 | * 验证最小值 169 | */ 170 | min(value, param) { 171 | return that.optional(value) || value >= param 172 | }, 173 | /** 174 | * 验证最大值 175 | */ 176 | max(value, param) { 177 | return that.optional(value) || value <= param 178 | }, 179 | /** 180 | * 验证一个值范围[min, max] 181 | */ 182 | range(value, param) { 183 | return that.optional(value) || (value >= param[0] && value <= param[1]) 184 | }, 185 | } 186 | } 187 | 188 | /** 189 | * 添加自定义验证方法 190 | * @param {String} name 方法名 191 | * @param {Function} method 函数体,接收两个参数(value, param),value表示元素的值,param表示参数 192 | * @param {String} message 提示信息 193 | */ 194 | addMethod(name, method, message) { 195 | this.methods[name] = method 196 | this.defaults.messages[name] = message !== undefined ? message : this.defaults.messages[name] 197 | } 198 | 199 | /** 200 | * 判断验证方法是否存在 201 | */ 202 | isValidMethod(value) { 203 | let methods = [] 204 | for (let method in this.methods) { 205 | if (method && typeof this.methods[method] === 'function') { 206 | methods.push(method) 207 | } 208 | } 209 | return methods.indexOf(value) !== -1 210 | } 211 | 212 | /** 213 | * 格式化提示信息模板 214 | */ 215 | formatTpl(source, params) { 216 | const that = this 217 | if (arguments.length === 1) { 218 | return function () { 219 | let args = Array.from(arguments) 220 | args.unshift(source) 221 | return that.formatTpl.apply(this, args) 222 | } 223 | } 224 | if (params === undefined) { 225 | return source 226 | } 227 | if (arguments.length > 2 && params.constructor !== Array) { 228 | params = Array.from(arguments).slice(1) 229 | } 230 | if (params.constructor !== Array) { 231 | params = [params] 232 | } 233 | params.forEach(function (n, i) { 234 | source = source.replace(new RegExp("\\{" + i + "\\}", "g"), function () { 235 | return n 236 | }) 237 | }) 238 | return source 239 | } 240 | 241 | /** 242 | * 判断规则依赖是否存在 243 | */ 244 | depend(param) { 245 | switch (typeof param) { 246 | case 'boolean': 247 | param = param 248 | break 249 | case 'string': 250 | param = !!param.length 251 | break 252 | case 'function': 253 | param = param() 254 | default: 255 | param = !0 256 | } 257 | return param 258 | } 259 | 260 | /** 261 | * 判断输入值是否为空 262 | */ 263 | optional(value) { 264 | return !this.methods.required(value) && 'dependency-mismatch' 265 | } 266 | 267 | /** 268 | * 获取自定义字段的提示信息 269 | * @param {String} param 字段名 270 | * @param {Object} rule 规则 271 | */ 272 | customMessage(param, rule) { 273 | const params = this.messages[param] 274 | const isObject = typeof params === 'object' 275 | if (params && isObject) return params[rule.method] 276 | } 277 | 278 | /** 279 | * 获取某个指定字段的提示信息 280 | * @param {String} param 字段名 281 | * @param {Object} rule 规则 282 | */ 283 | defaultMessage(param, rule) { 284 | let message = this.customMessage(param, rule) || this.defaults.messages[rule.method] 285 | let type = typeof message 286 | 287 | if (type === 'undefined') { 288 | message = `Warning: No message defined for ${rule.method}.` 289 | } else if (type === 'function') { 290 | message = message.call(this, rule.parameters) 291 | } 292 | 293 | return message 294 | } 295 | 296 | /** 297 | * 缓存错误信息 298 | * @param {String} param 字段名 299 | * @param {Object} rule 规则 300 | * @param {String} value 元素的值 301 | */ 302 | formatTplAndAdd(param, rule, value) { 303 | let msg = this.defaultMessage(param, rule) 304 | 305 | this.errorList.push({ 306 | param: param, 307 | msg: msg, 308 | value: value, 309 | }) 310 | } 311 | 312 | /** 313 | * 验证某个指定字段的规则 314 | * @param {String} param 字段名 315 | * @param {Object} rules 规则 316 | * @param {Object} data 需要验证的数据对象 317 | */ 318 | checkParam(param, rules, data) { 319 | 320 | // 缓存数据对象 321 | this.data = data 322 | 323 | // 缓存字段对应的值 324 | const value = data[param] !== null && data[param] !== undefined ? data[param] : '' 325 | 326 | // 遍历某个指定字段的所有规则,依次验证规则,否则缓存错误信息 327 | for (let method in rules) { 328 | 329 | // 判断验证方法是否存在 330 | if (this.isValidMethod(method)) { 331 | 332 | // 缓存规则的属性及值 333 | const rule = { 334 | method: method, 335 | parameters: rules[method] 336 | } 337 | 338 | // 调用验证方法 339 | const result = this.methods[method](value, rule.parameters) 340 | 341 | // 若result返回值为dependency-mismatch,则说明该字段的值为空或非必填字段 342 | if (result === 'dependency-mismatch') { 343 | continue 344 | } 345 | 346 | this.setValue(param, method, result, value) 347 | 348 | // 判断是否通过验证,否则缓存错误信息,跳出循环 349 | if (!result) { 350 | this.formatTplAndAdd(param, rule, value) 351 | break 352 | } 353 | } 354 | } 355 | } 356 | 357 | /** 358 | * 设置字段的默认验证值 359 | * @param {String} param 字段名 360 | */ 361 | setView(param) { 362 | this.form[param] = { 363 | $name: param, 364 | $valid: true, 365 | $invalid: false, 366 | $error: {}, 367 | $success: {}, 368 | $viewValue: ``, 369 | } 370 | } 371 | 372 | /** 373 | * 设置字段的验证值 374 | * @param {String} param 字段名 375 | * @param {String} method 字段的方法 376 | * @param {Boolean} result 是否通过验证 377 | * @param {String} value 字段的值 378 | */ 379 | setValue(param, method, result, value) { 380 | const params = this.form[param] 381 | params.$valid = result 382 | params.$invalid = !result 383 | params.$error[method] = !result 384 | params.$success[method] = result 385 | params.$viewValue = value 386 | } 387 | 388 | /** 389 | * 验证所有字段的规则,返回验证是否通过 390 | * @param {Object} data 需要验证数据对象 391 | */ 392 | checkForm(data) { 393 | this.__initData() 394 | 395 | for (let param in this.rules) { 396 | this.setView(param) 397 | this.checkParam(param, this.rules[param], data) 398 | } 399 | 400 | return this.valid() 401 | } 402 | 403 | /** 404 | * 返回验证是否通过 405 | */ 406 | valid() { 407 | return this.size() === 0 408 | } 409 | 410 | /** 411 | * 返回错误信息的个数 412 | */ 413 | size() { 414 | return this.errorList.length 415 | } 416 | 417 | /** 418 | * 返回所有错误信息 419 | */ 420 | validationErrors() { 421 | return this.errorList 422 | } 423 | } 424 | 425 | export default WxValidate --------------------------------------------------------------------------------